Introduction to Zend_Db

I recently worked on a project which was based on Zend Framework – I haven’t worked with it before and I was temporarily confused by the existing implementation of some of the database-level stuff. After much reading and untangling of code, I’m now pretty clear how this should look, so here’s my overview. I’m not going to go into setting up a whole application, but this is a quick primer on how data models go together.

Modelling Tables

Zend_Db_Table is a class that represents a table. You instantiate one of these and call query functions against it. The actual code for my classes is really minimal, here’s an example:

class UserTable extends Zend_Db_Table
{
    protected $_name = 'users';
    protected $_rowClass = 'User';
}

The two properties that I’m setting here are all I use for basic tables. $_name tells Zend Framework which database table to use. $_rowClass tells it which class it should instantiate for the results from your select query. By default you’ll get Zend_Db_Table_Row objects but you can have it use any object which extends this class instead.

Getting Results

To get results from a table, you instantiate the relevant table class, and then fetch some results. You can restrict the results you get but Zend_Db_Select is a whole other kettle of fish that perhaps I’ll post about some other day. So a controller action might look something like this:

function viewAction()
{
    $users = new UserTable();
    $user_list = $users->fetchAll();
}

The $user_list variable will then hold an instance of Zend_Db_Rowset.

Working with Rowsets

The rowsets are iterators, you can loop over them and they will return objects which represent the rows in the resultset of the query. By default these are objects of type Zend_Db_Table_Row but if you set the table object’s rowClass, either in the object declaration or by calling setRowClass() before you fetch the results, then you can have any class which extends Zend_Db_Table_Row used. Its pretty common to pass the rowset straight to the view and iterate over it there – you can put any functionality you need for this object into the class you use. Let’s look at my user class for this example.

The Row Class

    class User extends Zend_Db_Table_Row
    {
        public function getName()
        {
            return $this->first_name . ' '.$this->last_name;
        }

        public function getProfileUrl()
        {
            return '/users/profile/id/' . $this->id;
        }
    }

These are overly simple examples, but giving this kind of functionality to the user model allows it to be re-used any place you need it. I’ve also found it useful to have an intermediate table row class that contains functionality that will be used by data from more than one table – for example for formatting dates in a consistent manner.

Zend Framework and Models

This is a pretty simple overview but it took me a while to get to this point – the framework does have documentation but its quite case-specific and doesn’t really show how it ties together. Now I understand these classes and their relationships, my development project is going a lot more smoothly.

15 thoughts on “Introduction to Zend_Db

  1. butters: glad to hear it helped :)

    Stuart: The very nature of what I do means I work with whatever I need to, and I don’t get to choose! I’d be interested to see examples of how it works in other systems though

  2. diamondTears: glad to have cleared things up a bit.

    Zachary: I am now further into my project than I was when I wrote this post and I repent entirely the decision to inherit from the table_row classes!! I’ll be writing another post when I’ve settled a bit more with the whole concept but suffice to say I’ve got ordinary models with SQL or use of Zend_Db stuff in the various methods and that is working much better! They do say “you live and learn” and I did on this one :)

    Simon: Thanks for sharing the link. I agree that ORMs can be more hazard than help – especially since I know a lot more about databases than about PHP frameworks.

    • I have made the same mistake on my project(before I even read this post, so this is not your fault :-) ). I inherit EVERY classes from the table_row classes.
      Now I can see there is something wrong with the whole concept but I’m too deep in the projetc to change that. Anyway I would be glad to hear more from you about that.
      Tanks for this Post

    • The thing that gets me is this: in any non-trivial project, a model doesn’t just interact with MySQL. Models end up in caching layers, in sessions, and interacting with users through forms, query parameters, and of course APIs.

      Given all that, any sort of model that is designed around tables and rows just seems ultimately to be missing the point :)

      Best regards,
      Stu

  3. Thanks for this posting. I would like to question your assertion that you should have an intermediate class functions such as date formatting. Surely this kind of function should be implemented as a method on an independent helper class. Do you agree?

  4. Karim: You make a good point. In general, if I’m writing formatting code that is specific to a particular object, I’ll make it a method of the object, just to keep everything together. But if its something like formatting a date which will happen in lots of places, then yes I would want to use a helper. The examples in my post were really too simple – just because I wanted to give an outline without any distractions

  5. Therein lies the rub. When you do ORM at this level it seems almost mechanical until you realize that it introduces a lot of application layer cruft in your more complex models that could have been done by queries.

    I’m pretty good at queries, and while I ordinarily say don’t worry about preformance at first, the thing will preform better ultimately if we let the db server do complex queries rather than selecting a whole bunch of stuff and filtering it through a lot of these table objects in the app. When you do it this way you hardwire it into your model at a low level and it is not so easy to optimize.

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

This site uses Akismet to reduce spam. Learn how your comment data is processed.