/** * @inheritdoc */ function hydrate($document, $data, array $hints = []) { $hydratedData = []; foreach ($this->metadata->fieldMappings as $fieldName => $mapping) { $name = $mapping['name']; $propertyValue = isset($data[$name]) ? $data[$name] : null; if (!isset($mapping['association'])) { if ($propertyValue === null) { continue; } $type = Type::getType($mapping['type']); $value = $type->convertToPHPValue($propertyValue); $this->metadata->reflFields[$fieldName]->setValue($document, $value); $hydratedData[$fieldName] = $value; continue; } if ($mapping['association'] & ClassMetadata::TO_MANY) { $coll = new PersistentCollection(new ArrayCollection(), $this->dm, $this->uow); $coll->setOwner($document, $mapping); $coll->setInitialized(false); if ($propertyValue) { $coll->setData($propertyValue); } $this->metadata->reflFields[$fieldName]->setValue($document, $coll); $hydratedData[$fieldName] = $coll; continue; } if ($propertyValue === null) { continue; } if ($mapping['association'] === ClassMetadata::LINK) { if (is_string($propertyValue)) { $link = $this->dm->getReference($propertyValue); } else { $link = $this->uow->getOrCreateDocument($propertyValue); } $this->metadata->reflFields[$fieldName]->setValue($document, $link); $hydratedData[$fieldName] = $link; continue; } if ($mapping['association'] === ClassMetadata::EMBED) { // an embed one must have @class, we would support generic JSON properties via another mapping type if (!isset($propertyValue[self::ORIENT_PROPERTY_CLASS])) { throw new HydratorException(sprintf("missing @class for embedded property '%s'", $name)); } $oclass = $propertyValue[self::ORIENT_PROPERTY_CLASS]; $embeddedMetadata = $this->dm->getMetadataFactory()->getMetadataForOClass($oclass); $doc = $embeddedMetadata->newInstance(); $embeddedData = $this->dm->getHydratorFactory()->hydrate($doc, $propertyValue, $hints); $this->uow->registerManaged($doc, null, $embeddedData); $this->metadata->reflFields[$fieldName]->setValue($document, $doc); $hydratedData[$fieldName] = $doc; continue; } } return $hydratedData; }
/** * OProperty constructor. * * @param OClass $class * @param array $meta * */ public function __construct(OClass $class, array $meta) { parent::__construct($meta['name'], $class); $this->_meta = $meta; $this->_type = Type::getType(strtolower($meta['type'])); }
private function getDocReference($ref) { $oid = spl_object_hash($ref); if (isset($this->references[$oid])) { return $this->references[$oid]; } /** @var ClassMetadata $rmd */ $rmd = $this->metadataFactory->getMetadataFor(get_class($ref)); $rid = $rmd->getIdentifierValue($ref); if ($rid === null) { throw new ODMOrientDbException('missing reference'); } static $rid_type; if (!isset($rid_type)) { $rid_type = Type::getType('rid'); } return $rid_type->convertToDatabaseValue($rid); }
private function computeOrRecomputeChangeSet(ClassMetadata $class, $document, $recompute = false) { $oid = spl_object_hash($document); $actualData = $this->getDocumentActualData($document); $isNewDocument = !isset($this->originalDocumentData[$oid]); if ($isNewDocument) { // Document is either NEW or MANAGED but not yet fully persisted (only has an id). // These result in an INSERT. $this->originalDocumentData[$oid] = $actualData; $changeSet = []; foreach ($actualData as $propName => $actualValue) { $changeSet[$propName] = [null, $actualValue]; } $this->documentChangeSets[$oid] = $changeSet; } else { // Document is "fully" MANAGED: it was already fully persisted before // and we have a copy of the original data $originalData = $this->originalDocumentData[$oid]; $changeSet = []; foreach ($actualData as $propName => $actualValue) { $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null; // skip if value has not changed if ($orgValue === $actualValue) { continue; } // if relationship is a embed-one, schedule orphan removal to trigger cascade remove operations $field =& $class->fieldMappings[$propName]; if (isset($field['embedded']) && $field['association'] === ClassMetadata::EMBED) { if ($orgValue !== null) { $this->scheduleOrphanRemoval($orgValue); } $changeSet[$propName] = [$orgValue, $actualValue]; continue; } // if owning side of reference-one relationship if (isset($field['reference'])) { if ($field['association'] === ClassMetadata::LINK && $field['isOwningSide']) { if ($orgValue !== null && $field['orphanRemoval']) { $this->scheduleOrphanRemoval($orgValue); } $changeSet[$propName] = [$orgValue, $actualValue]; continue; } // ignore inverse side of reference-many relationship if ($field['association'] & ClassMetadata::TO_MANY && !$field['isOwningSide']) { continue; } } // Persistent collection was exchanged with the "originally" // created one. This can only mean it was cloned and replaced // on another document. if ($actualValue instanceof PersistentCollection) { $owner = $actualValue->getOwner(); if ($owner === null) { // cloned $actualValue->setOwner($document, $field); } elseif ($owner !== $document) { // no clone, we have to fix if (!$actualValue->isInitialized()) { $actualValue->initialize(); // we have to do this otherwise the cols share state } $newValue = clone $actualValue; $newValue->setOwner($document, $field); $class->reflFields[$propName]->setValue($document, $newValue); } } // if embed-many or reference-many relationship if (isset($field['association']) && $field['association'] & ClassMetadata::TO_MANY) { $changeSet[$propName] = [$orgValue, $actualValue]; if ($orgValue instanceof PersistentCollection) { $this->collectionDeletions[] = $orgValue; } continue; } // skip equivalent date values if (isset($field['type']) && $field['type'] === 'date') { $dateType = Type::getType('date'); if ($dateType->equalsPHP($orgValue, $actualValue)) { continue; } } // regular field $changeSet[$propName] = [$orgValue, $actualValue]; } if ($changeSet) { $this->documentChangeSets[$oid] = $recompute && isset($this->documentChangeSets[$oid]) ? $changeSet + $this->documentChangeSets[$oid] : $changeSet; $this->originalDocumentData[$oid] = $actualData; $this->documentUpdates[$oid] = $document; } } // Look for changes in associations of the document foreach ($class->associationMappings as $fieldName => $mapping) { $value = $class->reflFields[$fieldName]->getValue($document); if ($value !== null) { $this->computeAssociationChanges($document, $mapping, $value); if (isset($mapping['reference'])) { continue; } // embedded documents must set the state of their parent $values = $value; if ($mapping['association'] & ClassMetadata::TO_ONE) { $values = [$values]; } elseif ($values instanceof PersistentCollection) { if ($values->isDirty()) { $this->documentChangeSets[$oid][$mapping['fieldName']] = [$value, $value]; if (!$isNewDocument) { $this->documentUpdates[$oid] = $document; } continue; } $values = $values->unwrap(); } foreach ($values as $obj) { $oid2 = spl_object_hash($obj); if (isset($this->documentChangeSets[$oid2])) { $this->documentChangeSets[$oid][$mapping['fieldName']] = [$value, $value]; if (!$isNewDocument) { $this->documentUpdates[$oid] = $document; } break; } } } } }