Zend Framework Models – Part 1: Concepts

The power in Zend Framework lies in its uncompromising flexibility. However, evidently, this also means its very difficult for new ZF users to pick up the framework and hit the ground running. The most common question I see is usually “where is the model?”. The goal of this post is to show some examples and hopefully some new ideas on how to tackle models. There is no one-size-fits-all solution folks. Let’s look at some options and some background…

The concept of a model

Before we can go any further, we must first figure out what a model is. This stuff isn’t an exact science, so there will be some gray areas. Much of this post is my opinion (read: not fact). This doesn’t necessarily make them right or wrong. I like to think I’m right, so feel free to argue with me in the comments below.

In an MVC application, the model is responsible for all the business logic. The controller should handle flow control (taking input, calling models, redirection, etc.), and the view is responsible for representing your application, usually with some sort of data language (XML, HTML, JSON, etc.)

Implementation and and interpretation of the pattern is up to the developer… there are some gray areas so don’t worry if it doesn’t meet the exact specification. However, one thing I like to practice is skinny controllers, fat models. By shifting a lot of the work to the models (and their underlying libraries) you can usually organize your application much better. The result is simpler and more organized (primarily better encapsulated) code.

Simply said, a model should contain your business logic. Any processing that revolves around your application data should probably be put into models. I consider a model to be anything that does something in the big picture of your application… things like reading/writing data, sending/receiving data, processing data. They do the “work”.

One mistake I see is people simply setting up ORM (ex: Doctrine) models for each of their tables and leaving it at that. Your models’ public interfaces should be very simple. I prefer to have their interface represent their actual domain logic. For example, if you are making a post, then your controller (or calling code) should simply call something very self explanatory like post->create( info ). One personal guideline I follow is not to have more than 4 or 5 parameters to a method, and ideally, only 1 to 3.

One common implementation of this annoyance of mine is putting in chained query calls in your controller. Yes, the actual database code is encapsulated, but you are still revealing way too much information in your controller. The whole point of them is to encapsulate not only the code, but also the underlying logic. This way, when your business logic changes, your controllers can usually continue to function properly.

Working with databases

Most web applications revolve around storing information in the database. Whether it’s posts, comments or pictures, it all boils down to the same few operations. You can call this CRUD: create, read, update and destroy. In practice, it’s often much more complicated… but they remain to be the underlying concepts for most database interaction.

Most other frameworks come with a default model class/component which is a huge push in the right direction. Zend keeps an open mind about it, providing a few tools to use if you want to work with the database. Zend comes with a huge Zend_Db component to handle your database operations. It also contains Zend_Db_Table which is an implementation of the Table Data Gateway and Row Data Gateway patterns.

Personally, I’m not a big fan of Zend_Db_Table. I still think Doctrine is much more powerful, though I do really like Zend_Db. It operates under some of the same principles as PDO (database abstraction layer), so if you have used that before, you will be at home. I also really like Zend_Db_Select, which is what the table classes use quite a bit.

Using a base model

Because there are so many different types of models, I don’t think there is much point in having a do-it-all base class. However, for the group of models that will need database access, I use something like this:

class Site_Model {
    protected $_db;
 
    public function __construct(Zend_Db_Adapter_Abstract $db) {
        $this->_db = $db;
    }
}

You can probably tell that the default model is not even needed… and that’s the point. However, depending on your needs, this is a good place to start adding some common functionality that your db models will need. You may want to also make them all loader or dependency injector friendly if your application requires that.

Zend_Db

Zend’s database abstraction layer is really nice to work with. If you use it in combination with Zend_Db_Select you can make the database end of your application very portable. Here are some common methods I use from Zend_Db:

query(string)

fetchOne(query)
fetchRow(query)
fetchAll(query)

insert(table, data)
update(table, data, where)
delete(table, where)

quote(value)
quoteInto(string, value)

Abstracting your queries

If I’m working on an application that I plan to release to the public, then I always use Zend_Db_Select. It works on the same concept as the above insert/update/delete methods, meaning that you never have to write any of the SQL. If you let the Db libraries do it, then you are able to get much more portable code. Zend_Db supports IBM’s DB2, MySQL, MSSQL, Oracle, PostgreSQL and SQLite, so Db_Select is targetted at the same databases.

The concept of Zend_Db_Select is that the query is an object, and you can add/modify different parts of it. This gives you a lot more flexibility over dynamic query creation, as well as the added bonus of portability.

Summary

For your basic database-oriented models, all you your class will need is access to the Zend_Db_Adapter_Abstract interface. Keep your public methods very domain-oriented and your controllers will thank you for it. Break out of the mindset that models = database tables, or even model = database. Usually only around half my models deal with database operations. ZF also has a ton of service libraries available to help with all the common social sites APIs out there.

The next installment of this post will go into some concrete examples and also some ideas on how to implement your models. Comments and criticism welcomed and appreciated as always.