ZF-5906: Multi rowclass support in Zend_Db_Table_Abstract and Zend_Db_Table_Rowset_Abstract
Description
Rows from a database table should have the possibility to be instantiated as different types of objects depending on the values in the database row. Currently Zend_Db_Table_Abstract and Zend_Db_Table_Rowset_Abstract do not enable it.
I suggest that a protected method called getRowClass(array $data = array()) is added to both the _Table and Rowset abstract classes.
The methods to be modified are the following (changes made against ZF 1.7.2): -Zend_Db_Table_Abstract -- public function createRow(array $data = array(), $defaultSource = null) Replace lines
@Zend_Loader::loadClass($this->_rowClass);
$row = new $this->_rowClass($config);
With
$className = $this->_getRowClass($data);
$row = new $className($config);
-- public function fetchRow($where = null, $order = null) Replace lines
@Zend_Loader::loadClass($this->_rowClass);
return new $this->_rowClass($data);
With
$className = $this->_getRowClass($rows[0]);
return new $className($data);
-Zend_Db_Table_Rowset_Abstract -- public function current() Replace lines
$this->_rows[$this->_pointer] = new $this->_rowClass(
array(
'table' => $this->_table,
'data' => $this->_data[$this->_pointer],
'stored' => $this->_stored,
'readOnly' => $this->_readOnly
)
);
With
$className = $this->_getRowClass($this->_data[$this->_pointer]); // Find the correct class name
$this->_rows[$this->_pointer] = new $className(
array(
'table' => $this->_table,
'data' => $this->_data[$this->_pointer],
'stored' => $this->_stored,
'readOnly' => $this->_readOnly
)
);
Both Zend_Db_Table_Abstract and Zend_Db_Table_Rowset_Abstract should contain the following method, which then can be overridden in inheriting classes.
/**
* Returns a string matching the class name for this data. Default implementation returns the classname
* given in ROW_CLASS configuration option.
* @param array $data
* @return string Name of the class matching the given data.
*/
protected function _getRowClass(array $data = array())
{
@Zend_Loader::loadClass($this->_rowClass);
return $this->_rowClass;
}
Comments
Posted by Tommy Mattila (lup0) on 2009-02-27T04:12:21.000+0000
Example usage:
Posted by Martin Mayer (martin.mayer) on 2009-03-05T13:34:33.000+0000
Imho this feature should be left for userland code only where it's easy to implement. This is useful just for a few special cases.
Posted by Tommy Mattila (lup0) on 2009-03-05T22:19:20.000+0000
The trouble with implementing this feature in userland code is that we lose compatibility with Zend Framework. Because PHP doesn't allow casting of objects we cannot call for example the fetchRow or createRow methods of the Zend_Db_Table_Abstract. We need to directly instantiate the correct implementing class. Between ZF 1.5 and 1.7 the implementation of Zend_Db_Table_Abstract::createRow() and its dependencies were modified so much that it broke the compatibility between my createRow() implementation and the rest of Zend_Db_Table_Abstract.
Posted by Martin Mayer (martin.mayer) on 2009-03-06T02:43:33.000+0000
I still think it easy to do in user code and keep "compatibility" with ZF, simply by overriding Zend_Db_Table_Abstract::createRow() like this:
Though the implementation of Zend_Db_Table_Abstract::createRow() changed, it still works.
Posted by Tommy Mattila (lup0) on 2009-03-10T01:48:49.000+0000
You are right Martin that the code you showed enables us to keep Zend_Db_Table_Abstract's createRow() intact. But it doesn't work for fetchRow() because the data is retrieved inside the method the object is instantiated. Similar problems occur with the Zend_Db_Table_Rowset_Abstract::current() method.
Posted by Gerard Brouwer (gerard.brouwer1) on 2010-04-20T12:28:00.000+0000
I've the exact same need for this feature. It would be nice if it could be implement as suggested by Tommy!