/** * {@inheritdoc} */ public function buildCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, $entity) { $data = $this->uow->getOriginalEntityData($entity); $data = array_merge($data, $metadata->getIdentifierValues($entity)); // why update has no identifier values ? foreach ($metadata->associationMappings as $name => $assoc) { if (!isset($data[$name])) { continue; } if (!($assoc['type'] & ClassMetadata::TO_ONE)) { unset($data[$name]); continue; } if (!isset($assoc['cache'])) { $targetClassMetadata = $this->em->getClassMetadata($assoc['targetEntity']); $owningAssociation = !$assoc['isOwningSide'] ? $targetClassMetadata->associationMappings[$assoc['mappedBy']] : $assoc; $associationIds = $this->identifierFlattener->flattenIdentifier($targetClassMetadata, $targetClassMetadata->getIdentifierValues($data[$name])); unset($data[$name]); foreach ($associationIds as $fieldName => $fieldValue) { if (isset($targetClassMetadata->fieldMappings[$fieldName])) { $fieldMapping = $targetClassMetadata->fieldMappings[$fieldName]; $data[$owningAssociation['targetToSourceKeyColumns'][$fieldMapping['columnName']]] = $fieldValue; continue; } $targetAssoc = $targetClassMetadata->associationMappings[$fieldName]; foreach ($assoc['targetToSourceKeyColumns'] as $referencedColumn => $localColumn) { if (isset($targetAssoc['sourceToTargetKeyColumns'][$referencedColumn])) { $data[$localColumn] = $fieldValue; } } } continue; } if (!isset($assoc['id'])) { $targetClass = ClassUtils::getClass($data[$name]); $targetId = $this->uow->getEntityIdentifier($data[$name]); $data[$name] = new AssociationCacheEntry($targetClass, $targetId); continue; } // handle association identifier $targetId = is_object($data[$name]) && $this->uow->isInIdentityMap($data[$name]) ? $this->uow->getEntityIdentifier($data[$name]) : $data[$name]; // @TODO - fix it ! // handle UnitOfWork#createEntity hash generation if (!is_array($targetId)) { $data[reset($assoc['joinColumnFieldNames'])] = $targetId; $targetEntity = $this->em->getClassMetadata($assoc['targetEntity']); $targetId = [$targetEntity->identifier[0] => $targetId]; } $data[$name] = new AssociationCacheEntry($assoc['targetEntity'], $targetId); } return new EntityCacheEntry($metadata->name, $data); }
/** * @group utilities */ public function testFlattenIdentifierWithMutlipleIds() { $leeds = new City('Leeds'); $london = new City('London'); $this->_em->persist($leeds); $this->_em->persist($london); $this->_em->flush(); $flight = new Flight($leeds, $london); $this->_em->persist($flight); $this->_em->flush(); $class = $this->_em->getClassMetadata('Doctrine\\Tests\\Models\\Cache\\Flight'); $id = $class->getIdentifierValues($flight); $this->assertCount(2, $id); $this->assertArrayHasKey('leavingFrom', $id); $this->assertArrayHasKey('goingTo', $id); $this->assertEquals($leeds, $id['leavingFrom']); $this->assertEquals($london, $id['goingTo']); $flatIds = $this->identifierFlattener->flattenIdentifier($class, $id); $this->assertCount(2, $flatIds); $this->assertArrayHasKey('leavingFrom', $flatIds); $this->assertArrayHasKey('goingTo', $flatIds); $this->assertEquals($id['leavingFrom']->getId(), $flatIds['leavingFrom']); $this->assertEquals($id['goingTo']->getId(), $flatIds['goingTo']); }
/** * Creates a closure capable of finalizing state a cloned proxy * * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata * @param \Doctrine\ORM\Persisters\Entity\EntityPersister $entityPersister * * @return \Closure * * @throws \Doctrine\ORM\EntityNotFoundException */ private function createCloner(ClassMetadata $classMetadata, EntityPersister $entityPersister) { return function (BaseProxy $proxy) use($entityPersister, $classMetadata) { if ($proxy->__isInitialized()) { return; } $proxy->__setInitialized(true); $proxy->__setInitializer(null); $class = $entityPersister->getClassMetadata(); $identifier = $classMetadata->getIdentifierValues($proxy); $original = $entityPersister->loadById($identifier); if (null === $original) { throw EntityNotFoundException::fromClassNameAndIdentifier($classMetadata->getName(), $this->identifierFlattener->flattenIdentifier($classMetadata, $identifier)); } foreach ($class->getReflectionClass()->getProperties() as $property) { if (!$class->hasField($property->name) && !$class->hasAssociation($property->name)) { continue; } $property->setAccessible(true); $property->setValue($proxy, $property->getValue($original)); } }; }
/** * Verifies if two given entities actually are the same based on identifier comparison * * @param object $entity1 * @param object $entity2 * * @return bool */ private function isIdentifierEquals($entity1, $entity2) { if ($entity1 === $entity2) { return true; } $class = $this->em->getClassMetadata(get_class($entity1)); if ($class !== $this->em->getClassMetadata(get_class($entity2))) { return false; } $oid1 = spl_object_hash($entity1); $oid2 = spl_object_hash($entity2); $id1 = isset($this->entityIdentifiers[$oid1]) ? $this->entityIdentifiers[$oid1] : $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($entity1)); $id2 = isset($this->entityIdentifiers[$oid2]) ? $this->entityIdentifiers[$oid2] : $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($entity2)); return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2); }
/** * Fetches the current version value of a versioned entity. * * @param \Doctrine\ORM\Mapping\ClassMetadata $versionedClass * @param array $id * * @return mixed */ protected function fetchVersionValue($versionedClass, array $id) { $versionField = $versionedClass->versionField; $tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform); $identifier = $this->quoteStrategy->getIdentifierColumnNames($versionedClass, $this->platform); $columnName = $this->quoteStrategy->getColumnName($versionField, $versionedClass, $this->platform); // FIXME: Order with composite keys might not be correct $sql = 'SELECT ' . $columnName . ' FROM ' . $tableName . ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?'; $flatId = $this->identifierFlattener->flattenIdentifier($versionedClass, $id); $value = $this->conn->fetchColumn($sql, array_values($flatId)); return Type::getType($versionedClass->fieldMappings[$versionField]['type'])->convertToPHPValue($value, $this->platform); }