diff options
7 files changed, 214 insertions, 48 deletions
| diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php b/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php index 3bb1a74b..c72ba160 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php @@ -1,7 +1,71 @@ -<?php +<?php
 +/**
 + * TActiveRecordBelongsTo class file.	
 + *
 + * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2005-2007 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id$
 + * @package System.Data.ActiveRecord.Relations
 + */
 +/**
 + * Loads base active record relationship class.
 + */
  Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
 +/**
 + * Implements the foreign key relationship (TActiveRecord::BELONGS_TO) between 
 + * the source objects and the related foreign object. Consider the 
 + * <b>entity</b> relationship between a Team and a Player.
 + * <code>
 + * +------+            +--------+
 + * | Team | 1 <----- * | Player |
 + * +------+            +--------+
 + * </code>
 + * Where one team may have 0 or more players and each player belongs to only
 + * one team. We may model Team-Player <b>object</b> relationship as active record as follows.
 + * <code>
 + * class TeamRecord extends TActiveRecord
 + * {
 + *     // see TActiveRecordHasMany for detailed definition.
 + * }
 + * class PlayerRecord extends TActiveRecord
 + * {
 + *     const TABLE='player';
 + *     public $player_id; //primary key
 + *     public $team_name; //foreign key player.team_name <-> team.name
 + * 	   public $age;
 + *     public $team; //foreign object TeamRecord
 + * 
 + *     protected static $RELATIONS = array(
 + *			'team' => array(self::BELONGS_TO, 'TeamRecord'));
 + * 
 + *	   public static function finder($className=__CLASS__)
 + *	   {
 + *		   return parent::finder($className);
 + *	   }
 + * }
 + * </code>
 + * The <tt>$RELATIONS</tt> static property of PlayerRecord defines that the
 + * property <tt>$team</tt> belongs to (or is a) <tt>TeamRecord</tt>s.
 + *
 + * The team object may be fetched as follows.
 + * <code>
 + * $players = PlayerRecord::finder()->with_team()->findAll();
 + * </code>
 + * The method <tt>with_xxx()</tt> (where <tt>xxx</tt> is the relationship property
 + * name, in this case, <tt>team</tt>) fetchs the corresponding TeamRecords using
 + * a second query (not by using a join). The <tt>with_xxx()</tt> accepts the same
 + * arguments as other finder methods of TActiveRecord, e.g. 
 + * <tt>with_team('location = ?', 'Madrid')</tt>.
 + *
 + * @author Wei Zhuo <weizho[at]gmail[dot]com>
 + * @version $Id$
 + * @package System.Data.ActiveRecord.Relations
 + * @since 3.1
 + */
  class TActiveRecordBelongsTo extends TActiveRecordRelation
  {
  	/**
 @@ -39,5 +103,5 @@ class TActiveRecordBelongsTo extends TActiveRecordRelation  		}
  	}
  }
 - +
  ?>
\ No newline at end of file diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php index 27ffd194..795630ab 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php @@ -17,14 +17,14 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');  /**
   * Implements TActiveRecord::HAS_MANY relationship between the source object having zero or
 - * more foreign objects. Consider the relationship between a Team and a Player.
 + * more foreign objects. Consider the <b>entity</b> relationship between a Team and a Player.
   * <code>
   * +------+            +--------+
 - * | Team | 1 -----> * | Player |
 + * | Team | 1 <----- * | Player |
   * +------+            +--------+
   * </code>
   * Where one team may have 0 or more players and each player belongs to only
 - * one team. We may model Team-Player relationship as active record as follows.
 + * one team. We may model Team-Player <b>object</b> relationship as active record as follows.
   * <code>
   * class TeamRecord extends TActiveRecord
   * {
 @@ -44,15 +44,7 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');   * }
   * class PlayerRecord extends TActiveRecord
   * {
 - *     const TABLE='player';
 - *     public $player_id; //primary key
 - *     public $team_name; //foreign key player.team_name <-> team.name
 - * 	   public $age;
 - *
 - *	   public static function finder($className=__CLASS__)
 - *	   {
 - *		   return parent::finder($className);
 - *	   }
 + *     // see TActiveRecordBelongsTo for detailed definition
   * }
   * </code>
   * The <tt>$RELATIONS</tt> static property of TeamRecord defines that the
 diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php index 048f776b..e8c2ccee 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php @@ -1,6 +1,33 @@ -<?php +<?php
 +/**
 + * TActiveRecordHasOne class file.
 + *
 + * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2005-2007 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id$
 + * @package System.Data.ActiveRecord.Relations
 + */
 +
 +/**
 + * Loads base active record relationship class.
 + */
  Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
 +/**
 + * TActiveRecordHasOne models the object relationship that a record (the source object)
 + * property is an instance of foreign record object having a foreign key
 + * related to the source object. 
 + *
 + *
 + * 
 + *
 + * @author Wei Zhuo <weizho[at]gmail[dot]com>
 + * @version $Id$
 + * @package System.Data.ActiveRecord.Relations
 + * @since 3.1
 + */
  class TActiveRecordHasOne extends TActiveRecordRelation
  {
  	/**
 @@ -38,5 +65,5 @@ class TActiveRecordHasOne extends TActiveRecordRelation  		}
  	}
  }
 - +
  ?>
\ No newline at end of file diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php index f1e8fa60..38455309 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php @@ -1,6 +1,30 @@  <?php
 +/**
 + * TActiveRecordRelation class file.
 + *
 + * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2005-2007 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id$
 + * @package System.Data.ActiveRecord.Relations
 + */
 +
 +/**
 + * Load active record relationship context.
 + */
  Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelationContext');
 +/**
 + * Base class for active record relationships.
 + *
 + * description
 + *
 + * @author Wei Zhuo <weizho[at]gmail[dot]com>
 + * @version $Id$
 + * @package System.Data.ActiveRecord.Relations
 + * @since 3.1
 + */
  abstract class TActiveRecordRelation
  {
  	private $_context;
 @@ -28,11 +52,10 @@ abstract class TActiveRecordRelation  	/**
  	 * Dispatch the method calls to the source record finder object. When
 -	 * the results are returned as array or is an instance of TActiveRecord we
 -	 * will fetch the corresponding foreign objects with an sql query and populate
 -	 * the results obtained earlier.
 +	 * an instance of TActiveRecord or an array of TActiveRecord is returned
 +	 * the corresponding foreign objects are also fetched and assigned.
  	 *
 -	 * Allows chaining multiple relation handlers.
 +	 * Multiple relationship calls can be chain together.
  	 *
  	 * @param string method name called
  	 * @param array method arguments
 @@ -106,7 +129,7 @@ abstract class TActiveRecordRelation  	/**
  	 * Obtain the foreign key index values from the results.
  	 * @param array property names
 -	 * @param array|TActiveRecord TActiveRecord results
 +	 * @param array TActiveRecord results
  	 * @return array foreign key index values.
  	 */
  	protected function getIndexValues($keys, $results)
 @@ -134,14 +157,16 @@ abstract class TActiveRecordRelation  	{
  		$collections=array();
  		foreach($fkObjects as $fkObject)
 -		{
 -			$hash = $this->getObjectHash($fkObject, $fields);
 -			$collections[$hash][]=$fkObject;
 -		}
 -
 +			$collections[$this->getObjectHash($fkObject, $fields)][]=$fkObject;
  		$this->setResultCollection($results, $collections, $properties);
  	}
 +	/**
 +	 * Populates the result array with foreign objects (matched using foreign key hashed property values).
 +	 * @param array $results
 +	 * @param array $collections
 +	 * @param array property names
 +	 */
  	protected function setResultCollection(&$results, &$collections, $properties)
  	{
  		if(is_array($results))
 @@ -150,9 +175,7 @@ abstract class TActiveRecordRelation  				$this->setObjectProperty($results[$i], $properties, $collections);
  		}
  		else
 -		{
  			$this->setObjectProperty($results, $properties, $collections);
 -		}
  	}
  	/**
 diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php index 03dc4cd5..a33e105e 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php @@ -1,7 +1,33 @@  <?php +/**
 + * TActiveRecordRelationContext class.
 + *
 + * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2005-2007 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id$
 + * @package System.Data.ActiveRecord.Relations
 + */
 +/**
 + * TActiveRecordRelationContext holds information regarding record relationships
 + * such as record relation property name, query criteria and foreign object record
 + * class names.
 + *
 + * This class is use internally by passing a context to the TActiveRecordRelation
 + * constructor.
 + *
 + * @author Wei Zhuo <weizho[at]gmail[dot]com>
 + * @version $Id$
 + * @package System.Data.ActiveRecord.Relations
 + * @since 3.1
 + */
  class TActiveRecordRelationContext
  {
 +	/**
 +	 * static property name in TActiveRecord that defines the record relationships.
 +	 */
  	const RELATIONS_CONST = 'RELATIONS';
  	private $_property;
 @@ -16,9 +42,13 @@ class TActiveRecordRelationContext  		$this->_criteria=$criteria;
  		$this->_relation = $this->getSourceRecordRelation($property);
  	}
 +
  	/**
 +	 * Uses ReflectionClass to obtain the relation details array of a given
 +	 * property from the $RELATIONS static property in TActiveRecord.
  	 * @param string relation property name
  	 * @return array relation definition.
 +	 * @throws TActiveRecordException if property is not defined or missing.
  	 */
  	protected function getSourceRecordRelation($property)
  	{
 @@ -34,46 +64,76 @@ class TActiveRecordRelationContext  				$property, get_class($this->_sourceRecord), self::RELATIONS_CONST);
  	}
 +	/**
 +	 * @return string name of the record property that the relationship results will be assigned to.
 +	 */
  	public function getProperty()
  	{
  		return $this->_property;
  	}
 +	/**
 +	 * @return TActiveRecordCriteria sql query criteria for fetching the related record.
 +	 */
  	public function getCriteria()
  	{
  		return $this->_criteria;
  	}
 +	/**
 +	 * @return TActiveRecord the active record instance that queried for its related records.
 +	 */
  	public function getSourceRecord()
  	{
  		return $this->_sourceRecord;
  	}
 +	/**
 +	 * @return string foreign record class name.
 +	 */
  	public function getForeignRecordClass()
  	{
  		return $this->_relation[1];
  	}
 +	/**
 +	 * @return string HAS_MANY, HAS_ONE, or BELONGS_TO
 +	 */
  	public function getRelationType()
  	{
  		return $this->_relation[0];
  	}
 +	/**
 +	 * @return string the M-N relationship association table name.
 +	 */
  	public function getAssociationTable()
  	{
  		return $this->_relation[2];
  	}
 +	/**
 +	 * @return boolean true if the relationship is HAS_MANY and requires an association table.
 +	 */
  	public function hasAssociationTable()
  	{
  		return isset($this->_relation[2]);
  	}
 +	/**
 +	 * @return TActiveRecord corresponding relationship foreign object finder instance.
 +	 */
  	public function getForeignRecordFinder()
  	{
  		return TActiveRecord::finder($this->getForeignRecordClass());
  	}
 +	/**
 +	 * Creates and return the TActiveRecordRelation handler for specific relationships.
 +	 * An instance of TActiveRecordHasOne, TActiveRecordBelongsTo, TActiveRecordHasMany,
 +	 * or TActiveRecordHasManyAssocation will be returned.
 +	 * @return TActiveRecordRelation record relationship handler instnace.
 +	 */
  	public function getRelationHandler()
  	{
  		switch($this->getRelationType())
 diff --git a/framework/Data/ActiveRecord/TActiveRecord.php b/framework/Data/ActiveRecord/TActiveRecord.php index 67057554..2ff3f1d4 100644 --- a/framework/Data/ActiveRecord/TActiveRecord.php +++ b/framework/Data/ActiveRecord/TActiveRecord.php @@ -10,9 +10,9 @@   * @package System.Data.ActiveRecord   */ -/**
 - * Load record manager, criteria and relations.
 - */
 +/** + * Load record manager, criteria and relations. + */  Prado::using('System.Data.ActiveRecord.TActiveRecordManager');  Prado::using('System.Data.ActiveRecord.TActiveRecordCriteria');  Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelationContext'); @@ -282,7 +282,7 @@ abstract class TActiveRecord extends TComponent  	 * @param array name value pair record data  	 * @return TActiveRecord object record, null if data is empty.  	 */ -	public function populateObject($type, $data) +	protected function populateObject($type, $data)  	{  		if(empty($data)) return null;  		$registry = $this->getRecordManager()->getObjectStateRegistry(); @@ -311,7 +311,7 @@ abstract class TActiveRecord extends TComponent  	/**  	 * @param TDbDataReader data reader  	 */ -	public function collectObjects($reader) +	protected function collectObjects($reader)  	{  		$result=array();  		$class = get_class($this); @@ -428,14 +428,14 @@ abstract class TActiveRecord extends TComponent  	}  	/** -	 * Fetches records using the sql clause "(fields) IN (values)", where
 -	 * fields is an array of column names and values is an array of values that
 -	 * the columns must have.
 -	 *
 -	 * This method is to be used by the relationship handler.
 -	 *
 -	 * @param TActiveRecordCriteria additional criteria
 -	 * @param array field names to match with "(fields) IN (values)" sql clause.
 +	 * Fetches records using the sql clause "(fields) IN (values)", where +	 * fields is an array of column names and values is an array of values that +	 * the columns must have. +	 * +	 * This method is to be used by the relationship handler. +	 * +	 * @param TActiveRecordCriteria additional criteria +	 * @param array field names to match with "(fields) IN (values)" sql clause.  	 * @param array matching field values.  	 * @return array matching active records.  	 */ @@ -461,17 +461,17 @@ abstract class TActiveRecord extends TComponent  		return $gateway->countRecords($this,$criteria);  	} -	/**
 -	 * Returns the active record relationship handler for $RELATION with key
 +	/** +	 * Returns the active record relationship handler for $RELATION with key  	 * value equal to the $property value. -	 * @param string relationship property name.
 +	 * @param string relationship property name.  	 * @param array method call arguments.  	 * @return TActiveRecordRelation  	 */  	protected function getRelationHandler($property,$args)  	{ -		$criteria = $this->getCriteria(count($args)>0 ? $args[0] : null, array_slice($args,1));
 -		$context = new TActiveRecordRelationContext($this, $property, $criteria);
 +		$criteria = $this->getCriteria(count($args)>0 ? $args[0] : null, array_slice($args,1)); +		$context = new TActiveRecordRelationContext($this, $property, $criteria);  		return $context->getRelationHandler();  	} diff --git a/framework/Data/ActiveRecord/TActiveRecordStateRegistry.php b/framework/Data/ActiveRecord/TActiveRecordStateRegistry.php index ef415b5e..691090dc 100644 --- a/framework/Data/ActiveRecord/TActiveRecordStateRegistry.php +++ b/framework/Data/ActiveRecord/TActiveRecordStateRegistry.php @@ -54,13 +54,13 @@ class TActiveRecordStateRegistry  	 * @param mixed row data fetched
  	 * @return TActiveRecord cached object if found, null otherwise.
  	 */
 -	public function getCachedInstance($data)
 +	public function getCachedInstance($data,$mustBeClean=true)
  	{
  		$key = $this->getObjectDataKey($data);
  		if(isset($this->_cachedObjects[$key]))
  		{
  			$obj = $this->_cachedObjects[$key];
 -			if($this->getIsCleanObject($obj))
 +			if(!($mustBeClean && !$this->getIsCleanObject($obj)))
  				return $obj;
  		}
  	}
 | 
