From d5eb713888715e8f18d2ccf508a8eb0b1a483ad1 Mon Sep 17 00:00:00 2001 From: wei <> Date: Tue, 24 Apr 2007 06:14:56 +0000 Subject: add active record Relations --- .../Relations/TActiveRecordRelation.php | 172 +++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php (limited to 'framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php') 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 @@ +_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 -- cgit v1.2.3