“What is a model” and “Is Zend_Db_Table a model” seem to be asked once in a while on #zftalk. Frameworks say they have a full model available, thus they are MVC frameworks
ORM libraries say they generate models. It seems the ActiveRecord pattern has become somewhat synonymous with model.
Pádraic Brady wrote an excellent post on how models are misunderstood, and how this poor understanding causes “fat stupid ugly controllers”, as he puts it.
Here are some thoughts on actually putting Pádraic’s advice into practice, and some examples in context of the Zend Framework.
Pádraic writes that the best controller is one that doesn’t need to exist. This is true: many pages simply need to display certain data fetched from the database (or other data source), or maybe simply a static page. Why would you need a controller for this?
At this point you may think “to pass the data from the model to the view, of course”, but that’s not really the case. If you’ve seen any of those diagrams which explain MVC, you may have noticed that line which goes from the view to the model to show that views could access models. In the case of Zend Framework, you could use view helpers for this.
I have to admit that I’ve done actions in my controllers just to get some data from the database. It’s so easy! Just grab data, assign it to the view, and have the view output it… Compared to having to think of a good way to access the model from the view. Maybe it would be time to break from status quo?
However, there are some questions in regards to having the views fetch data on their own. Very often the fetched data would depend on the parameters passed in from the URL, such as the ID of the document, the page of the list or such.
Many frameworks don’t implicitly allow access to the request in the view, so would accessing such variables require the intervention by a controller? Or would this too be a case where you would utilize a view helper?
In a sense, the parameters passed from the request are also parts of a model: the request model. The request model could be instanciated based on the request object itself, and it could perform validation on the data. Alternatively, you could set up your routes so, that they won’t match any requests with illegal data, by providing sufficient regexes for validation.
To achieve most flexibility, it would probably be a good idea to keep parsing any parameters from “outside” inside your controllers. Imagine a case where you for example displayed a specific user’s details. The user’s ID could come in from the request, and passed to the view from the controller.
In the most typical example you would see for the above, you probably would have the view called the same as the controller’s action. It could be “user” or something. But if the view itself could access the user model, it wouldn’t need to depend on the controller. So you could actually have some completely different controller render the user’s information if it needed to, by simply passing the user id to the user view. Or you could even have some other view include the user view as a partial, passing the user id to it.
So how would you access the models in your views then? You could write a view helper for each of them, or instanciate them in your views.. but that could be a bit tedious and sometimes not the best approach.
Instead, a single view helper for getting and instanciating models could be more convenient. It could work in a bit similar way as the service locator pattern does:
<?php $this->getModel('MyModel')->getAll(); ?>
Using this approach, the views would not need to know how the models are created, or what model they are actually even dealing with. You simply would program to a specific interface, assuming that by calling getModel(‘MyModel’), you would get something that conforms to MyModel_Interface, or something like that.
I’ve been thinking about these for a while already, but Pádraic Brady’s post got me thinking about it a bit more.
In all this, there’s still certain things that need to be kept in mind. Caching, for example. If you wanted to cache specific SQL resultsets or such, it would need to go somewhere where it would happen without interaction from the controller.
And finally, bear in mind that I don’t think these are necessarily the best approaches to solving this “problem”. Please comment what are your thoughts on this matter.