Question

Using Zend (1 or 2), what is the best way to abstract common code in the model mappers? In the controller/view there are the relevant helpers, what about in the mappers...

Was it helpful?

Solution

I tend to base my mappers on two examples:

  1. Survive the Deep End by Padraic Brady
  2. Dasprid's blog source

Padraic allows each mapper to compose other mappers, keeping the code DRY and focusing each mapper on precisely those database fields it needs to know about.

Dasprid's uses a base mapper class to contain common code for handling the db connection.

Together, there should be enough places to keep common code.

Of course, the Doctrine2 ORM manages most of this via configuration. After several only-half-satisfying attempts to do mapping myself, I have found myself happier with Doctrine.

OTHER TIPS

Just create a class in your library or wherever you store common code, perhaps something like:

//library/My/Model/Mapper/Abstract.php
<?php

abstract class My_Model_Mapper_Abstract
{
    /**
     * Instance of Zend_Db_Table_Abstract
     *
     * @var Zend_Db_Table_Abstract $tableGateway
     */
    protected $tableGateway = null;
    /**
     * sets up the identity map
     */
    protected $map          = array();

    /**
     * Will accept a DbTable model passed or will instantiate
     * a Zend_Db_Table_Abstract object from table name.
     *
     * @param Zend_Db_Table_Abstract $tableGateway
     */
    public function __construct(Zend_Db_Table_Abstract $tableGateway = null)
    {
        if (is_null($tableGateway)) {
            $this->tableGateway = new Zend_Db_Table($this->tableName);
        } else {
            $this->tableGateway = $tableGateway;
        }
    }

    /**
     * Get the default database table adapter.
     *
     * @return Zend_Db_Table_Abstract
     */
    protected function getGateway()
    {
        return $this->tableGateway;
    }

    //truncated for space

    public function findById($id)
    {
        if ($this->getMap($id)) {
            return $this->getMap($id);
        }

        $select = $this->getGateway()->select();
        $select->where('id = ?', $id);

        $row = $this->getGateway()->fetchRow($select);

        $entity = $this->createEntity($row);

        $this->setMap($row->id, $entity);

        return $entity;
    }

    //truncated for space

    /**
     * Abstract method to be implemented by concrete mappers.
     */
    abstract protected function createEntity($row);
}

Then a concrete implementation might resemble:

//application/modules/users/model/mappers/User.php
<?php

class Users_Model_Mapper_User extends My_Model_Mapper_Abstract
{
    protected $tableName = 'users';

    public function __construct(Zend_Db_Table_Abstract $tableGateway = null)
    {
        if (is_null($tableGateway)) {
            //TODO: inject this resource
            $tableGateway = new Application_Model_DbTable_User();
        } else {
            $tableGateway = $tableGateway;
        }

        parent::__construct($tableGateway);
    }

    protected function createEntity($row)
    {
        $data = array(
            'id'       => $row->id,
            'username' => $row->username,
            'password' => $row->password
        );
        $user = new Users_Model_User($data);

        return $user;
    }

    private function hashPassword($password)
    {
        return Password::createPasswordHash($password);
    }

    public function saveUser(My_Model_Entity_Abstract $user)
    {
        if (!is_null($user->id)) {

            $select = $this->getGateway()->select();
            $select->where('id = ?', $user->id);

            $row = $this->getGateway()->fetchRow($select);
        } else {
            $row = $this->getGateway()->createRow();
            $row->password = $this->hashPassword($user->password);
        }
        $row->username = $user->username;

        $row->save();
        return $row;
    }
}

These are created to utilize the DbTable Models commonly used in ZF1 and are still works in progress.

ZF2 models may be somewhat different as ZF2 implements and extends much more of the PHP SPL library so some modification will likely be useful.

Good Luck!

Actually Zend Framework does not offers any built-in ORM. There is just Zend_Db_Table (and Zend_Db_Table_Row) which implements Table Gateway pattern.

One of the common ways to work with data models in ZF-projects is to use Doctrine 2 ORM. First version of Doctrine (Doctrine 1) implemented Active record pattern and the second works with Data Mapper.

In Zend Framework 1 Quick Start in the section Create a Model and Database Table the possible self-developing implementation of Data Mapper pattern is described:

class Application_Model_Guestbook
{
    protected $_comment;
    protected $_created;
    protected $_email;
    protected $_id;

    public function __set($name, $value);
    public function __get($name);

    public function setComment($text);
    public function getComment();

    public function setEmail($email);
    public function getEmail();

    public function setCreated($ts);
    public function getCreated();

    public function setId($id);
    public function getId();
}

class Application_Model_GuestbookMapper
{
    public function save(Application_Model_Guestbook $guestbook);
    public function find($id);
    public function fetchAll();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top