Long, long post warning…
I’m having trouble sleeping tonight. Tomorrow I have to explain to him why it makes no sense to me to try to solve 500 problem tickets on a codebase spiraling out of control (at 2 hours / ticket minimum 1000 hours) then rewrite the damn thing (estimated time 500 hours). Not wanting to go into how and why, complicated.
My thoughts have drifted to my own framework as one possible solution - but it’s not quite up to the task and I want to give it a rewrite to take advantage of features I’ve mastered since the last major overhaul and features new for PHP 5.3. The current codebase needs PHP 5.2 so it’s not a major rewrite in that regard.
Model-View-Control gets a lot of endless debate. I liken it to web developer porn - you know it when you see it but no one quite agrees on what constitutes it. The goal of the paradigm is code separation.
Tonight I brainstormed a bit on what my code does well, the mistakes I’ve made in implementing MVC, and I even pulled up code from back before I heard of MVC to see if those bad old days had any thoughts worth revisiting.
One that called out to me was the elegance of an old framework that organized itself by operations and views. You do an op then return a view. Not too flexiable since it was procedural, but it got the job done with a lot of hard wiring.
I got to thinking about what my framework does well – it is REALLY damn good at AJAXing. The way it’s laid out the controlling javascript code is in the controller files in parallel to their callbacks. One of the lovely things is the framework detects if javascript made the call and allows an echo back of pure javascript responses.
It’s very precise and clean. Larger tasks, such as embedding what Joomla and drupal would call modules into a page are not handled as well.
So, I began to think on how I would lay out a framework if I were starting today. An Event perspective on the classic MVC paradigm. Basically every request from the browser is an event, but events can arise elsewhere - an error is an event. If the domain detects the user lacks permissions that is an event. If a view needs a menu inline from somewhere it fires an event.
The reason for breaking this up is so that events can rise from javascript as easily as php (although I can’t stress enough they don’t HAVE to). For the most part, javascript is view control code. View is not as simple as templates (sorry Smarty lovers but it is true), though templates are a large part of it. Rather than write validation code once for server and then client side, javascript should be able to quick query the server each time a field fires an onBlur event to check that field against the model. This call by the view code of javascript must pass through the event dispatcher.
In short
Model => Data Events: Events that modify or fetch information from the datastore, whatever form it takes.
View => View Events: Events that arise from the composition of a view at page build time or javascript events arising from user interactions.
Control => Event Dispatch: Basically, what happens next. Since events can arise out of events (a successful POST will need to fire a View Event to give the user feedback).
I’m looking at this sketch and typing up this post in hopes of finding holes as there are a lot of smart people here capable of poking holes in things.
Still Reading -> Let’s go in more depth…
Control Code -> Event Dispatch
I think a lot of MVC implementations get lost in determining exactly what control is supposed to do. My own current framework has a lot of view related stuff in it because I proceeded from the idea that templates were the view code and that’s that. They aren’t. They are a component in support of view code yes, but not the view itself.
One thing I intend to keep from my current framework is the idea that ./htdocs is a cache. If PHP can recuse itself from constantly making a page and place a static file in ./htdocs it will. A tiny PHP snippet may be placed at the head of the file to check the time to live for the file and based on cookies whether the page should dynamically load, but the eval of this snippet doesn’t require the framework to load into place so will be faster than pure dynamic pages.
Do As Little As Possible Whenever Plausible
Anyway, due to this structure PHP only is involved when the browser tries to go to a non-existant page. Using Apache mod_rewrite we enter the framework from a single point of entry. This starts the Core class which readies the framework to go to work - setting env, autoloaders, stuff everyone’s framework does in one way or another. At the end the core class starts the Event Dispatcher and hands off program flow to it.
Here’s where the fun starts. The event dispatcher looks at the URL and determines which event is to be fired. It does this by considering the request method ($_POST or $_GET) and mode (HTTPXML or HTTP standard). Having determined the event we go and get it.
The two major event groups are data and view events. So let’s talk about them…
Model Code -> Data Events
As with the controller each MVC has its own ideas on what goes on in the model. To me it’s the access to and from the database and it’s entities.
Above we see control divided into roughly 3 layers - the first layer is pure apache returns of static files without PHP’s involvement, the second layer is the core of the framework which gets the system ready for the other parts and the third is the Event Dispatch.
The Model area also has 3 layers. The Event Layer is the nearest to the control layer and the only one that talks to control (specifically to the EventDispatcher). Events can be the composition of a table summary of data drawn from one or more tables, a form with data bound for one or more tables, and so on. The next layer down is the database abstraction, classes for abstracting tables, rows and fields. Most SQL composition occurs here using SQL that adheres to standard and will run on any database program that likewise adheres to it. Furthest out but closest to the database is the database driver which is where the raw querying happens.
A data event will cause the instantiation of one or more entities, at the least the user entity. Note that the EventDispatcher itself may create the events entity from the database if it has to, but for speed reasons it caches the results of this query to a php file so that the database doesn’t have to be queried on every single page hit. It is possible for a view event to occur without a data event.
At the conclusion of most data events they will fire a view event. This isn’t a direct call over to the view code – the model just hands over the data to control (the EventDispatcher) and specifies the type of view event needed. However, the Event Dispatcher decides on what view event fires based upon the nature of the initial request. For example, if javascript calls for a table summary, page 3, it only needs the table rows. If the browser calls for it the page must be built. The model doesn’t care, it just knows it was asked to get and return a table summary, page 3.
View Code -> View Events
View code is the most confused section I think of MVC. Views are not merely templates. View Code is the code that interacts with the user. Templates are only part of this. In a modern web page most of this code will be written in Javascript - PHP’s job is to deliver the initial view state. If javascript isn’t present we should pass seamlessly between static view states. Javascript by theory needs to be optional - and a framework that pragmatically endorses this would be awesome. Hence this idea of dividing along event lines.
View code breaks down into 4 layers.
Server Event Code is the part of the code that touches and talks to the controller. It receives data from the model via the controller (and why this is should now be clear, the controller must decide which view is appropriate. Server Event code also includes javascript callbacks wrapped in PHP that are sent back to be eval’ed at the end of the ajax request lifecycle.
Client Event Code is written in javascript These can get real specific and are off in their own service library and will be built on prototype framework.
Template Drivers: This code drives the template evaluation process to compose the output. This layer exists because HTML is not always what we are sending. We may send an image, a PDF, or anything else.
Templates: These are specific to their driver. The HTML templates are simply PHP files in the braceless syntax. Support functions they require live in the HTML drivers.
Putting it together
Ok, still with me?
Thoughts on how this goes. Scenario one - ye old login. We go to the admin home page hitting Core, then Event Dispatch. This fires the homepage data event. The homepage data event discovers no user so fires the authentication fail view event. This event gets the login template, parses it then fires the close session event which does the actual echo out of the code.
So they Fill in the login form. The javascript control code ajax submits the form This hits the event dispatch which does the post login event. Whoops, password is wrong, authentication fail view event is called. The dispatcher however knows that this came from POST instead of GET and further XMLHTTPREQUEST was used, so a javascript callback is fired back with the answer of no and reason. When it evals the login box shakes angrily, turns it borders red, then displays what went wrong.
They fill it in again and get it right. Javascript callback has the browser load the homepage.
The homepage data event requires summaries off the recentWork table, newMessages table, and the session table has an incomplete form that the user didn’t finish yesterday before the user session timed out, so we do an alert to see if the user wants to pick up on that. We fire the view event…
And so on. I think it has promise. It’s a tangent off MVC I haven’t seen before…
Thoughts?