-- remataklan <[email protected]> wrote
(on Friday, 08 May 2009, 05:36 AM -0700):
> I was trying to understand the quickstart guide on the ZF site. 
> 
> My question is about the model part.
> First of all a little check to see if I understand the stuff. As I
> understand Zend_Db_Table handles the stuff with database. The mapper maps
> this to the model and the model handles everything about getting and setting
> data. Is this correct?

That's how we setup the quick start, yes. It's using three patterns:

 * Domain Model (the Default_Model_Guestbook class)
 * Data Mapper (the Default_Model_GuestbookMapper class)
 * Table Data Gateway (the Default_Model_DbTable_Guestbook class)

One slight difference to what you wrote: the domain model is an object
that has properties and behavior. The data mapper maps those to a
persistence layer (the database, in this case).

> Now the question, is it me or in the end the data we passed to the
> view is a little bit large. I mean the whole model object is passed to
> the final view.  Is this the correct way to do it?

It's one way to do it. When it comes down to it, the size of an item
passed to the view is not really an issue -- and, in fact, passing
objects is typically less expensive than other data as the objects are
passed by reference.

> And finally if I wanted to find to all posts from a certain user do I
> need a new function in the mapper? Something like 

So, another person responded already, and he was suggesting using
Zend_Db_Table as your model.

This is a perfectly valid approach -- Martin Fowler notes in his section
on Domain Models that it's often expedient to use ActiveRecord or table
data gateway directly as your models, particularly for prototyping or
when the model has a basically 1:1 mapping to the database. 

Problems arise, however, when you decide you want to persist your
data differently. For instance, if you decide to move to a document
storage system, or offload the direct data access to a middle-ware tier
accessed via web services, or even want to abstract access so that you
can use memcached unless the data is not cached. It was for these
reasons that we chose to go with a slightly more abstract approach in
the current iteration of the Quick Start.

So, back to your example; that's one way to do it. The drawback is
you'll find yourself writing methods in your mapper for every behaviour
in your model, which quickly eliminates some of the benefits of having a
data mapper in the first place.

Another approach is to build and use a Query Object
(http://www.martinfowler.com/eaaCatalog/queryObject.html), and then have
the data mapper figure out how to map the query object into a request
for the data access layer. In such a case, you might do something like
this:

    public function query(Model_QueryObject $query)
    {
        $table  = $this->getDbTable();
        $select = $table->select();

        foreach ($query->getCriteria() as $criteria) {
            $method = 'where';
            if ($criteria->isOr()) {
                $method = 'orWhere';
            }
            $statement = $criteria->getField() . ' '
                       . $criteria->getOperator() . ' ?';
            $select->$method($statement, $criteria->getValue());
        }

        $resultSet = $table->fetchAll($select);
        $entries   = array();
        foreach ($resultSet as $row) {
            $entry = new Model_List($row->toArray());
            $entry->setMapper($this);
            $entries[] = $entry;
        }
        return $entries;
    }

This affords you the ability to have a fairly generic data mapper that
can handle arbitrary criteria. It's not quite as flexible as
Zend_Db_Select (no support for joins, order, having, etc.), but for most
purposes it would be adequate.

Your model, then, would have a postsByUser() method, and would look
something like this:

    public function postsByUser($userId)
    {
        $query = new Model_QueryObject();
        $query->addCriteria(array(
            'field'    => 'user_id', 
            'operator' => '=',
            'value'    => $userId,
        ));
        return $this->getMapper()->query($query);
    }

I won't go into the query object definition for now -- but it's
basically just able to add criteria objects and return them. The
criteria objects themselves simply are value objects, with properties
for field, operator, and value.

> public function postsByUser($userId)
>     {
>         $resultSet =
> $this->getDbTable()->fetchAll($this->getDbTable()->select()->where('user_id
> = ?', $userId));
> 
>         $entries   = array();
>         foreach ($resultSet as $row) {
>             $entry = new Model_List();
>             $entry->setId($row->id)
>                   ->setEmail($row->email)
>                   ->setComment($row->comment)
>                   ->setCreated($row->created)
>                   ->setMapper($this);
> 
>             $entries[] = $entry;
>         }
>         return $entries;
>     }
> 
> or is there better way.
> 
> 
> -- 
> View this message in context: 
> http://www.nabble.com/Zend-Model-and-quickstart-tp23445168p23445168.html
> Sent from the Zend Framework mailing list archive at Nabble.com.
> 

-- 
Matthew Weier O'Phinney
Project Lead            | [email protected]
Zend Framework          | http://framework.zend.com/

Reply via email to