Jun 292012
 

The new Zend\Db in Zend Framework 2 has a handy feature which allows you to specify your own entity/model class to represent rows in your database tables. This means you can tell Zend\Db to return each row as a populated instance of your own custom objects. Keep in mind that this is simply a convenience feature, and not meant to serve as a fully-featured ORM. If you’re looking for a full-blown ORM, have a look at Doctrine 2.

For this demonstration, let’s assume the following table:

CREATE TABLE `book` (
   `isbn10` VARCHAR(10) NOT NULL,
   `isbn13` VARCHAR(13) NOT NULL,
   `author` VARCHAR(50) NOT NULL,
   `title` VARCHAR(255) NOT NULL,
   `year` INT(4) NOT NULL
);

The first step is to create a simple entity class which represents a row in your table:

<?php
 
namespace MyModule\Entity;
 
class Book
{
    protected $isbn10;
 
    protected $isbn13;
 
    protected $author;
 
    protected $title;
 
    protected $year;
 
    public function getIsbn10()
    {
        return $this->isbn10;
    }
 
    public function setIsbn10($isbn10)
    {
        $this->isbn10 = $isbn10;
        return $this;
    }
 
    public function getIsbn13()
    {
        return $this->isbn13;
    }
 
    public function setIsbn13($isbn13)
    {
        $this->isbn13 = $isbn13;
        return $this;
    }
 
    public function getAuthor()
    {
        return $this->author;
    }
 
    public function setAuthor($author)
    {
        $this->author = $author;
        return $this;
    }
 
    public function getTitle()
    {
        return $this->title;
    }
 
    public function setTitle($title)
    {
        $this->title = $title;
        return $this;
    }
 
    public function getYear()
    {
        return $this->year;
    }
 
    public function setYear($year)
    {
        $this->year = (int) $year;
        return $this;
    }
}

Next, let’s set up the database connection, and configure a TableGateway:

<?php
 
$dbSettings = array(
    'driver'    => 'pdo',
    'dsn'       => 'mysql:dbname=mydb;host=localhost',
    'username'  => 'evan',
    'password'  => '123456',
);
$dbAdapter          = new \Zend\Db\Adapter\Adapter($dbSettings);
$hydrator           = new \Zend\Stdlib\Hydrator\ClassMethods;
$rowObjectPrototype = new \MyModule\Entity\Book;
$resultSet          = new \Zend\Db\ResultSet\HydratingResultSet($hydrator, $rowObjectPrototype);
$tableGateway       = new \Zend\Db\TableGateway\TableGateway('book' /* table name  */, $dbAdapter, null, $resultSet);

Now we’re ready to try it out. To insert a new record into the database, you might do something like this:

<?php
 
$book = new \MyModule\Entity\Book;
$book->setIsbn10('0321127420')
     ->setIsbn13('9780321127426')
     ->setAuthor('Martin Fowler')
     ->setTitle('Patterns of Enterprise Application Architecture')
     ->setYear(2002);
$tableGateway->insert($hydrator->extract($book));

Nothing special so far, right? Well, let’s see what happens when we do a select:

<?php
 
// Select all books by Martin Fowler
$books = $tableGateway->select(array('author' => 'Martin Fowler'));
 
foreach ($books as $book) {
    // Each row comes back as an instance of MyModule\Entity\Book
    echo $book->getTitle() . ' by ' . $book->getAuthor() . "\n";
}

As you can see, each row comes back as a populated instance of MyModule\Entity\Book!

In this example, I’m using the Zend\Stdlib\Hydrator\ClassMethods hydrator, which simply takes ‘my_field’ and calls Entity::setMyField($value) (it has a constructor parameter to use camelCase or not). There are several other hydrators available in Zend\Stdlib\Hydrator worth looking at and you can even make your own custom hydrator(s) by simply implementing Zend\Stdlib\Hydrator\HydratorInterface.

  9 Responses to “Using Zend\Db’s TableGateway and HydratingResultSet to return rows as custom entity/model objects in ZF2”

  1. I know full well you wrote this to stop me badgering you on IRC, but thanks very much anyway!

  2. As you can see, each row comes back as a populated instance of MyModule\Entity\Book!

    What is the advantage of a TableGateway over a simple table class that extends Zend_Db_Table and has protected $_rowClass = ‘MyLib_Table_Row_Book’? e.g.

    $books = $table->fetchAll($table->select('author = ?', 'Martin Fowler'));

    This seems to get where you want to go quicker. Is there a larger problem which TableGateway exists to solve, and this is just how one obvious task is handled within that framework?

  3. Nice :D domain models are cleaner then custom rows :)

  4. @Kalessin: an row object is not equal to an model. The model doesn’t know where the data comes from, where an row object is simply a table row. There are some advantages in splitting models from gateways.

  5. Seems very nice, but.. if you will add inputFilter implementation, hydrator will also extract inputFilter object with all data in the row. Is it possible to get rid of this without hacks?

  6. I posted a question I had related to hydrators in ZF2 at http://zend-framework-community.634137.n4.nabble.com/ZF2-Hydrators-td4655622.html

    I’m not sure if I should re-post it here. I figured the link would be better. :-)

  7. Hi evan,

    I ‘ve got a Catchable fatal error when I intent insert a row in DB. I don’t understand why happening it, my code is the same that you has posted.

    My class:

    <?php namespace Frontend\Model; /** * Description of CommentTable * * @author jorts */ use Zend\Db\TableGateway\TableGateway; use \Frontend\Model\Comment;

    class CommentTable { protected $_commentTableGateway; protected $_hydratator; protected $_resultSet;

    public function __construct($adapter)
    {
        $this->_hydratator           = new \Zend\Stdlib\Hydrator\ClassMethods;
        $rowObjectPrototype = new Comment();
        $this->_resultSet          = new \Zend\Db\ResultSet\HydratingResultSet($this->_hydratator, $rowObjectPrototype);
        $this->_commentTableGateway =  new TableGateway('comments', $adapter, null, $this->_resultSet );
    }   
    public function fetchAll() 
    {
        return $this->_commentTableGateway->select();
    }
    
    public function saveComment(Comment $comment)
    {
        $data = array(
            'autor' => $comment->getAutor(),
            'email'  => $comment->getEmail(),
            'comment'  => $comment->getComment(),
            'ip'  => $comment->getIp(),
            'browser'  => $comment->getBrowser(),
            'fecha'  => $comment->getIdPublication()
        );
    
        $id = (int)$comment->getId();
        if ($id == 0) {
            $this->_commentTableGateway->insert($this->_hydratator->extract($comment));//in this line fired the error
        } else {
            if ($this->getComment($id)) {
                $this->_commentTableGateway->update($data, array('id' => $id));
            } else {
                throw new \Exception('El comentario que queire editar no exite');
            }
        }
    }
    
    public function getComment($id)
    {
        $id  = (int) $id;
        $rowset = $this->_commentTableGateway->select(array('id' => $id));
        $row = $rowset->current();
        if (!$row) {
            throw new \Exception("Could not find row $id");
        }
        return $row;
    }
    

    }

    I put this class in service manager and I get it in controller , of this way: public function getCommentTable() { if (!$this->_commentTable) { $sm = $this->getServiceLocator(); $this->_commentTable = $sm->get(‘Comment\Model\CommentTable’); } return $this->_commentTable; }

    and in my module class a factory of that model:

                    'Comment\Model\CommentTable' =>  function($sm) {
                         $dbAdapter          = $sm->get('Zend\Db\Adapter\Adapter');
                        $table = new CommentTable($dbAdapter);
                        return $table;
                    },
    

    But doesn’t works… I get this error:

    Catchable fatal error: Object of class stdClass could not be converted to string in D:\xampp\htdocs\haystack\vendor\zendframework\zendframework\library\Zend\Db\Adapter\Driver\Pdo\Statement.php on line 258

    Any help is appreciated.

    Kind regards.

  8. I write a leave a response each time I appreciate a post on a site or I have something to valuable to contribute to the discussion.

    <

    p>Usually it’s a result of the sincerness communicated in the post I looked at. And on this post Using Zend\Db

  9. Check out this wordpress plugin to help with bounce rate http://goo.gl/6lVVqP

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre user="" computer="" color="" escaped="">