A question that frequently comes up in my interactions with other developers about Zend Framework is how to approach designing models. There’s a small collection of resources and advice that I generally give on the subject, so I thought I’d write up a blog post to give people an easy place to access it all.
More than one way to skin a cat
First, there is no one “correct” way to design a model. If there were, the framework would probably have an actual model component. It doesn’t, and as Bill Karwin — former Project Manager for Zend Framework — has said, the reason for this because designing the model is your job. There are pros and cons to any approach. It’s all about finding a method that works for you, is appropriate for the situation at hand, and mitigates difficulty in long-term application maintenance.
The Model section of the Quick Start Guide and this blog post by Michelangelo van Dam includes examples of a Data Mapper approach.
Zend_Db uses a Table Data Gateway and Row Data Gateway approach. Doctrine, a popular ORM library that is gaining traction in the ZF community, uses an Active Record approach. And available approaches don’t stop there. As a general rule of thumb when designing models and components in general, I recommend favoring composition over inheritance. You’ll get a better sense of what I mean by that later in the post.
Defining the model
The Wikipedia article on the MVC architectural pattern isn’t all-encompassing, but isn’t a bad place to start either. In particular, it drives home a few important points about the model that you should bear in mind.
The model is a “domain-specific representation of the data upon which the application operates.”
In a nutshell, the model handles data: storing it, retrieving it, filtering and validating it, and providing access to it.
The model contains “domain logic” that “adds meaning to raw data.”
In other words, it handles the conversion from raw data in a data source to semantically meaningful PHP objects and back again.
“MVC does not specifically mention the data access layer because it is understood to be underneath or encapsulated by the model.”
The shorter version:
$model != $database. This is one point that trips a lot of people up. The model and your database are not congruent, synonymous, or in any way equivalent. Yes, 99% of the time, your model will use a database for its data source. However, models can be more complex than that: they can serve as clients to web services, limit access to data using an ACL, access data caching resources like memcached or APC, and so forth.
Designing the model
“So which approach do you use?”
Generally, the answer is none of the above. My personal preference is to keep data, in the form of plain old PHP arrays and objects, separate from logic to handle that data. Many common PHP tasks result in data already being present in either of these forms such as in its superglobal arrays, so it seems natural to just take it in the form in which it’s provided.
I define a model class that composes some other object to access the data I need, generally a
Zend_Db_Adapter instance. Any methods of that model class return data using scalar types or classes that PHP supports natively. What’s great about this is that it’s fairly easy to convert data to and from these forms using type juggling regardless of the data’s origin.
“But wait, how can I encapsulate the data source within my model if I need a dependency like a
Zend_Db_Adapterinstance for it to be able to interact with that data source?”
This is another major question that people tend to ask. If any code calling your model first has to handle injecting its dependencies, that muddies up separation of concerns because calling code then must have some knowledge of how your model operates internally. This is a problem because, if the data source of the model needs to change in the future, all calling code needs to change as well versus only model code. There are a few ways to approach this problem in Zend Framework.
The first method involves storing your dependencies in
Zend_Registry. Declare accessor methods in the model for dependencies that retrieve them from the registry only if they are not explicitly injected from calling code. This bypasses the need for dependency injection from application code, thus preserving separation of concerns, but still allows injection to be performed for unit testing purposes.
The second method is a variation of the first and is specific to the case of
Zend_Db_Adapter instances. This approach involves setting your adapter as the default adapter to use for
Zend_Db_Table instances in lieu of using the registry to store it. Note that this doesn’t require actually using
Zend_Db_Table in order to work. This can be set from the bootstrap or application configuration file, then retrieved using the
getDefaultAdapter() method of the
Zend_Db_Table_Abstract class. Again, don’t forget your accessor methods so dependencies can be injected from unit tests.
Another method might be to use a service locator as a dependency in models. This serves as a layer of abstraction between models and their dependencies when it comes to controllers dealing with both. To my knowledge, the closest thing to an implementation of this in ZF is the Zend_Application_Bootstrap classes. From a controller, the bootstrap instance can be accessed as in the code example below.
$bootstrap = $this->getInvokeArg('bootstrap');
Where to go from here
Service layers are another frequent topic related to models. Those aside, I mainly suggest picking a simple model that you can prototype and try several approaches to see which you prefer. If you’ve got some ZF experience under your belt, I’d be interested in hearing about your own modeling approaches and experiences and encourage you to leave a comment on this post.