Models in Zend Framework

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_Adapter instance 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.

13 Comments

  1. [...] This post was mentioned on Twitter by Planet PHP and PHP Belarus, PHP Ireland. PHP Ireland said: Models in Zend Framework – Matthew Turland: A question that frequently comes up in my interactions with other deve… http://bit.ly/dqNqNC [...]

  2. Social comments and analytics for this post…

    This post was mentioned on Twitter by planetphp: Models in Zend Framework – Matthew Turland http://matthewturland.com/2010/03/26/models-in-zend-framework/

  3. EllisGL says:

    On some current work I’m doing, we have models, which don’t extend anything, only takes data in, passes it to what we call query classes and return them to the caller. So each method in a query class is specific to a DB/Table and only does simple query. No logic in those methods.

  4. [...] Turland has written an article on models in Zend Framework. A question that frequently comes up in my interactions with other developers about Zend Framework [...]

  5. abcphp.com says:

    Models in Zend Framework | Matthew Turland…

    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 …

  6. A nice overview of the core ideas. Thanks!

    The source code of DASPRiD’s site contains an interesting implementation of an injection-container-based service architecture that calls mappers which build models.

    Site itself: http://www.dasprids.de/
    Source code: http://site.svn.dasprids.de/trunk

    The App library, in particular, is completely generic: drop it into a project, add a little bootstrap, and start creating your own services, mappers, and models.

    I’ve just done one, though I fear I might have mucked it up a bit. More experienced hands would no doubt do a better job with it. I’ll probably try a little more experimentation to develop familiarity with custom mappers, but I feel that there might some Doctrine in my future).

    Cheers!

  7. Carlos Aguado says:

    “In a nutshell, the model handles data: storing it, retrieving it, filtering and validating it, and providing access to it.”

    Good to hear that filtering and validation are to be performed by the model. This is precisely my idea, as filtering and validation are also, somehow, “domain logic”. I had a long discussion about this with people that stated that filtering and validation are view’s tasks. I don’t agree with that at all…

    Thanks for the article!

  8. Doctrine 2 is very different from Doctrine 1 and it allows you to have Plain Old PHP Objects instead of Active Records in your model (a la Hibernate). Very beneficial. :)

  9. Arne Riemann says:

    Thanks for this nice post,now i have to rethink my Model Architecture.

  10. Jeff Dickey says:

    @Carlos Aguado: Exactly. The way I’ve preferred to develop MVC applications (desktop, Web, whatever) is to use a view that has near-zero intelligence – it just serves as a mapping from a logical/functional API (exercised by the controller) to the code needed to paint the interface. Since the controller is basically a traffic cop (take this command input, get the appropriately-massaged data from the model and hand it off to the view), that means that most of the “interesting” code goes into a “heavy” model (which itself is a set of interfaces with various domain classes in between. This makes it easy to, say, change application types. (here’s a Web site; here’s a set of Web services; here’s a desktop app…. see how much gets reused?) It’s also easy (easier) to make heart-transplant-level architectural changes. Client wants a new database? Fine. They’re booting their old ISP and the new one has several major differences? Sorted.

    Of course, MVC is also The Poster Child™ for TDD and CI, but that’s a whole other set of posts…

  11. James Green says:

    FWIW I find it best to decouple the model and the database. Instead, I have the model which knows almost nothing about the underlying persistence and one or more data loading/saving classes. The saving classes can be thrown the model and database connection (usually a Zend_Db_Adapter_Abstract instance) usually because the calling code knows it loaded that object through the same class. Allows us to cleanly switch between database schemas or even load representations from external sources such as a CRM.

  12. [...] Models in Zend Framework – Matthew Turland Post a Comment Name [...]