Welcome Guest, Not a member yet? Register   Sign In
Nested MVC
#21

[eluser]wiredesignz[/eluser]
Its not MVC that forces you to do this, it is CodeIgniter's $data['part'] = load->view('file' $data) method.

I have created a View Object that stores all my view partials as file names and raw $data only, and then use it to render the page only when I tell it to.
#22

[eluser]Edemilson Lima[/eluser]
File names? Does it store data on disk?
#23

[eluser]wiredesignz[/eluser]
Its an Object, it has variables to store data.

I have just finished adapting my View Object to use Plugins as psuedo-controllers so I am now able to nest an MVC triad as a partial view.

See the Ignited Code forum.
http://ellislab.com/forums/viewthread/70629/
#24

[eluser]Edemilson Lima[/eluser]
Quote:http://ellislab.com/forums/viewthread/70629/

There are some solutions to bring nested MVC to CodeIgniter, but is very hard to adopt one, because these things change the way we code the whole application. The ideal scenario was if we had a solution from the CI developers. If CodeIgniter have its own HMVC, it becomes a standard, so the feature goes to the docs. If another developer need to change anything in my code, he/she will look at CI documentation and easily understand what I have done.

At this moment I am stucked and I have no idea what I will do... 8-/
#25

[eluser]wiredesignz[/eluser]
I think, the whole point of using CI is to try new things that work for you, and then use them. You never know, your coding style might actually improve.

I see a lot of new people struggling to fit all their code into one controller. But I'm sure as they learn about MVC they will think up better ways to do things. Nested MVC is one way.
#26

[eluser]Edemilson Lima[/eluser]
Instead of put everything in a base controller, I did created some helpers, but I am not sure if it is the best way to do my application...

The "application/helper" folder is ideal for extending/replacing core helpers (since 1.6.0) and to put my sporadic functions, like my own string/date format/validate functions or things like that.

The "application/libraries" folder is ideal for extending/replacing core libraries and to put my proprietary libraries, with things like my own template parser, my own session management, file management, etc.

May I could use the "application/plugins" folder to put my application modules/partials, but the name "plugins" suggests me that such folder is for third part applications, like for example, a plug-in to import/export data from another web site.

One option could be use the "application/models" folder to put my modules/partials as models, but I don't think this is a good pratice too. My modules/partials are more like controllers than models. They will have their own models and will load their own views.

In my opinion, to create helpers, libraries or plug-ins and use them as my application modules/partials are not the best pratice, because helpers/libraries/plug-ins are things related to the low level of my application, which rarely deals with my application logic.

Actually I must build my modules/partials in strings in every controller and every function, and then pass everything to the main view at the end of every function. The best way to not repeat code is made them as a helper, library or plug-in and load them in the controller contructor. But as I said above, the modules/partials are not helpers, nor libraries, nor plug-ins.

I could extend the Loader class and create a new folder exclusive for my modules. But anyway, may I need to load them into every controller and every function, passing them to the main view in the end of every function of my controllers. I really don't like to do that... It is a very repetitive task anyway.

I think a Nested MVC is the answer to put everything in a more logic structure and make the hierarchy work for us by itself.
#27

[eluser]Edemilson Lima[/eluser]
I was thinking in something like this: (well, this is just a sketch)

My "main" view:
Code:
<div id="header">&lt;?=$header?&gt;</div>
<div id="content">
  <div id="leftside">&lt;?=$leftside?&gt;</div>
  <div id="center">&lt;?=$center?&gt;</div>
  <div id="rightside">&lt;?=$rightside?&gt;</div>
</div>
<div id="footer"&lt;?=$footer?&gt;</div>

My "main" controller:
Code:
class Main extends Controller {

  function Main() {
    parent::Controller();
    $header['title']="Welcome!";
    $data['header']=$this->load->module('header',$header);
    $data['leftside']=$this->load->module('products/categories');
    $data['center']=$this->load->module('home');
    $data['rightside']=$this->load->module('publish/banners');
    $data['footer']=$this->load->module('footer');
    $this->load->view('main_view',$data);
  }
}

Notice the "load->module" lines above. The modules goes to a "modules" folder.

My "categories" module:
Code:
class Categories extends Module {

  function Categories() {
    parent::Module();
    $this->load->model('products/categories');
    $data['categories']=$this->products->get_categories_list();
    $this->load->view('categories_view',$data);
  }
}

My "home" module:
Code:
class Home extends Module {

  function Home() {
    parent::Module();
    $data['offers']=$this->load->module('products/offers');
    $data['news']=$this->load->module('press/news');
    $data['top10']=$this->load->module('products/top10');
    $this->load->view('home_view',$data);
  }
}

Suppose my main menu have a link that points to "/products/".
It will load a "products" controller like this:
Code:
class Products extends Controller {

  function Products() {
    parent::Controller();
    $header['title']="Our Products";
    $data['header']=$this->load->module('header',$header);
    $data['leftside']=$this->load->module('products/categories');
    $data['center']=$this->load->module('products/home');
    $data['rightside']=$this->load->module('publish/banners_two');
    $data['footer']=$this->load->module('footer');
    $this->load->view('main_view',$data);
  }
}

As you can see, the products controller will load the header, categories and footer modules, as the main controller do, but instead of the home module, it will load its own modules. Another page title is also passed to the header module as a parameter.

My "products/home" module:
Code:
class Home extends Module {
  
  function Home() {
    parent::Module();
    $data['product_list']=$this->load->module('products/list');
    $data['suggestions']=$this->load->module('products/suggestions');
    $this->load->view('products/home_view',$data);
  }

  function details($id) {
    $module['id']=$id;
    $data['part']=$this->load->module('products/details',$module);
    $this->load->view('products/details_view',$data);
  }

  function add() {
    $this->load->view('products/insert');
  }

  function edit($id) {
    $module['id']=$id;
    $data['part']=$this->load->module('products/edit',$module);
    $this->load->view('products/edit_view',$data);
  }

  function remove($id) {
  }
}

As you can see from these examples, if we have a feature like this, you will not need to use the third parameter of load->view(), because the output of a view called by a module must always be buffered and returned to the caller module or controller. This will enable the hierarchy to work.

Each module could load sub_modules, which in turn could load more sub_modules. And each module could load their own models and views, completely independent of everything else in the application. But modules could get user data and manage it as controllers do.

The main problem is when you call an URI like "/products/details/123". Will the CI engine know that is to call the "details" function inside the "products/home" module, loaded by "products" controller and pass the "123" to the function first parameter? I don't think so. May be a more elegant structure like an HMVC is necessary, but these examples are the basic idea.

But is such thing too hard to implement in CodeIgniter?

I have found this thread about a View Library very interesting:
http://ellislab.com/forums/viewthread/49910/
#28

[eluser]Edemilson Lima[/eluser]
Here is Rick Jolly's View-centric Nested Controllers:

http://ellislab.com/forums/viewthread/58405/

I must agree with Rick, this is a much better solution for Nested Controllers, because it decouples the caller controller from the view partials. The only drawback is that I would like to have these partials separated from my libraries. It could go to a another folder called "modules" or "partials". Instaed of create a helper, I think we could extend the Loader and add a new method like "$this->load->module()" or "$this->load->partial()" to be used into the views. And within these partials, instead of return the data as an string, the Loader could use the PHP output buffering to get the result that will be returned to the caller controller.

May anybody here can tell me if this is possible?
#29

[eluser]BizComputing[/eluser]
Sorry, I started this thread and then disappeared. I had an HDD crash and my backup strategy has been decidedly lazy of late, so, restoration turned out to be a nightmare. Thankfully nothing of importance lost, and I'm mostly back in the saddle.

As for having my nested controllers as something other than a libary, already done. I extended the CI_Loader class to add 2 features. First feature allows loading libaries without instantiation. This allows loading the class definition for self instantiation using new. Second change was to add a load module (my current name for my sub controllers). The load module is basically a rip of the libary loading with minor exceptions. Module loader auto loads without instantiation my base module library ( All my modules extend this library ). Module loader loads libraries from my application/modules folder instead of my application/libraries folder.

My module base class used to build modules follows a pattern I'm using in my controllers. Each of my controllers handles 1 page, so, method index is used for page display. A pages actions( links internal to page and form posting ) go to a method called submit. Therefore, my modules (sub controllers) have an index method and a submit method. Both methods accept an array of arguments. So the parent controller is responsible for building the array of data necessary for the subcontroller and calling the subcontrollers appropriate method ( index, or submit depending on what method is executing in the parent controller ). Both methods also return a data array. The index return data array contains a key called 'view' which is a string of HTML generated by the module, this then puts the responsiblity for placement of the view fragment on the parent controller. Other return values are based on how the module is being used. For instance, one of my modules has a close button which should close the parent controllers page, so, the submit method of this module puts $data['result'] = 'close' as a return value when the close button is selected. The parent controller is then responsible for checking for this returned key/value pair and execute whatever code it needs to to close itself.

I do have some additional methods on my modules that are to support other uses of modules. Currently in the application I am porting to CI, my modules are for reusablility. I have a few different screens that share some common functionality and display fragments. So the module provides the common functionality and loads the common display fragment as it's own view, and, loads it's own model in support of the common functionality. The additional methods on my modules are to support using modules as portions of a screen that load or not based on current configuration or the rights of the currently logged in user, or in the case of a workflow application, the current state of the workflow. This use of modules is not absolutely necessary, but does greatly help to simplify the main controller since the main controller would be responsible for gluing together all the module views and dispatching all the module posts.
#30

[eluser]Edemilson Lima[/eluser]
Quote:I extended the CI_Loader class to add 2 features. First feature allows loading libraries without instantiation. This allows loading the class definition for self instantiation using new. Second change was to add a load module (my current name for my sub controllers).
Very interesting! Will you pleasure us with an example of it? Smile
Quote:Module loader loads libraries from my application/modules folder instead of my application/libraries folder.
That is something I'm looking for.
Quote:Therefore, my modules (sub controllers) have an index method and a submit method.
Can I have how many methods I want? Can I define in my views which method will be called? (for example, in a form action)?




Theme © iAndrew 2016 - Forum software by © MyBB