Page 1 of 1

Something in between MVC and CMS

Posted: Fri Mar 16, 2007 3:18 pm
by Ollie Saunders
The other day I created a web site for hosting a video (a frequent task in my job) but this one was slightly different in that
  1. I had to turn the whole thing out in about 9 hours
  2. The video being hosted came in several different flavours (two different quality streaming pages, three different download qualities and a fourth download for burning to DVD)
To manage all this I created a series of forms, a wizard if you like, so the user could choosing the how they wanted to see the video and optionally specified their internet connection speed before finally being presented with simplified options complete with estimated download times and "recommended for your connection" messages.

Whilst being a slightly different project from those in the past, for those reasons I've just explained, it was also similar in that, like before, this new website needed to be done in the look and feel of the client's company and had to be expandable for more videos later - that means sections, subsections and navigation. In order to get the project out I pretty much ignored that on a functional level; ensuring that the site's design appeared to have room to grow but actually doing what ever was necessary to get the code up and running in the time. That is to be expected and wasn't a real problem.

Once the project was successfully completed the client was very pleased. I recommended to my boss that it should be "refactored" so that we can respond to requests for expansion quickly. He listened while I explained what refactoring is and why it is necessary; making the points that not refactoring leads to code that get exponentially harder to maintain and how it's a bit like how cell references in excel can make changing a value a very quick task compared with having the that value duplicated across the worksheet.

By the time I'd finished explaining all this another member of staff involved in the project walked in the room and that was great because we got to explain to him as well about refactoring. A few short moments later it was agreed that the refactoring should be done and in fact the decision was a "no brainer", to which I completely agree. And so begun my job of refactoring the code.

So how should such a project be refactored?

I spent a few moments considering a couple of strategies. What I really wanted to do was to write the site up in a meaningful XML structure and use XSLT to transform it into HTML. But currently I can't used XSLT because of server limitation and besides how am I going to integrate forms into that? So I decided on MVC and the Zend Framework. I spent a whole day setting up ZF, SimpleTest, PHPUTF8, writing controllers, models, views, etc. I was determined to do it as perfectly as possible because this project would be a model of future ones. Towards the end of the day I was starting to realise that it wasn't as easy as it should be. In fact it was significantly harder than the unrefactored version, which, although a little messy, was pretty easy to follow. Worryingly I ended up with a controller page that looked a bit like this:

Code: Select all

public function indexAction()
{
    $view = Zend::registry('view');
    switch ($this->_getParam('section', 'foo')) {
        case 'foo':
            $view->pageTitle = 'foo';
            $view->body = 'some body';
            switch ($this->_getParam('subsection', 'zim')) {
                case 'gir':
                    $view->videos = array(new Video(...));
                    break;
                case 'zim':
                    $view->videos = arrat(new Video(...), new Video(....));
                    $view->xtraBlurb = ';lkdfs';
                    break;
                default:
                    $view->xtraBlurb = 'dfsdgf';
            }
            break;
        case 'bar':
            $view->pageTitle = 'The very important bar';
            $view->body = 'blah blah. I\'ve drunk too much at the bar';
            switch ($this->_getParam('subsection', 'dib')) {
                case 'dib':
                    $vide->videos = array(new Video(...));
                case 'gaz':
                    $vide->videos = array(new Video(...));
                default:
                    $view->body = 'stuff';                    
            }
            break;
        default:
            
    }
    echo $view->render('main.php');
}
only with a lot more assignments to $view and much longer strings. The view main.php was then handling all of these different assignments and many more with the idea of being as powerful as possible. I even extended Zend_View to allow for nested views so that I could contains views within view and reap some flexibility from view specialisation.

MVC is designed to "decouple data access and business logic from data presentation and user interaction" and was doing a fine job of it but clearly that isn't what I'm after. I was misapplying the pattern completely.

So this got on to thinking about a CMS. CMSes "facilitate the organization, control, and publication of documents and other content, such as images and multimedia resources" and sounds a little more like what I'm after but then how do I integrate custom functionality such as my video chooser wizard thing into that. Incidentally I've no intention of using a pre-packaged CMS or writing anything myself much larger than is necessary to satisfy the requirements of this site but it sounds to me that I'm after some kind of CMS / MVC hybrid or at least a template system that blocks of functionality can be injected into or perhaps the other way round.

Hope you enjoyed the story and have lots of useful suggestions for me :)

Posted: Fri Mar 16, 2007 3:42 pm
by Christopher
I'm going to skip over you implications that XSLT Templates, MVC, CMSs, etc. are somehow competing and exclusive. In looking at the code it seem like the core of your problem is that you are not defining routing for 'section' and 'subsection'. Doing that would eliminate the mess in your controller. The key to using a Front Controller is embracing dispatching. (and for the record: using a FC has nothing to do with MVC).

Posted: Fri Mar 16, 2007 3:50 pm
by Kieran Huggins
I'd stick to the "less is more" philosophy and display flash video + a link to download the ISO.

Make each video a standard data object and build templates that are designed to load it.

Something like:

Code: Select all

$video = new video('id');

echo "<h1>watch".$video->title."</h1>";
$video->displayFlash();

$video->linkToIso('download the DVD iso');
Does that make sense for your situation?

Posted: Fri Mar 16, 2007 4:34 pm
by Ollie Saunders
arborint, remember all links that make up the main and sub navigation have to be displayed as well as being possible to be dispatched to. Is that still possible do you think?

kieran, your advice isn't addressing the wider issue.

Posted: Fri Mar 16, 2007 5:17 pm
by Maugrim_The_Reaper
Your indexAction is doing far too much decision making... Each new part of the web application should have an assigned "route", which at a minimum splits out your switch statement sections. From there it's a matter of applying OOP, knowing that actions can "forward" to other actions on the same dispatch cycle (without user agent redirects), and being able to separate the View into re-useable elements where presentation logic is the same, i.e. always the case for a dynamic menu. So I'd argue you have the technology, and you just need to familiarise yourself with such specifics.

If menus are the same for all pages - dynamic presumably for each current View. Then it might be beneficial to consider adding a few plugins which can manipulate the Menu based on the current Request object (which holds controller and action names). You can make this accept a View object, generate the dynamic menus, and as a plugin run automatically for all dispatches to a specific controller. This is a lot easier if your controllers all extend a set of application specific Zend_Controller_Action subclasses which let you tinker with controller initialisation steps.

Granted the minimal documentation hurts - so it may take a bit of code digging to realise all the functionality a ZF component offers.

A first step would be taking what you have and "boiling" it down. I'm not sure, but it looks like new videos might require extending the switch? If so it would better just to let indexAction redirect to a section/subsection specific action on the same controller. Use some private methods to centralise any duplicated code which results from such a method extraction.

Posted: Fri Mar 16, 2007 5:31 pm
by Luke
Maugrim_The_Reaper wrote:Your indexAction is doing far too much decision making... Each new part of the web application should have an assigned "route", which at a minimum splits out your switch statement sections. From there it's a matter of applying OOP, knowing that actions can "forward" to other actions on the same dispatch cycle (without user agent redirects), and being able to separate the View into re-useable elements where presentation logic is the same, i.e. always the case for a dynamic menu. So I'd argue you have the technology, and you just need to familiarise yourself with such specifics.
If you would like some great examples of this, download Astrum Futura and look at its controllers and how it is organized. It's a great example of how to properly use the Zend Framework for MVC. So good, in fact, that I design my applications almost identically. :)

Posted: Fri Mar 16, 2007 6:40 pm
by Maugrim_The_Reaper
AF is a bit out of whack with ZF 0.9. I actually hope to have a much better base ZF implementation soon as part of a smaller project. The funny thing with frameworks is that you end up doing the same stuff for each application the same way - so having a central simple setup with a collection of subclasses (e.g. I prefer having View variables automatically escaped and requiring a deliberate developer interference to avoid) makes for even greater re-use.

If I had Chris Shiflett's web designer I'd be all set ;). His redeveloped blog (used the ZF) is fantastic if you haven't spotted it in the last few days.

Posted: Fri Mar 16, 2007 6:57 pm
by Luke
nope, I hadn't seen it. It looks great.

Posted: Sat Mar 17, 2007 6:34 am
by Ollie Saunders
Thanks for all the help and suggestions so far guys. I'm going to study your words in details later on.

Posted: Sat Mar 17, 2007 11:16 pm
by alvinphp
CMS is a tool to manage content. MVC is one of many ways to structure your code. What you can do is build a CMS tool using MVC structure. You should not completely blow off existing CMS tools as some are pretty interesting (check out Drupal).

Posted: Sun Mar 18, 2007 6:55 am
by Ollie Saunders
CMS is a tool to manage content. MVC is one of many ways to structure your code. What you can do is build a CMS tool using MVC structure
OK then forget I ever mentioned CMS. I'm looking for a design pattern to build structured web sites, with some functionality in a refactored way.
some are pretty interesting (check out Drupal)
Yeah I thought it looked interesting too for a while. But then over the months I heard people complaining about it (as they do any CMS) and I realised it wasn't for me.
If I had Chris Shiflett's web designer I'd be all set Wink. His redeveloped blog (used the ZF) is fantastic if you haven't spotted it in the last few days.
Yeah I noticed that. Really cool. You say you are after a web designer on sourceforge, I'm considering applying for the position maybe in a couple of weeks time - what do you need designed exactly? Could you elaborate on the work required.
our indexAction is doing far too much decision making... Each new part of the web application should have an assigned "route", which at a minimum splits out your switch statement sections. From there it's a matter of applying OOP, knowing that actions can "forward" to other actions on the same dispatch cycle (without user agent redirects), and being able to separate the View into re-useable elements where presentation logic is the same, i.e. always the case for a dynamic menu. So I'd argue you have the technology, and you just need to familiarise yourself with such specifics.

If menus are the same for all pages - dynamic presumably for each current View. Then it might be beneficial to consider adding a few plugins which can manipulate the Menu based on the current Request object (which holds controller and action names). You can make this accept a View object, generate the dynamic menus, and as a plugin run automatically for all dispatches to a specific controller. This is a lot easier if your controllers all extend a set of application specific Zend_Controller_Action subclasses which let you tinker with controller initialisation steps.
That all sounds really complicated but I'd be prepared to do it if it could cope with any level of subsection nesting and reusable microtemplates (new term! invented by me :)).

Posted: Sun Mar 18, 2007 1:15 pm
by Christopher
ole wrote:That all sounds really complicated but I'd be prepared to do it if it could cope with any level of subsection nesting and reusable microtemplates (new term! invented by me :)).
Not that complicated ... but you need to be a little RESTful in thinking about the modules, controllers and actions in your application. Start with a request/response scheme and then code to that.

Posted: Sun Mar 18, 2007 3:19 pm
by Maugrim_The_Reaper
Yeah I noticed that. Really cool. You say you are after a web designer on sourceforge, I'm considering applying for the position maybe in a couple of weeks time - what do you need designed exactly? Could you elaborate on the work required.
You can drop me an email or PM - I dont need huge tracts of time, mainly some template and design help.
if it could cope with any level of subsection nesting and reusable microtemplates
This should be available by ZF 1.0 - if not already. I haven't gotten around to assessing yesterdays 0.9-beta release. But it's simple to do using some predefined View array values. View Helpers (see manual) are a good example of where you can place any menu plugins for re-use. Then it could be as simple as:

Code: Select all

<div class="menu_left">
    <?php echo $this->menu($this); ?>
</div>
This would assume the Helper class was called "Zend_View_Helper_Menu" - last phrase becomes the Zend_View method name to call. Your view should have enough data for the Helper to figure out how the standard menu should be constructed, or altered from some "microtemplate", and then return the menu HTML to be integrated into the above template output. That's the simplest way of doing it - using a View Helper.