The Blogs Page: The mapper classes
Tuesday, February 9, 2010
The Default_Model_Db_Mapper_Blog class is used to manage data exchange between the Default_Model_Db_Blog and the Default_Model_Db_Table_Blog classes; this exchange represents reading data from and writing data to the database.
It is derived from the abstract class Default_Model_Db_Mapper_Abstract. Here is a skeleton outline of the class implementation:
abstract class Default_Model_Db_Mapper_Abstract { public function fetchAll($where = null, $order = null, $count = null, $offset = null) { // TODO: Implementaion of fetchAll method } public function fetchRow($where = null, $order = null) { // TODO: Implementation of fetchRow method } public function getSelect() { // TODO: Implementation of getSelect method } abstract protected function _createTable(); abstract protected function _createRow($result); private function _getTable() { // TODO: Implementation of _getTable method } private $_table; }
The fetchAll method is called to retrieve multiple records from the table. It makes use of the abstract _getTable and _createRow methods to create the appropriate table object, and to create an instance of the appropriate data object for each row in the database.
public function fetchAll($where = null, $order = null, $count = null, $offset = null) { $results = $this->_getTable()->fetchAll( $where, $order, $count, $offset); $rows = array(); foreach ($results as $result) { $row = $this->_createRow($result); $rows[] = $row; } return $rows; }
The fetchOne method is similar, except that it only returns one row:
public function fetchRow($where = null, $order = null) { $result = $this->_getTable()->fetchRow($where, $order); if (isset($result)) { $row = $this->_createRow($result); } else { $row = null; } return $row; }
The select object used as the where parameter of the above methods can be created using the getSelect method. This also uses the _getTable method.
public function getSelect() { return $this->_getTable()->select(); }
The _getTable method implements the Singleton pattern; if there is not yet a table object, the method creates it and returns a reference to it; otherwise it just returns a reference:
private function _getTable() { if (null === $this->_table) { $this->_table = $this->_createTable(); } return $this->_table; }
Default_Model_Db_Mapper_Blog derives from this class; it implements the two abstract methods, _createTable() and _createRow($result), as required. The table created is an instance of the Default_Model_Db_Table_Blog class, while each row is an instance of Default_Model_Db_Blog, which was examined in the previous post:
class Default_Model_Db_Mapper_Blog extends Default_Model_Db_Mapper_Abstract { protected function _createTable() { return new Default_Model_Db_Table_Blog(); } protected function _createRow($result) { return new Default_Model_Db_Blog($result); } }

Practical Web 2.0 Applications with PHP (Expert's Voice) by Quentin Zervaas
Beginning Databases with PostreSQL: From Expert to Professional 2nd Edition: From Novice to Professional by Neil Matthew, Richard Stones
Great posts.
What about saving the model to the DB? Should there be a storeRow() in Default_Model_Db_Mapper_Abstract as well as a storeXXX() in Default_Model_Db_XXX?
Yes, that is essentially what needs to be added. However, writing is a more complex operation, in that a record may not exist already, so you would then need to perform an insert rather than an update. I may come back to looking at this in a later post, after I have finally finished the current series.