diff options
Diffstat (limited to 'framework/Data/ActiveRecord/Relations')
6 files changed, 142 insertions, 31 deletions
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php b/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php index c72ba160..1168bf55 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php @@ -1,6 +1,6 @@ <?php
/**
- * TActiveRecordBelongsTo class file.
+ * TActiveRecordBelongsTo class file.
*
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
* @link http://www.pradosoft.com/
@@ -16,8 +16,8 @@ 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
+ * 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>
* +------+ +--------+
@@ -38,17 +38,19 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation'); * 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'));
- *
+ *
+ * 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
+ * The static <tt>$RELATIONS</tt> 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.
@@ -58,7 +60,7 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation'); * 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.
+ * arguments as other finder methods of TActiveRecord, e.g.
* <tt>with_team('location = ?', 'Madrid')</tt>.
*
* @author Wei Zhuo <weizho[at]gmail[dot]com>
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php index 795630ab..c5ce616e 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php @@ -34,8 +34,10 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation'); *
* public $players=array(); //list of players
*
- * protected static $RELATIONS=array(
- * 'players' => array(self::HAS_MANY, 'PlayerRecord'));
+ * protected static $RELATIONS=array
+ * (
+ * 'players' => array(self::HAS_MANY, 'PlayerRecord')
+ * );
*
* public static function finder($className=__CLASS__)
* {
@@ -47,7 +49,7 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation'); * // see TActiveRecordBelongsTo for detailed definition
* }
* </code>
- * The <tt>$RELATIONS</tt> static property of TeamRecord defines that the
+ * The static <tt>$RELATIONS</tt> property of TeamRecord defines that the
* property <tt>$players</tt> has many <tt>PlayerRecord</tt>s.
*
* The players list may be fetched as follows.
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php index 456848fe..50558a2b 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php @@ -1,16 +1,98 @@ <?php
+/**
+ * TActiveRecordHasManyAssociation 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 relations class.
*/
Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
+/**
+ * Implements the M-N (many to many) relationship via association table.
+ * Consider the <b>entity</b> relationship between Articles and Categories
+ * via the association table <tt>Article_Category</tt>.
+ * <code>
+ * +---------+ +------------------+ +----------+
+ * | Article | * -----> * | Article_Category | * <----- * | Category |
+ * +---------+ +------------------+ +----------+
+ * </code>
+ * Where one article may have 0 or more categories and each category may have 0
+ * or more articles. We may model Article-Category <b>object</b> relationship
+ * as active record as follows.
+ * <code>
+ * class ArticleRecord
+ * {
+ * const TABLE='Article';
+ * public $article_id;
+ *
+ * public $Categories=array(); //foreign object collection.
+ *
+ * protected static $RELATIONS = array
+ * (
+ * 'Categories' => array(self::HAS_MANY, 'CategoryRecord', 'Article_Category')
+ * );
+ *
+ * public static function finder($className=__CLASS__)
+ * {
+ * return parent::finder($className);
+ * }
+ * }
+ * class CategoryRecord
+ * {
+ * const TABLE='Category';
+ * public $category_id;
+ *
+ * public $Articles=array();
+ *
+ * protected static $RELATIONS = array
+ * (
+ * 'Articles' => array(self::HAS_MANY, 'ArticleRecord', 'Article_Category')
+ * );
+ *
+ * public static function finder($className=__CLASS__)
+ * {
+ * return parent::finder($className);
+ * }
+ * }
+ * </code>
+ *
+ * The static <tt>$RELATIONS</tt> property of ArticleRecord defines that the
+ * property <tt>$Categories</tt> has many <tt>CategoryRecord</tt>s. Similar, the
+ * static <tt>$RELATIONS</tt> property of CategoryRecord defines many ArticleRecords.
+ *
+ * The articles with categories list may be fetched as follows.
+ * <code>
+ * $articles = TeamRecord::finder()->withCategories()->findAll();
+ * </code>
+ * The method <tt>with_xxx()</tt> (where <tt>xxx</tt> is the relationship property
+ * name, in this case, <tt>Categories</tt>) fetchs the corresponding CategoryRecords using
+ * a second query (not by using a join). The <tt>with_xxx()</tt> accepts the same
+ * arguments as other finder methods of TActiveRecord.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Data.ActiveRecord.Relations
+ * @since 3.1
+ */
class TActiveRecordHasManyAssociation extends TActiveRecordRelation
{
private $_association;
private $_sourceTable;
private $_foreignTable;
+ /**
+ * Get the foreign key index values from the results and make calls to the
+ * database to find the corresponding foreign objects using association table.
+ * @param array original results.
+ */
protected function collectForeignObjects(&$results)
{
$association = $this->getAssociationTable();
@@ -26,6 +108,9 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation $this->fetchForeignObjects($results, $foreignKeys,$indexValues,$sourceKeys);
}
+ /**
+ * @return TDbTableInfo association table information.
+ */
protected function getAssociationTable()
{
if($this->_association===null)
@@ -38,6 +123,9 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation return $this->_association;
}
+ /**
+ * @return TDbTableInfo source table information.
+ */
protected function getSourceTable()
{
if($this->_sourceTable===null)
@@ -48,6 +136,9 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation return $this->_sourceTable;
}
+ /**
+ * @return TDbTableInfo foreign table information.
+ */
protected function getForeignTable()
{
if($this->_foreignTable===null)
@@ -59,6 +150,9 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation return $this->_foreignTable;
}
+ /**
+ * @return TDbCommandBuilder
+ */
protected function getCommandBuilder()
{
return $this->getSourceRecord()->getRecordGateway()->getCommand($this->getSourceRecord());
@@ -117,6 +211,10 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation return $command;
}
+ /**
+ * @param array source table column names.
+ * @return string comma separated source column names.
+ */
protected function getSourceColumns($sourceKeys)
{
$columns=array();
@@ -127,6 +225,13 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation return implode(', ', $columns);
}
+ /**
+ * SQL inner join for M-N relationship via association table.
+ * @param array foreign table column key names.
+ * @param array source table index values.
+ * @param array source table column names.
+ * @return string inner join condition for M-N relationship via association table.
+ */
protected function getAssociationJoin($foreignKeys,$indexValues,$sourceKeys)
{
$refInfo= $this->getAssociationTable();
@@ -143,9 +248,7 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation $joins[] = "{$fkTable}.{$fkField} = {$refTable}.{$refField}";
}
$joinCondition = implode(' AND ', $joins);
-
$index = $this->getCommandBuilder()->getIndexKeyCondition($refInfo,array_keys($sourceKeys), $indexValues);
-
return "INNER JOIN {$refTable} ON ({$joinCondition}) AND {$index}";
}
}
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php index 4286254b..6348f16b 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php @@ -21,7 +21,7 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation'); * related to the source object. The HAS_ONE relation is very similar to the
* HAS_MANY relationship (in fact, it is equivalent in the entities relationship point of view).
*
- * The difference of HAS_ONE from HAS_MANY is that the foreign object is singular.
+ * The difference of HAS_ONE from HAS_MANY is that the foreign object is singular.
* That is, HAS_MANY will return a collection of records while HAS_ONE returns the
* corresponding record.
*
@@ -32,7 +32,7 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation'); * +-----+ +--------+
* </code>
* Where each engine belongs to only one car, that is, the Engine entity has
- * a foreign key to the Car's primary key. We may model
+ * a foreign key to the Car's primary key. We may model
* Engine-Car <b>object</b> relationship as active record as follows.
* <code>
* class CarRecord extends TActiveRecord
@@ -43,8 +43,10 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation'); *
* public $engine; //engine foreign object
*
- * protected static $RELATIONS=array(
- * 'engine' => array(self::HAS_ONE, 'EngineRecord'));
+ * protected static $RELATIONS=array
+ * (
+ * 'engine' => array(self::HAS_ONE, 'EngineRecord')
+ * );
*
* public static function finder($className=__CLASS__)
* {
@@ -57,14 +59,14 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation'); * public $engine_id;
* public $capacity;
* public $car_id; //foreign key to cars
- *
+ *
* public static function finder($className=__CLASS__)
* {
* return parent::finder($className);
* }
* }
* </code>
- * The <tt>$RELATIONS</tt> static property of CarRecord defines that the
+ * The static <tt>$RELATIONS</tt> property of CarRecord defines that the
* property <tt>$engine</tt> that will reference an <tt>EngineRecord</tt> instance.
*
* The car record with engine property list may be fetched as follows.
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php index 38455309..46609095 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php @@ -18,8 +18,6 @@ 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
@@ -66,7 +64,7 @@ abstract class TActiveRecordRelation static $stack=array();
$results = call_user_func_array(array($this->getSourceRecord(),$method),$args);
- if(is_array($results) || $results instanceof TActiveRecord)
+ if(is_array($results) || $results instanceof ArrayAccess || $results instanceof TActiveRecord)
{
$this->collectForeignObjects($results);
while($obj = array_pop($stack))
@@ -134,8 +132,9 @@ abstract class TActiveRecordRelation */
protected function getIndexValues($keys, $results)
{
- if(!is_array($results))
+ if(!is_array($results) && !$results instanceof ArrayAccess)
$results = array($results);
+ $values=array();
foreach($results as $result)
{
$value = array();
@@ -169,7 +168,7 @@ abstract class TActiveRecordRelation */
protected function setResultCollection(&$results, &$collections, $properties)
{
- if(is_array($results))
+ if(is_array($results) || $results instanceof ArrayAccess)
{
for($i=0,$k=count($results);$i<$k;$i++)
$this->setObjectProperty($results[$i], $properties, $collections);
@@ -191,5 +190,5 @@ abstract class TActiveRecordRelation $source->{$prop} = isset($collections[$hash]) ? $collections[$hash] : array();
}
}
- +
?>
\ No newline at end of file diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php index 033d7638..167c90a5 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php @@ -57,11 +57,14 @@ class TActiveRecordRelationContext if(!isset($statics[self::RELATIONS_CONST]))
throw new TActiveRecordException('ar_relations_undefined',
get_class($this->_sourceRecord), self::RELATIONS_CONST);
- if(isset($statics[self::RELATIONS_CONST][$property]))
- return $statics[self::RELATIONS_CONST][$property];
- else
- throw new TActiveRecordException('ar_undefined_relation_prop',
- $property, get_class($this->_sourceRecord), self::RELATIONS_CONST);
+ $property = strtolower($property);
+ foreach($statics[self::RELATIONS_CONST] as $name => $relation)
+ {
+ if(strtolower($name)===$property)
+ return $relation;
+ }
+ throw new TActiveRecordException('ar_undefined_relation_prop',
+ $property, get_class($this->_sourceRecord), self::RELATIONS_CONST);
}
/**
|