Location: PHPKode > projects > Maintainable PHP Framework > vendor/Mad/Model/Join/Dependency.php
<?php
/**
 * @category   Mad
 * @package    Mad_Model
 * @subpackage Join
 * @copyright  (c) 2007-2009 Maintainable Software, LLC
 * @license    http://opensource.org/licenses/bsd-license.php BSD
 */

/**
 * @category   Mad
 * @package    Mad_Model
 * @subpackage Join
 * @copyright  (c) 2007-2009 Maintainable Software, LLC
 * @license    http://opensource.org/licenses/bsd-license.php BSD
 */
class Mad_Model_Join_Dependency
{
    /**
     * The array of model objects to build the join. First element
     * is always the base model.
     * @var array
     */
    protected $_joins = array();

    /**
     * The array of association reflections
     * @var array
     */
    protected $_reflections = array();

    /**
     * The 'include' association array used to build the dependency
     * @var array
     */
    protected $_associations = array();

    /**
     * The list of table aliases used to build SQL To make sure we don't duplicate.
     * @var array
     */
    protected $_tableAliases = array();

    /**
     * The hash of base records
     * @var array
     */
    protected $_baseRecordsHash = array();


    /*##########################################################################
    # Construct/Destruct
    ##########################################################################*/

    /**
     * Construct Join dependency
     * @param   object        $model
     * @param   array|string  $associations
     */
    public function __construct(Mad_Model_Base $model, $associations)
    {
        $this->_joins              = array(new Mad_Model_Join_Base($model));
        $this->_associations       = $associations;
        $this->_baseRecordsHash    = array();
        $this->_tableAliases[$model->tableName()] = 1;

        $this->_build($associations);
    }

    /**
     * Stringified version of the object
     * @return  string
     */
    public function __toString()
    {
        foreach ($this->_joins as $join) {
            $joinData[] = $join->__toString();
        }
        return "\n".implode("\n", $joinData);
    }


    /*##########################################################################
    # Public
    ##########################################################################*/

    /**
     * Get all the joins
     *
     * @return  array()
     */
    public function reflections()
    {
        return $this->_reflections;
    }

    /**
     * Get all the joins
     *
     * @return  array()
     */
    public function joins()
    {
        return $this->_joins;
    }

    /**
     * Get the base model join
     *
     * @return  array
     */
    public function joinBase()
    {
        return $this->_joins[0];
    }

    /**
     * Get the association joins
     *
     * @return  array
     */
    public function joinAssociations()
    {
        return array_slice($this->_joins, 1);
    }

    /**
     * Instantiate the model/association given the sql rows
     *
     * @param   array   $rows
     * @return  array
     */
    public function instantiate($rows)
    {
        foreach ($rows as $row) {
            $primaryId = $this->joinBase()->recordId($row);
            if (!isset($this->_baseRecordsHash[$primaryId])) {
                $this->_baseRecordsHash[$primaryId] = $this->joinBase()->instantiate($row);
            }
            $this->_construct($this->_baseRecordsHash[$primaryId], $this->_associations,
                              $this->joinAssociations(), $row);
        }
        return array_values($this->_baseRecordsHash);
    }

    /**
     * Get the list of table aliases
     *
     * @return  array
     */
    public function tableAliases()
    {
        return $this->_tableAliases;
    }

    /**
     * Get the table alias index for the given name
     *
     * @param   string  $name
     * @return  int
     */
    public function tableAlias($name)
    {
        return isset($this->_tableAliases[$name]) ? $this->_tableAliases[$name] : 0;
    }

    /**
     * Add a table alias to the list
     *
     * @param   string  $alias
     */
    public function addTableAlias($alias)
    {
        if (isset($this->_tableAliases[$alias])) {
            $this->_tableAliases[$alias]++;
        } else {
            $this->_tableAliases[$alias] = 1;
        }
    }


    /*##########################################################################
    # Private
    ##########################################################################*/

    /**
     * Iterate through associations and build list of joins needed
     *
     * @param   array|string  $associations
     * @param   object        $parent
     */
    protected function _build($associations, $parent=null)
    {
        // previous join is the parent
        if (!isset($parent)) {
            $tmp = array_slice($this->_joins, -1);
            $parent = array_pop($tmp);
        }

        // Association name
        if (is_string($associations)) {
            if (!$reflection = $parent->reflections($associations)) {
                throw new Mad_Model_Exception("Association named \"$associations\" was not found");
            }
            $this->_reflections[] = $reflection;
            $this->_joins[] = new Mad_Model_Join_Association($reflection, $this, $parent);

        // Reference to another association
        } elseif (is_array($associations)) {
            foreach ($associations as $key => $val) {
                // array
                if (is_int($key)) {
                    $this->_build($val, $parent);

                // hash
                } else {
                    $this->_build($key, $parent);
                    $this->_build($val);
                }
            }
        }
    }

    /**
     * Construct model from the result row
     *
     * @param   object  $parent
     * @param   array   $associations
     * @param   array   $row
     */
    protected function _construct(Mad_Model_Base $parent, $associations, $joins, $row)
    {
        // Association name
        if (is_string($associations)) {
            // get the join we need
            do {
                $join = array_shift($joins);
            } while ($associations != $join->reflection()->getAssocName());

            $this->_constructAssociation($parent, $join, $row);

         // Reference to another association
        } elseif (is_array($associations)) {
            foreach ($associations as $key => $val) {
                // array
                if (is_int($key)) {
                    $this->_construct($parent, $val, $joins, $row);

                // hash
                } else {
                    // get the join we need
                    do {
                        $join = array_shift($joins);
                    } while ($key != $join->reflection()->getAssocName());

                    if ($association = $this->_constructAssociation($parent, $join, $row)) {
                        $this->_construct($association, $val, $joins, $row);
                    }
                }
            }
        }
    }

    /**
     * Construct associations for model from record/row
     *
     * @param   object  $record
     * @param   object  $join
     * @param   array   $row
     */
    protected function _constructAssociation(Mad_Model_Base $record, 
                                             Mad_Model_Join_Base $join, $row)
    {
        // set that we've loaded this association
        $record->setAssociationLoaded($join->reflection()->getAssocName());

        if ($record->id != $join->parent()->recordId($row) ||
            empty($row[$join->aliasedPrimaryKey()])) {
            return;
        }
        $association = $join->instantiate($row);

        $macro = $join->reflection()->getMacro();
        $singular = Mad_Support_Inflector::singularize($join->reflection()->getAssocName());

        if ($macro == 'hasAndBelongsToMany' || $macro == 'hasMany' || 
            $macro == 'hasManyThrough') {
            $addMethod = Mad_Support_Inflector::camelize('add'.ucfirst($singular), 'lower');
            $addMethod = str_replace('/', '_', $addMethod);

            // make sure object isn't already included
            $getter = Mad_Support_Inflector::camelize($join->reflection()->getAssocName(), 'lower');
            $getter = str_replace('/', '_', $getter);
            $exists = array();
            foreach ($record->$getter as $val) { $exists[] = $val->id; }

            if (!in_array($association->id, $exists)) {
                $record->$addMethod($association);
            }

        } elseif ($macro == 'belongsTo' || $macro == 'hasOne') {
            $assignMethod = Mad_Support_Inflector::camelize($singular, 'lower');
            $record->$assignMethod = $association;
        }
        return $association;
    }
}
Return current item: Maintainable PHP Framework