2008年7月24日星期四

[fw-db] About new step of Zend_Db_Table*

Second Party.

We wants more!!! I and Milfont need the inheritance with 2 tables. An example is the table Person and Developer. A Developer is a Person and in ORM he need have fullname, but this data belongs to table Person. :D

tables:

+------------------+    +--------------+
|Person            |    |Developer     |
+------------------+    +--------------+
|id_person int (PK)|--+ |id_developer  |
+------------------+  | +--------------+
|fullname varchar  |  <>|id_person (FK)|
+------------------+    +--------------+
                        |language      |
                        +--------------+



I wanna a code like follow work:

<?php

$devModel = new Developer(); //Model class extended Zend_Db_Table_Abstract and $_name="Developer"
$dev = $devModel->find(1)->current();
$dev->fullname = "full name test";
$dev->save(); // here the fullname will save in Person Table
?>

So I modify the Zend_Db_Table* classes.

The first step was choice the way and I choice create a attribute call _father(protected) in each instance of Row and a attribute call _fatherRule(protected) in table class. This have the name of rule of _referenceMap. In my choise the class Developer extends class Person, but can be implemented in difence way. I modify this fallow methods to call the rigth method in _father if the attribute not exist in current instance.

Zend_Db_Table_Abstract:
     /**
     * @var string
     */
    protected $_fatherRule = "";
   
    public function getFatherRule()
    {
        return $this->_fatherRule;
    }

Zend_Db_Table_Row_Abstract


    /**
     * Object father
     *
     * @var Zend_Db_Table_Row_Abstract
     */
    protected $_father = null;

    /**
     * Initialize object
     *
     * Called from {@link __construct()} as final step of object instantiation.
     *
     * @return void
     */
    public function init()
    {
        parent::init();
         
        if ($this->_table->getFatherRule())
        {
            $this->_father = $this->findParentRow(get_parent_class($this->_table),$this->_table->getFatherRule());
        }
        $this->_columnMap = $this->_table->getColumnMap();
    }

    /**
     * Retrieve row field value
     *
     * @param  string $columnName The user-specified column name.
     * @return string             The corresponding column value.
     * @throws Zend_Db_Table_Row_Exception if the $columnName is not a column in the row.
     */
    public function __get($columnName)
    {
        $columnName = $this->_transformColumn($columnName);
        if (!array_key_exists($columnName, $this->_data)) {
            if ($this->_father)
            {
                return $this->_father->$columnName;
            }
            else
            {
                require_once 'Zend/Db/Table/Row/Exception.php';
                throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row");
            }             
        }
        else
        {
            return $this->_data[$columnName];
        }
    }

    /**
     * Set row field value
     *
     * @param  string $columnName The column key.
     * @param  mixed  $value      The value for the property.
     * @return void
     * @throws Zend_Db_Table_Row_Exception
     */
    public function __set($columnName, $value)
    {
        $columnName = $this->_transformColumn($columnName);
        if (!array_key_exists($columnName, $this->_data)) {
            if ($this->_father)
            {
                $this->_father->$columnName=$value;
            }
            else
            {
                require_once 'Zend/Db/Table/Row/Exception.php';
                throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row");
            }
        }
        $this->_data[$columnName] = $value;
        $this->_modifiedFields[$columnName] = true;
    }

    /**
     * Test existence of row field
     *
     * @param  string  $columnName   The column key.
     * @return boolean
     */
    public function __isset($columnName)
    {
        $columnName = $this->_transformColumn($columnName);
        if (array_key_exists($columnName, $this->_data))
        {
            return true;
        }
        else if ($this->_father)
        {
            return $this->_father->__isset($columnName);
        }
        else
        {
            return false;
        }
    }

    /**
     * Store table, primary key and data in serialized object
     *
     * @return array
     */
    public function __sleep()
    {
        return array('_tableClass', '_primary', '_data', '_cleanData', '_readOnly' ,'_modifiedFields','_father');
    }
   
    /**
     * Saves the properties to the database.
     *
     * This performs an intelligent insert/update, and reloads the
     * properties with fresh data from the table on success.
     *
     * @return mixed The primary key value(s), as an associative array if the
     *     key is compound, or a scalar if the key is single-column.
     */
    public function save()
    {
       parent::save();
       if ($this->_father)
       {
            $this->_father->save();
       }
    }

     /**
     * Query a parent table to retrieve the single row matching the current row.
     *
     * @param string|Zend_Db_Table_Abstract $parentTable
     * @param string                        OPTIONAL $ruleKey
     * @return Zend_Db_Table_Row_Abstract   Query result from $parentTable
     * @throws Zend_Db_Table_Row_Exception If $parentTable is not a table or is not loadable.
     */
    public function findParentRow($parentTable, $ruleKey = null, Zend_Db_Table_Select $select = null)
    {
        $db = $this->_getTable()->getAdapter();

        if (is_string($parentTable)) {
            try {
                @Zend_Loader::loadClass($parentTable);
            } catch (Zend_Exception $e) {
                require_once 'Zend/Db/Table/Row/Exception.php';
                throw new Zend_Db_Table_Row_Exception($e->getMessage());
            }
            $parentTable = new $parentTable(array('db' => $db));
        }
        if (! $parentTable instanceof Zend_Db_Table_Abstract) {
            $type = gettype($parentTable);
            if ($type == 'object') {
                $type = get_class($parentTable);
            }
            require_once 'Zend/Db/Table/Row/Exception.php';
            throw new Zend_Db_Table_Row_Exception("Parent table must be a Zend_Db_Table_Abstract, but it is $type");
        }

        try {
            $map = $this->_prepareReference($this->_getTable(), $parentTable, $ruleKey);
            if ($select === null) {
                $select = $parentTable->select();
            } else {
                $select->setTable($parentTable);
            }
            for ($i = 0; $i < count($map[Zend_Db_Table_Abstract::COLUMNS]); ++$i) {
                $dependentColumnName = $db->foldCase($map[Zend_Db_Table_Abstract::COLUMNS][$i]);
                $value = $this->_data[$dependentColumnName];
                // Use adapter from parent table to ensure correct query construction
                $parentDb = $parentTable->getAdapter();
                $parentColumnName = $parentDb->foldCase($map[Zend_Db_Table_Abstract::REF_COLUMNS][$i]);
                $parentColumn = $parentDb->quoteIdentifier($parentColumnName, true);
                $parentInfo = $parentTable->info();
                $type = $parentInfo[Zend_Db_Table_Abstract::METADATA][$parentColumnName]['DATA_TYPE'];
                $select->where("$parentColumn = ?", $value, $type);
            }
            return $parentTable->fetchRow($select);
        }
        catch (Zend_Db_Table_Exception $e)
        {
            if ($this->_father)
            {
                return $this->_father->findParentRow($parentTable,$ruleKey,$select);
            }
            else
            {
                throw $e;
            }
        }
    }

I can implement Zend_Db_Table_Row_Abstract::findParentRow,
but lack implement the Zend_Db_Table_Row_Abstract::findDependentRowset and Zend_Db_Table_Row_Abstract::findManyToManyRowset.


--
Fernando Chucre - LPIC-1
http://www.horizontesdigitais.com

没有评论: