views:

11508

answers:

13

What are some of the ways you have implemented models in the Zend Framework?

I have seen the basic class User extends Zend_Db_Table_Abstract and then putting calls to that in your controllers:

$foo = new User;

$foo->fetchAll()

but what about more sophisticated uses? The Quickstart section of the documentation offers such an example but I still feel like I'm not getting a "best use" example for models in Zend Framework. Any interesting implementations out there?


EDIT: I should clarify (in response to CMS's comment)... I know about doing more complicated selects. I was interested in overall approaches to the Model concept and concrete examples of how others have implemented them (basically, the stuff the manual leaves out and the stuff that basic how-to's gloss over)

+1  A: 

You can do more complicated queries, check the Advanced usage section in the Zend_Db_Table manual page.

$select = $table->select();
$select->from($table,
              array('COUNT(reported_by) as `count`', 'reported_by'))
       ->where('bug_status = ?', 'NEW')
       ->group('reported_by');
CMS
+1  A: 

you can extend the Zend_Db_Table_Abstract class and add some useful methods to it. for example you can add a changePassword() method to your user class and manipulate it's data. or you can change the default __toString() method of your class, so you'll have a customized __toString() method that, let's say returns the whole contact information of the user (name, address, phone number) in a well formatted string. in your constructor you could populate your data into properties of your object. then use them like:

public function __toString() {
   $data = $this->_name . ', ' . $this->_adderss . ', call: ' . $this->_phone;
   return $data;
}

your model extends the Zend_Db_Table_Abstract just to ease the process of accessing its data, but the functionality you could have on that data is all up on your creativity and need. I recommend you the book "php|architect's guide to programming with zend framework" by Cal Evans. the book is very informative and easy to read. chapters 4 and 6 are going to be useful for this matter.

farzad
+2  A: 

Skip ZF for the models part, there are much better solutions. The "M" in ZF's "MVC" is pretty much absent. Reading their docs they don't really mention models at all -- which is a good thing, it means you can use just about anything you want without writing lots of adapter code.

Take a look at Doctrine for models instead. It is quickly becoming the de-facto ORM for PHP.

Christopher Nadeau
Doctrine would be awesome but I cannot be certain of having access to versions of PHP current enough to satisfy doctrine's requirements.
gaoshan88
Doctrine says it requires PHP 5.2.3, while ZF requires PHP 5.1.4 but also strongly recommends 5.2.3 for its security and performance benefits.
Bill Karwin
+12  A: 

I personally subclass both Zend_Db_Table_Abstract and Zend_Db_Table_Row_Abstract. The main difference between my code and yours is that explicitly treat the subclass of Zend_Db_Table_Abstract as a "table" and Zend_Db_Table_Row_Abstract as "row". Very rarely do I see direct calls to select objects, SQL, or the built in ZF database methods in my controllers. I try to hide the logic of requesting specific records to calls for behind Zend_Db_Table_Abstract like so:

class Users extends Zend_Db_Table_Abstract {

    protected $_name = 'users';

    protected $_rowClass = 'Users'; // <== THIS IS REALLY HELPFUL

    public function getById($id) {
        // RETURNS ONE INSTANCE OF 'User'
    }

    public function getActiveUsers() {
        // RETURNS MULTIPLE 'User' OBJECTS            
    }

}

class User extends Zend_Db_Table_Row_Abstract {

    public function setPassword() {
        // SET THE PASSWORD FOR A SINGLE ROW
    }

}

/* CONTROLLER */
public function setPasswordAction() {

    /* GET YOUR PARAMS */

    $users = new Users();

    $user = $users->getById($id);

    $user->setPassword($password);

    $user->save();
}

There are numerous ways to approach this. Don't think this is the only one, but I try to follow the intent of the ZF's design. (Here are more of my thoughts and links on the subject.) This approach does get a little class heavy, but I feel it keeps the controllers focused on handling input and coordinating with the view; leaving the model to do the application specific work.

Barrett Conrad
Should "protected $_rowClass = 'Users';" have been "protected $_rowClass = 'User';"?
Svish
+23  A: 

I worked for Zend and did quite a bit of work on the Zend_Db_Table component.

Zend Framework doesn't give a lot of guidance on the concept of a "Model" with respect to the Domain Model pattern. There's no base class for a Model because the Model encapsulates some part of business logic specific to your application. I wrote a blog about this subject in more detail.

Persistence to a database should be an internal implementation detail of a Model. The Model typically uses one or more Table. It's a common but improper object-oriented design to consider a Model as an extension of a Table. In other words, we should say Model HAS-A Table -- not Model IS-A Table.

You can also read Martin Fowler's take on the Domain Model design pattern, and his description of the Anemic Domain Model antipattern, which is how many developers unfortunately approach OO programming.

Bill Karwin
"... did quite a bit of work on the Zend_Db_Table..." I know you did, Bill. I'm something of a fan of your php work, to be honest.
gaoshan88
FWIW, I didn't start the project, I only took over when the original guys moved on. Paul M. Jones (http://paul-m-jones.com/) deserves the credit as architect of the Zend_Db components.
Bill Karwin
Benedict Cohen
@Benedict: Right, but it's worth describing exactly what we mean by those terms, and why one is good and the other is bad.
Bill Karwin
Your blog is excellent Bill, but why not putting that in the ZF documentation !? When I did the quickstart for the 1st time, I didn't understood the "model/mapper/Zend_Db_Table" thing.
Matthieu
Thanks @Matthieu, I wrote the blog after I left the ZF project. I've developed that blog into a chapter of my new book, "SQL Antipatterns" http://www.pragprog.com/titles/bksqla/sql-antipatterns
Bill Karwin
+5  A: 

Don't ever use Zend_Db_Table as your model. It just gets you into trouble. Either you write your own model classes which use Zend_Db_Table to talk to your database or you can read my blog post here for a hack that allows you to somewhat combine the "Model" class and Zend_Db_Table.

The main thing to not is that when you use Zend_Db_Table directly in your controllers you end up doing the same things in multiple places. If you have to make a change to some of that logic, you have to make a change in multiple places. Not good. My first professional project was done like this because I was the one in the company who had to learn how to use ZF and it's a total mess now.

I also tend to write helper functions into my classes for sophisticated fetches. Somthing like $table->doNameFetchAll() or $table->doOrderFetchAll().

smack0007
Your link is broken, do you have another copy of said resource?
X-Istence
@x-istence It seems that blog moved from .com to .net domain. Here is the link: http://zacharysnow.net/2008/06/20/zend_db_table-as-a-model/
Petr Peller
Sorry, just saw this comment thread for the first time. I wrote that article long ago. If you writing a new application going forward I would take more of the approach presented in the Zend Framework quickstart: http://framework.zend.com/manual/en/learning.quickstart.create-model.html
smack0007
+1  A: 

A database entity is not the only kind of model component. As such, it doesn't really make sense to speak of models (in plural) - Your application has one model, which contains a multitude of components. Some of these components could be table gateways (And thus extend from Zend_Db), while others would not.

I recommend that you get hold of the book Domain Driven Design by Eric Evans, which does an excellent job of explaining how to construct an object model.

troelskn
+5  A: 

I've been doing some research on Models for ZF and came across an interesting series of articles by Matthew Weier O'Phinney which are well worth checking out:

It's not "production code" and a lot is left to the imagination, but it's a good read and has helped me quite a bit.

ironkeith
+1  A: 

I use Propel 1.3 instead of Zend_Db_Table. It's tricky to setup, but awesome. It can examine your database and auto-generate all your models. It actually generates 2 levels and 2 types of model.

Examples for 'user' table:

Level 1: BaseModel & BasePeer: these get overwritten every time you regenerate your ORM. i.e. BaseUser.php & BaseUserPeer.php

Level 2: StubModel & StubPeer: these don't get overwritten. They're the ones you customize. i.e. User.php & UserPeer.php

Type 1: Model - for basic CRUD operations, not queries i.e. User.php Type 2: Peer -- for queries. These are static objects. i.e. UserPeer.php

So to create a user:

$derek = new User();
$derek->setFirstName('Derek');
$derek->save();

To find all dereks:

$c = new Criteria();
$c->add(UserPeer::FIRST_NAME, 'Derek');
$dereks = UserPeer::doSelect($c);
lo_fye
+1  A: 

I suggest you read this article about Fat Models and Skinny Controllers http://www.survivethedeepend.com/zendframeworkbook/en/1.0/the.model and Google around a bit for those keywords.

wenbert
+1  A: 

http://zfsite.andreinikolov.com/2008/08/zend_db_table-time-overhead-about-25-percents/

Bit of a catch 22, Zend_Table is nice in principle, but generates some performance overheads (without caching)...

sunwukung
A: 

Haha, now I understand why all Zend applications are so so slow.... and so CPU/RAM eater

eBuildy
+1  A: 

A model has nothing to do with the database. What if I am fetching data from an RSS feed or a SOAP service or reading files from the FS?

I put all these kinds of things in models. In that case, my model class might not extend anything. I'm about to write a model that uses methods of other models.

sims
Absolutely agree! Although this is dated question, many people still come and look here, so I will postmy solution. I have written article how I have implemented Model and ORM in zend framework. Hope it helps to many people. it's on : http://havl.net/devnotes/2010/10/zendframework-model-orm/
DavidHavl