Beispiel #1
0
 /**
  * Computes the changes of an association.
  *
  * @param AssociationMapping $assoc
  * @param mixed $value The value of the association.
  */
 private function _computeAssociationChanges($assoc, $value)
 {
     if ($value instanceof PersistentCollection && $value->isDirty()) {
         if ($assoc->isOwningSide) {
             $this->_collectionUpdates[] = $value;
         }
         $this->_visitedCollections[] = $value;
     }
     if (!$assoc->isCascadeSave) {
         //echo "NOT CASCADING INTO " . $assoc->getSourceFieldName() . PHP_EOL;
         return;
         // "Persistence by reachability" only if save cascade specified
     }
     // Look through the entities, and in any of their associations, for transient
     // enities, recursively. ("Persistence by reachability")
     if ($assoc->isOneToOne()) {
         $value = array($value);
     }
     $targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
     foreach ($value as $entry) {
         $state = $this->getEntityState($entry);
         $oid = spl_object_hash($entry);
         if ($state == self::STATE_NEW) {
             // Get identifier, if possible (not post-insert)
             $idGen = $targetClass->getIdGenerator();
             if (!$idGen->isPostInsertGenerator()) {
                 $idValue = $idGen->generate($this->_em, $entry);
                 $this->_entityStates[$oid] = self::STATE_MANAGED;
                 if (!$idGen instanceof \Doctrine\ORM\Id\Assigned) {
                     $this->_entityIdentifiers[$oid] = array($idValue);
                     $targetClass->getSingleIdReflectionProperty()->setValue($entry, $idValue);
                 } else {
                     $this->_entityIdentifiers[$oid] = $idValue;
                 }
                 $this->addToIdentityMap($entry);
             }
             // Collect the original data and changeset, recursing into associations.
             $data = array();
             $changeSet = array();
             foreach ($targetClass->reflFields as $name => $refProp) {
                 $data[$name] = $refProp->getValue($entry);
                 $changeSet[$name] = array(null, $data[$name]);
                 if (isset($targetClass->associationMappings[$name])) {
                     //echo "RECURSING INTO $name" . PHP_EOL;
                     //TODO: Prevent infinite recursion
                     $this->_computeAssociationChanges($targetClass->associationMappings[$name], $data[$name]);
                 }
             }
             // NEW entities are INSERTed within the current unit of work.
             $this->_entityInsertions[$oid] = $entry;
             $this->_entityChangeSets[$oid] = $changeSet;
             $this->_originalEntityData[$oid] = $data;
         } else {
             if ($state == self::STATE_DELETED) {
                 throw DoctrineException::updateMe("Deleted entity in collection detected during flush." . " Make sure you properly remove deleted entities from collections.");
             }
         }
         // MANAGED associated entities are already taken into account
         // during changeset calculation anyway, since they are in the identity map.
     }
 }
Beispiel #2
0
 /**
  * Computes the changes of an association.
  *
  * @param AssociationMapping $assoc
  * @param mixed $value The value of the association.
  */
 private function computeAssociationChanges($assoc, $value)
 {
     if ($value instanceof PersistentCollection && $value->isDirty()) {
         if ($assoc->isOwningSide) {
             $this->collectionUpdates[] = $value;
         }
         $this->visitedCollections[] = $value;
     }
     // Look through the entities, and in any of their associations, for transient (new)
     // enities, recursively. ("Persistence by reachability")
     if ($assoc->isOneToOne()) {
         if ($value instanceof Proxy && !$value->__isInitialized__) {
             return;
             // Ignore uninitialized proxy objects
         }
         $value = array($value);
     } else {
         if ($value instanceof PersistentCollection) {
             // Unwrap. Uninitialized collections will simply be empty.
             $value = $value->unwrap();
         }
     }
     $targetClass = $this->em->getClassMetadata($assoc->targetEntityName);
     foreach ($value as $entry) {
         $state = $this->getEntityState($entry, self::STATE_NEW);
         $oid = spl_object_hash($entry);
         if ($state == self::STATE_NEW) {
             if (!$assoc->isCascadePersist) {
                 throw new InvalidArgumentException("A new entity was found through a relationship that was not" . " configured to cascade persist operations: " . self::objToStr($entry) . "." . " Explicitly persist the new entity or configure cascading persist operations" . " on the relationship.");
             }
             $this->persistNew($targetClass, $entry);
             $this->computeChangeSet($targetClass, $entry);
         } else {
             if ($state == self::STATE_REMOVED) {
                 return new InvalidArgumentException("Removed entity detected during flush: " . self::objToStr($removedEntity) . ". Remove deleted entities from associations.");
             } else {
                 if ($state == self::STATE_DETACHED) {
                     // Can actually not happen right now as we assume STATE_NEW,
                     // so the exception will be raised from the DBAL layer (constraint violation).
                     throw new InvalidArgumentException("A detached entity was found through a " . "relationship during cascading a persist operation.");
                 }
             }
         }
         // MANAGED associated entities are already taken into account
         // during changeset calculation anyway, since they are in the identity map.
     }
 }
 /**
  * Computes the changes of an association.
  *
  * @param AssociationMapping $assoc
  * @param mixed $value The value of the association.
  */
 private function _computeAssociationChanges($assoc, $value)
 {
     if ($value instanceof PersistentCollection && $value->isDirty()) {
         if ($assoc->isOwningSide) {
             $this->_collectionUpdates[] = $value;
         }
         $this->_visitedCollections[] = $value;
     }
     if (!$assoc->isCascadePersist) {
         return;
         // "Persistence by reachability" only if persist cascade specified
     }
     // Look through the entities, and in any of their associations, for transient
     // enities, recursively. ("Persistence by reachability")
     if ($assoc->isOneToOne()) {
         if ($value instanceof Proxy && !$value->__isInitialized__) {
             return;
             // Ignore uninitialized proxy objects
         }
         $value = array($value);
     } else {
         if ($value instanceof PersistentCollection) {
             $value = $value->unwrap();
         }
     }
     $targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
     foreach ($value as $entry) {
         $state = $this->getEntityState($entry, self::STATE_NEW);
         $oid = spl_object_hash($entry);
         if ($state == self::STATE_NEW) {
             if (isset($targetClass->lifecycleCallbacks[Events::prePersist])) {
                 $targetClass->invokeLifecycleCallbacks(Events::prePersist, $entry);
             }
             if ($this->_evm->hasListeners(Events::prePersist)) {
                 $this->_evm->dispatchEvent(Events::prePersist, new LifecycleEventArgs($entry, $this->_em));
             }
             // Get identifier, if possible (not post-insert)
             $idGen = $targetClass->idGenerator;
             if (!$idGen->isPostInsertGenerator()) {
                 $idValue = $idGen->generate($this->_em, $entry);
                 if (!$idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) {
                     $this->_entityIdentifiers[$oid] = array($targetClass->identifier[0] => $idValue);
                     $targetClass->getSingleIdReflectionProperty()->setValue($entry, $idValue);
                 } else {
                     $this->_entityIdentifiers[$oid] = $idValue;
                 }
                 $this->addToIdentityMap($entry);
             }
             $this->_entityStates[$oid] = self::STATE_MANAGED;
             // NEW entities are INSERTed within the current unit of work.
             $this->_entityInsertions[$oid] = $entry;
             $this->computeChangeSet($targetClass, $entry);
         } else {
             if ($state == self::STATE_REMOVED) {
                 throw ORMException::removedEntityInCollectionDetected($entity, $assoc);
             }
         }
         // MANAGED associated entities are already taken into account
         // during changeset calculation anyway, since they are in the identity map.
     }
 }
 /**
  * Gets the SELECT SQL to select one or more entities by a set of field criteria.
  *
  * @param array $criteria
  * @param AssociationMapping $assoc
  * @param string $orderBy
  * @return string
  * @override
  */
 protected function _getSelectEntitiesSQL(array &$criteria, $assoc = null, $orderBy = null)
 {
     $idColumns = $this->_class->getIdentifierColumnNames();
     $baseTableAlias = $this->_getSQLTableAlias($this->_class);
     if ($this->_selectColumnListSql === null) {
         // Add regular columns
         $columnList = '';
         foreach ($this->_class->fieldMappings as $fieldName => $mapping) {
             if ($columnList != '') {
                 $columnList .= ', ';
             }
             $columnList .= $this->_getSelectColumnSQL($fieldName, isset($mapping['inherited']) ? $this->_em->getClassMetadata($mapping['inherited']) : $this->_class);
         }
         // Add foreign key columns
         foreach ($this->_class->associationMappings as $assoc) {
             if ($assoc->isOwningSide && $assoc->isOneToOne()) {
                 $tableAlias = isset($this->_class->inheritedAssociationFields[$assoc->sourceFieldName]) ? $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->inheritedAssociationFields[$assoc->sourceFieldName])) : $baseTableAlias;
                 foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
                     $columnAlias = $srcColumn . $this->_sqlAliasCounter++;
                     $columnList .= ", {$tableAlias}.{$srcColumn} AS {$columnAlias}";
                     $resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
                     if (!isset($this->_resultColumnNames[$resultColumnName])) {
                         $this->_resultColumnNames[$resultColumnName] = $srcColumn;
                     }
                 }
             }
         }
         // Add discriminator column (DO NOT ALIAS THIS COLUMN).
         $discrColumn = $this->_class->discriminatorColumn['name'];
         if ($this->_class->rootEntityName == $this->_class->name) {
             $columnList .= ", {$baseTableAlias}.{$discrColumn}";
         } else {
             $columnList .= ', ' . $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->rootEntityName)) . ".{$discrColumn}";
         }
         $resultColumnName = $this->_platform->getSQLResultCasing($discrColumn);
         $this->_resultColumnNames[$resultColumnName] = $discrColumn;
     }
     // INNER JOIN parent tables
     $joinSql = '';
     foreach ($this->_class->parentClasses as $parentClassName) {
         $parentClass = $this->_em->getClassMetadata($parentClassName);
         $tableAlias = $this->_getSQLTableAlias($parentClass);
         $joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
         $first = true;
         foreach ($idColumns as $idColumn) {
             if ($first) {
                 $first = false;
             } else {
                 $joinSql .= ' AND ';
             }
             $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
         }
     }
     // OUTER JOIN sub tables
     foreach ($this->_class->subClasses as $subClassName) {
         $subClass = $this->_em->getClassMetadata($subClassName);
         $tableAlias = $this->_getSQLTableAlias($subClass);
         if ($this->_selectColumnListSql === null) {
             // Add subclass columns
             foreach ($subClass->fieldMappings as $fieldName => $mapping) {
                 if (isset($mapping['inherited'])) {
                     continue;
                 }
                 $columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass);
             }
             // Add join columns (foreign keys)
             foreach ($subClass->associationMappings as $assoc2) {
                 if ($assoc2->isOwningSide && $assoc2->isOneToOne() && !isset($subClass->inheritedAssociationFields[$assoc2->sourceFieldName])) {
                     foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
                         $columnAlias = $srcColumn . $this->_sqlAliasCounter++;
                         $columnList .= ', ' . $tableAlias . ".{$srcColumn} AS {$columnAlias}";
                         $resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
                         if (!isset($this->_resultColumnNames[$resultColumnName])) {
                             $this->_resultColumnNames[$resultColumnName] = $srcColumn;
                         }
                     }
                 }
             }
         }
         // Add LEFT JOIN
         $joinSql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
         $first = true;
         foreach ($idColumns as $idColumn) {
             if ($first) {
                 $first = false;
             } else {
                 $joinSql .= ' AND ';
             }
             $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
         }
     }
     $conditionSql = '';
     foreach ($criteria as $field => $value) {
         if ($conditionSql != '') {
             $conditionSql .= ' AND ';
         }
         if (isset($this->_class->fieldMappings[$field]['inherited'])) {
             $conditionSql .= $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->fieldMappings[$field]['inherited'])) . '.';
         } else {
             $conditionSql .= $baseTableAlias . '.';
         }
         if (isset($this->_class->columnNames[$field])) {
             $conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
         } else {
             if ($assoc !== null) {
                 $conditionSql .= $field;
             } else {
                 throw ORMException::unrecognizedField($field);
             }
         }
         $conditionSql .= ' = ?';
     }
     $orderBySql = '';
     if ($orderBy !== null) {
         $orderBySql = $this->_getCollectionOrderBySQL($orderBy, $baseTableAlias);
     }
     if ($this->_selectColumnListSql === null) {
         $this->_selectColumnListSql = $columnList;
     }
     return 'SELECT ' . $this->_selectColumnListSql . ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $baseTableAlias . $joinSql . ($conditionSql != '' ? ' WHERE ' . $conditionSql : '') . $orderBySql;
 }