The Blogs Page: The data classes
Saturday, December 19, 2009
The Default_Model_Db_Blog class is used to encapsulate the data contained in the rows of the blog table.
It is derived from Default_Model_Db_Abstract, which is an abstract base class for classes that encapsulate the data in a database table. Here is a skeleton outline of the class implementation:
abstract class Default_Model_Db_Abstract { const INTEGER = 'integer'; const STRING = 'string'; public function __construct($row = null) { // TODO: Implementation of constructor } public function __set($name, $value) { // TODO: Implementation of set magic method } public function __get($name) { // TODO: Implementation of get magic method } public function setFields($row) { // TODO: Implementation of setFields method } abstract protected function _getFields(); abstract protected function _createMapper(); protected function _getMapper() { // TODO: Implementation of getMapper method } private $_mapper; }
The constants INTEGER and STRING are used to represent that data types of the database fields. Of course, more constants could be added to represent other data types, e.g. FLOAT. It would then be necessary to add another case to the switch statement in the set magic method; the implementation of that is examined below.
The constructor is used to initialise and object used to represent a single row from the table. It takes an array as an optional parameter, which will be used to initialise the fields:
public function __construct($row = null) { if (isset($row)) { $this->setFields($row); } }
The set magic method is used to make sure that only the member variables representing the database fields can be set by classes using the object. Also, it casts the new value as the correct data type.
public function __set($name, $value) { $fields = $this->_getFields(); if (array_key_exists($name, $fields)) { switch ($fields[$name]) { case self::INTEGER: $this->$name = (int)$value; break; case self::STRING: $this->$name = (string)$value; break; default: $this->$name = $value; } } else { throw new Exception('Invalid field name'); } }
The get magic method enforces the same thing in the opposite direction:
public function __get($name) { $fields = $this->_getFields(); if (array_key_exists($name, $fields)) { if (isset($this->$name)) { return $this->$name; } else { return null; } } else { throw new Exception('Invalid field name'); } }
The setFields method is used to populate multiple fields within the row:
public function setFields($row) { $fields = $this->_getFields(); foreach ($fields as $name => $type) { if (isset($row->$name)) { $this->$name = $row->$name; } } }
There are a couple of abstract method declared in the class, _getFields and _createMapper, which need to be implemented in the derived class.
The _getFields method should return an array of key/value pairs, where the key is the field name, and the value is one of the constants defined in this class to represent field data types.
The _createMapper should instantiate an object of the corresponding mapper class and return a reference to that object. We shall look at the implementation of the abstract base and concrete mapper classes in a subsequent post. All that needs to be noted here is that the mapper links the data class with the database table.
The _createMapper method is called the first time a call is made to _getMapper; the reference returned is stored, then returned on subsequent calls to the method.
protected function _getMapper() { if ($this->_mapper === null) { $this->_mapper = $this->_createMapper(); } return $this->_mapper; }
The Default_Model_Db_Blog class derives from this abstract class. Here is a skeleton outline of the class implementation:
class Default_Model_Db_Blog extends Default_Model_Db_Abstract { protected function _getFields() { // TODO: Implementation of _getFields method } protected function _createMapper() { // TODO: Implementation of _createMapper method } public function fetchBlogs() { // TODO: Implementation of fetchBlogs method } public function fetchBlog($id) { // TODO: Implementation of _fetchBlog method } }
The _getFields method, declared as abstract in the base class, returns an array of five values, corresponding to the fields in the blog table:
protected function _getFields() { return array( 'id' => self::INTEGER, 'name' => self::STRING, 'description' => self::STRING, 'href' => self::STRING, 'feed' => self::STRING ); }
The _createMapper, also declared as abstract in the base class, creates and returns an object of the appropriate type to act as the mapper for the class:
protected function _createMapper() { return new Default_Model_Db_Mapper_Blog(); }
There are a couple of additional functions declared here, which perform the two basic operations required against the blog table. They both make use of the mapper class.
The first fetches the details of all the blogs:
public function fetchBlogs() { return $this->_getMapper()->fetchAll(); }
The second retrieves the details of a specific blog, identified by its ID:
public function fetchBlog($id) { $where = $this->_getMapper()->getSelect()->where('id = ?', $id); return $this->_getMapper()->fetchRow($where); }
In my next post, I shall look at the mapper classes.

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