summaryrefslogtreecommitdiff
path: root/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php
diff options
context:
space:
mode:
authorwei <>2007-04-24 06:14:56 +0000
committerwei <>2007-04-24 06:14:56 +0000
commitd5eb713888715e8f18d2ccf508a8eb0b1a483ad1 (patch)
tree3752f12f0a9379681e13171df805e8f5760c53ec /framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php
parent1c74ee3c07cd2b25670826d44f7a1b1959302ce3 (diff)
add active record Relations
Diffstat (limited to 'framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php')
-rw-r--r--framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php172
1 files changed, 172 insertions, 0 deletions
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php
new file mode 100644
index 00000000..f1e8fa60
--- /dev/null
+++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php
@@ -0,0 +1,172 @@
+<?php
+Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelationContext');
+
+abstract class TActiveRecordRelation
+{
+ private $_context;
+
+ public function __construct(TActiveRecordRelationContext $context)
+ {
+ $this->_context = $context;
+ }
+
+ /**
+ * @return TActiveRecordRelationContext
+ */
+ protected function getContext()
+ {
+ return $this->_context;
+ }
+
+ /**
+ * @return TActiveRecord
+ */
+ protected function getSourceRecord()
+ {
+ return $this->getContext()->getSourceRecord();
+ }
+
+ /**
+ * 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.
+ *
+ * Allows chaining multiple relation handlers.
+ *
+ * @param string method name called
+ * @param array method arguments
+ * @return mixed TActiveRecord or array of TActiveRecord results depending on the method called.
+ */
+ public function __call($method,$args)
+ {
+ static $stack=array();
+
+ $results = call_user_func_array(array($this->getSourceRecord(),$method),$args);
+ if(is_array($results) || $results instanceof TActiveRecord)
+ {
+ $this->collectForeignObjects($results);
+ while($obj = array_pop($stack))
+ $obj->collectForeignObjects($results);
+ }
+ else if($results instanceof TActiveRecordRelation)
+ array_push($stack,$this); //call it later
+ return $results;
+ }
+
+ /**
+ * Returns foreign keys in $fromRecord with source column names as key
+ * and foreign column names in the corresponding $matchesRecord as value.
+ * The method returns the first matching foreign key between these 2 records.
+ * @param TActiveRecord $fromRecord
+ * @param TActiveRecord $matchesRecord
+ * @return array foreign keys with source column names as key and foreign column names as value.
+ */
+ protected function findForeignKeys($from, $matchesRecord)
+ {
+ $gateway = $matchesRecord->getRecordGateway();
+ $matchingTableName = $gateway->getRecordTableInfo($matchesRecord)->getTableName();
+ $tableInfo=$from;
+ if($from instanceof TActiveRecord)
+ $tableInfo = $gateway->getRecordTableInfo($from);
+ foreach($tableInfo->getForeignKeys() as $fkeys)
+ {
+ if($fkeys['table']===$matchingTableName)
+ return $fkeys['keys'];
+ }
+ throw new TActiveRecordException('no fk defined for '.$tableInfo->getTableFullName());
+ }
+
+ /**
+ * @param mixed object or array to be hashed
+ * @param array name of property for hashing the properties.
+ * @return string object hash using crc32 and serialize.
+ */
+ protected function getObjectHash($obj, $properties)
+ {
+ $ids=array();
+ foreach($properties as $property)
+ $ids[] = is_object($obj) ? $obj->{$property} : $obj[$property];
+ return sprintf('%x',crc32(serialize($ids)));
+ }
+
+ /**
+ * Fetches the foreign objects using TActiveRecord::findAllByIndex()
+ * @param array field names
+ * @param array foreign key index values.
+ * @return TActiveRecord[] foreign objects.
+ */
+ protected function findForeignObjects($fields, $indexValues)
+ {
+ $criteria = $this->getContext()->getCriteria();
+ $finder = $this->getContext()->getForeignRecordFinder();
+ return $finder->findAllByIndex($criteria, $fields, $indexValues);
+ }
+
+ /**
+ * Obtain the foreign key index values from the results.
+ * @param array property names
+ * @param array|TActiveRecord TActiveRecord results
+ * @return array foreign key index values.
+ */
+ protected function getIndexValues($keys, $results)
+ {
+ if(!is_array($results))
+ $results = array($results);
+ foreach($results as $result)
+ {
+ $value = array();
+ foreach($keys as $name)
+ $value[] = $result->{$name};
+ $values[] = $value;
+ }
+ return $values;
+ }
+
+ /**
+ * Populate the results with the foreign objects found.
+ * @param array source results
+ * @param array source property names
+ * @param array foreign objects
+ * @param array foreign object field names.
+ */
+ protected function populateResult(&$results,$properties,&$fkObjects,$fields)
+ {
+ $collections=array();
+ foreach($fkObjects as $fkObject)
+ {
+ $hash = $this->getObjectHash($fkObject, $fields);
+ $collections[$hash][]=$fkObject;
+ }
+
+ $this->setResultCollection($results, $collections, $properties);
+ }
+
+ protected function setResultCollection(&$results, &$collections, $properties)
+ {
+ if(is_array($results))
+ {
+ for($i=0,$k=count($results);$i<$k;$i++)
+ $this->setObjectProperty($results[$i], $properties, $collections);
+ }
+ else
+ {
+ $this->setObjectProperty($results, $properties, $collections);
+ }
+ }
+
+ /**
+ * Sets the foreign objects to the given property on the source object.
+ * @param TActiveRecord source object.
+ * @param array source properties
+ * @param array foreign objects.
+ */
+ protected function setObjectProperty($source, $properties, &$collections)
+ {
+ $hash = $this->getObjectHash($source, $properties);
+ $prop = $this->getContext()->getProperty();
+ $source->{$prop} = isset($collections[$hash]) ? $collections[$hash] : array();
+ }
+}
+
+?> \ No newline at end of file