I would like to share a few articles I've written back in 2005/2006 while working on an open source project - Hierarchical MVC Web framework - Claw:
Long gone post #2.
It is a common pattern in Java community (NOTE: I thought so back then, though found out that it's not really common at all), while it seems like PHP developers think there is no heaven like MVC. For those, who are interested in HMVC concepts, read this (and notice the date – quite an oldie, eh?):
I haven't found a single open source PHP framework with HMVC implementation, that's why Claw was born. Are there any more of this kind? Did I miss anything? Please let me know if I did. Anyway, the long URL above would most probably be helpful for Java GUI application developers, I must say that I do not understand more than a half of that document, and never actually read the code examples carefully, so I think it is easier for me to rewrite the concepts the way I understand them and the way they work in Claw Framework. Before that you may take a glance at another Javish explanation of Hierarchical MVC here:
Did not get that one either, but at least it's shorter and easier to read. If you really bothered yourself to at least briefly look through that information (and shame on you if you did not, and I know you did not), you should have found out the key advantages of HMVC pattern are something like:
- Defined intralayer communication and isolation from higher layers
- Defined interlayer communication with minimal coupling
- Localization of exposure to third-party code
- Reduced dependencies between disparate parts of the program
- Encouraged reuse of code, components, and modules
- Increased extensibility while easing maintainability
Back to our shop architecture – here is the draft of my HMVC-inspired implementation:
For those who see a spaceship or a piece of DNA chain – bigger blocks are controllers, small tablets – controller actions (you can call them functions, methods or events if you like), black arrows show possible routes to some point of application and dotted lines show which action belongs to which controller. Now imagine the flattened requests:
These requests would go easily without any custom mappings, URL rewriting or any other hacks you would have to do in plain old MVC. I guess these links need no special explanation, but just in case, let's examine the longest one piece by piece:
/ IndexPage – root controller for the following hierarchy
/list ListPage – controller for accessing product lists
/search ListPage::search -search action invoked on list controller
/query.big+fork ListPage::search – argument 'query' => 'big fork'
/sort.price ListPage::search – argument 'sort' => 'price'
/order.asc ListPage::search – argument 'order' => 'asc'
/page.18 ListPage::page – argument 'page' => 18
/product ProductPage – controller for single product related logic
/114 ProductPage – numeric argument => 114
/review ProductPage::review – action for adding new review
We simply form this chain element by element, so the application grows like a tree, and when you need a new branch, you simply put a tiny piece of code on top of the tree, without having to touch what has already grown big. But you have all the information inherited in the way. In our example above, when user is reviewing product #114, application is aware that he/she came from a product list page 18 of search for “big fork” by price, so when it comes to rendering navigation and layouts, you could even show search results along with review form, if you would want that for some weird reason. But it's nice to have the power, no? Those who ever developed large systems should be nodding.
How do controllers inherit data? The picture below should help you visualize the process:
As application is executed, each controller (Page) may set some variables. Child controllers can set their own, though, when you are trying to get a variable that current controller does not have, system falls back to parent and checks if this variable is not there, and if it is, the value is returned. Recursion goes to the bottom of the chain if required. And since any point you can redeclare variables, so beyond a certain point the value will be as redeclared (though parent controllers will still use the old one). As you build your application layering the controllers one upon another, at the end of what I call “chain reaction”, application collects the flattened set of variables and passes them to final view (which is flattened after playing the puzzle within same reaction):
This is simply a composite view, with parts and layers, that each controller inherits from the parent and can manipulate it, rewrite it, etc. Final view is rendered only when chain reaction is over, and view layers are “flat” in final position. This is the time when variables are stamped in, so before final controller hits the breaks, nothing is rendered – this lazy kind of work saves resources.