| <?php |
| /** |
| * File containing the ezcPersistentIdentityRelationObjectExtractor class. |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * @package PersistentObject |
| * @version //autogen// |
| * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
| */ |
| |
| /** |
| * Extracts related objects from a generated pre-fetch query. |
| * |
| * An instance of this class is used in {@link ezcPersistentIdentityMap} to |
| * extract related persistent objects from a pre-fetch query generated by |
| * {@link ezcPersistentSessionIdentityDecoratorRelationQueryCreator}. |
| * |
| * @package PersistentObject |
| * @version //autogen// |
| * @access private |
| */ |
| class ezcPersistentIdentityRelationObjectExtractor |
| { |
| /** |
| * Definition manager. |
| * |
| * @var ezcPersistentDefinitionManager |
| */ |
| protected $defManager; |
| |
| /** |
| * Identity map. |
| * |
| * @var ezcPersistentIdentityMap |
| */ |
| protected $idMap; |
| |
| /** |
| * Identity session options. |
| * |
| * @var ezcPersistentSessionIdentityDecoratorOptions |
| */ |
| protected $options; |
| |
| /** |
| * Creates a new object extractor for $idMap on basis of $defManager. |
| * |
| * Creates a new object extractor which gathers needed object definitions |
| * from $defManager and uses $idMap to store the extracted objects and to |
| * check if their identities already exist. $options are the options used |
| * by the decorator using this instance. |
| * |
| * @param ezcPersistentIdentityMap $idMap |
| * @param ezcPersistentDefinitionManager $defManager |
| * @param ezcPersistentSessionIdentityDecoratorOptions $options |
| */ |
| public function __construct( ezcPersistentIdentityMap $idMap, ezcPersistentDefinitionManager $defManager, ezcPersistentSessionIdentityDecoratorOptions $options ) |
| { |
| $this->defManager = $defManager; |
| $this->idMap = $idMap; |
| $this->options = $options; |
| } |
| |
| /** |
| * Extracts a single object and its related objects from $stmt. |
| * |
| * Extracts the object of $class with $id from the result set in $stmt and |
| * all of its related objects defined in $relations. The extracted relation |
| * sets can be received from the {@link ezcPersistentIdentityMap} given to |
| * {@link __construct()}, after this method has finished. The method |
| * returns the object of $class with $id. |
| * |
| * @param PDOStatement $stmt |
| * @param string $class |
| * @param mixed $id |
| * @param array(string=>ezcPersistentRelationFindDefinition) $relations |
| * |
| * @return ezcPersistentObject |
| */ |
| public function extractObjectWithRelatedObjects( PDOStatement $stmt, $class, $id, array $relations ) |
| { |
| $results = $stmt->fetchAll( PDO::FETCH_ASSOC ); |
| |
| $def = $this->defManager->fetchDefinition( $class ); |
| |
| $object = $this->idMap->getIdentity( $class, $id ); |
| if ( $this->options->refetch || $object === null ) |
| { |
| $object = new $class(); |
| $this->setObjectState( |
| $object, |
| $def, |
| reset( $results ) |
| ); |
| $this->idMap->setIdentity( $object ); |
| } |
| |
| foreach ( $results as $row ) |
| { |
| $this->extractObjectsRecursive( $row, $relations, $object, array() ); |
| } |
| |
| return $object; |
| } |
| |
| /** |
| * Extracts all objects and their related objects from $stmt. |
| * |
| * Extracts all objects of the $class defined in $q from $stmt, including |
| * all related objects as defined in the $relations property of $q. Returns |
| * the set of base objects found by $q. |
| * |
| * @param PDOStatement $stmt |
| * @param ezcPersistentFindWithRelationsQuery $q |
| * @return array(ezcPersistentObject) |
| */ |
| public function extractObjectsWithRelatedObjects( PDOStatement $stmt, ezcPersistentFindWithRelationsQuery $q ) |
| { |
| $class = $q->className; |
| |
| $results = $stmt->fetchAll( PDO::FETCH_ASSOC ); |
| |
| $def = $this->defManager->fetchDefinition( $class ); |
| |
| $extractedBaseObjects = array(); |
| |
| foreach ( $results as $row ) |
| { |
| $baseObjId = $row[$def->idProperty->propertyName]; |
| |
| if ( !isset( $extractedBaseObjects[$baseObjId] ) ) |
| { |
| $object = new $class(); |
| $this->setObjectState( |
| $object, |
| $def, |
| $row |
| ); |
| $this->idMap->setIdentity( $object ); |
| $extractedBaseObjects[$baseObjId] = $object; |
| } |
| |
| $this->extractObjectsRecursive( |
| $row, |
| $q->relations, |
| $extractedBaseObjects[$baseObjId], |
| $q->isRestricted |
| ); |
| } |
| |
| return $extractedBaseObjects; |
| } |
| |
| /** |
| * Extracts objects recursively from $row. |
| * |
| * Checks if $row contains new objects defined in $relations. If this is |
| * the case, the objects will be extracted and added as related objects of |
| * their class for the object of $parentClass with $parentId. If |
| * sub-sequent relations exist for an extracted object, this method is |
| * called recursively. If $restricted is set to true, named related object |
| * sets will be created instead of normal related object sets. |
| * |
| * @param array(string=>string) $row |
| * @param array(ezcPersistentRelationFindDefinition) $relations |
| * @param ezcPersistentObject $parent |
| * @param bool $restricted |
| */ |
| protected function extractObjectsRecursive( array $row, array $relations, $parent, $restricted = false ) |
| { |
| foreach ( $relations as $tableAlias => $relation ) |
| { |
| $id = $row[ |
| $this->getColumnAlias( |
| $relation->definition->idProperty->propertyName, |
| $tableAlias |
| ) |
| ]; |
| |
| if ( $id === null ) |
| { |
| // Related object not present, check if a relation is recorded |
| // in general, to potentially add an empty set |
| if ( $restricted ) |
| { |
| $relatedObjects = $this->idMap->getRelatedObjectSet( |
| $parent, |
| $tableAlias |
| ); |
| if ( $relatedObjects === null ) |
| { |
| $this->idMap->setRelatedObjectSet( |
| $parent, |
| array(), |
| $tableAlias |
| ); |
| } |
| } |
| else |
| { |
| $relatedObjects = $this->idMap->getRelatedObjects( |
| $parent, |
| $relation->relatedClass, |
| $relation->relationName |
| ); |
| if ( $relatedObjects === null ) |
| { |
| $this->idMap->setRelatedObjects( |
| $parent, |
| array(), |
| $relation->relatedClass, |
| $relation->relationName |
| ); |
| } |
| } |
| // Skip further processing since this related object did not exist |
| continue; |
| } |
| |
| // Check if object was already extracted |
| $object = $this->idMap->getIdentity( $relation->relatedClass, $id ); |
| if ( $this->options->refetch || $object === null ) |
| { |
| $object = $this->createObject( |
| $row, |
| $tableAlias, |
| $relation |
| ); |
| $this->idMap->setIdentity( $object ); |
| } |
| |
| // Check if relations from $parentClass to $relation->relatedClass |
| // were already recorded |
| if ( $restricted ) |
| { |
| $relatedObjects = $this->idMap->getRelatedObjectSet( |
| $parent, |
| $tableAlias |
| ); |
| } |
| else |
| { |
| $relatedObjects = $this->idMap->getRelatedObjects( |
| $parent, |
| $relation->relatedClass, |
| $relation->relationName |
| ); |
| } |
| if ( $relatedObjects === null ) |
| { |
| // No relation set recorded, create |
| $relatedObjects = array(); |
| } |
| |
| // Check if relation itself is already recorded and only set the |
| // identities if not |
| if ( $this->options->refetch || !isset( $relatedObjects[$id] ) ) |
| { |
| $relatedObjects[$id] = $object; |
| // This performs the full setting process on every new object, |
| // which is somewhat expensive but not really possible in a |
| // different way, since adding new related objects invalidates |
| // named related sets. |
| if ( $restricted ) |
| { |
| $this->idMap->setRelatedObjectSet( |
| $parent, |
| $relatedObjects, |
| $tableAlias |
| ); |
| } |
| else |
| { |
| $this->idMap->setRelatedObjects( |
| $parent, |
| $relatedObjects, |
| $relation->relatedClass, |
| $relation->relationName |
| ); |
| } |
| } |
| |
| // Recurse |
| $this->extractObjectsRecursive( |
| $row, |
| $relation->furtherRelations, |
| $object, |
| $restricted |
| ); |
| } |
| } |
| |
| /** |
| * Creates a new object of $relation->relatedClass with state from $result. |
| * |
| * Creates a new object of the class defined in $relation->relatedClass and |
| * sets its state from the given $result row, as defined in $relation. |
| * $tableAlias is the alias used for the specific relation in the query. |
| * |
| * @param array(string=>string) $result |
| * @param string $tableAlias |
| * @param ezcPersistentRelationFindDefinition $relation |
| * @return ezcPersistentObject |
| */ |
| protected function createObject( array $result, $tableAlias, ezcPersistentRelationFindDefinition $relation ) |
| { |
| $object = new $relation->relatedClass; |
| $this->setObjectState( |
| $object, |
| $relation->definition, |
| $result, |
| $tableAlias |
| ); |
| return $object; |
| } |
| |
| /** |
| * Sets the state of $object from $result. |
| * |
| * Sets the state of $object from the $result given, using the $def. |
| * |
| * @param ezcPersistentObject $object |
| * @param ezcPersistentObjectDefinition $def |
| * @param array $result |
| * @param string $prefix |
| */ |
| protected function setObjectState( $object, ezcPersistentObjectDefinition $def, array $result, $prefix = null ) |
| { |
| $state = array( |
| $def->idProperty->propertyName => $result[ |
| $this->getColumnAlias( |
| $def->idProperty->propertyName, |
| $prefix |
| ) |
| ] |
| ); |
| |
| foreach ( $def->properties as $property ) |
| { |
| $state[$property->propertyName] = $result[ |
| $this->getColumnAlias( $property->propertyName, $prefix ) |
| ]; |
| } |
| |
| $object->setState( $state ); |
| } |
| |
| /** |
| * Returns the column alias for a $column with $prefix. |
| * |
| * @param string $column |
| * @param string $prefix |
| * @return string |
| */ |
| protected function getColumnAlias( $column, $prefix = null ) |
| { |
| if ( $prefix === null ) |
| { |
| return $column; |
| } |
| return sprintf( |
| '%s_%s', |
| $prefix, |
| $column |
| ); |
| } |
| } |
| |
| ?> |