/** * Create a document given class, data and the doc-id and revision * * @param string $documentName * @param array $data * @param array $hints * * @return object * @throws \InvalidArgumentException * @throws InvalidDocumentTypeException */ public function createDocument($documentName, $data, array &$hints = array()) { $data = $this->migrations->migrate($data); if (!$this->metadataResolver->canMapDocument($data)) { throw new \InvalidArgumentException("Missing or mismatching metadata description in the Document, cannot hydrate!"); } $type = $this->metadataResolver->getDocumentType($data); $class = $this->dm->getClassMetadata($type); $documentState = array(); $nonMappedData = array(); $embeddedDocumentState = array(); $id = $data['_id']; $rev = $data['_rev']; $conflict = false; foreach ($data as $jsonName => $jsonValue) { if (isset($class->jsonNames[$jsonName])) { $fieldName = $class->jsonNames[$jsonName]; if (isset($class->fieldMappings[$fieldName])) { if ($jsonValue === null) { $documentState[$class->fieldMappings[$fieldName]['fieldName']] = null; } else { if (isset($class->fieldMappings[$fieldName]['embedded'])) { $embeddedInstance = $this->embeddedSerializer->createEmbeddedDocument($jsonValue, $class->fieldMappings[$fieldName]); $documentState[$jsonName] = $embeddedInstance; // storing the jsonValue for embedded docs for now $embeddedDocumentState[$jsonName] = $jsonValue; } else { $documentState[$class->fieldMappings[$fieldName]['fieldName']] = Type::getType($class->fieldMappings[$fieldName]['type'])->convertToPHPValue($jsonValue); } } } } else { if ($jsonName == '_rev' || $jsonName == "type") { continue; } else { if ($jsonName == '_conflicts') { $conflict = true; } else { if ($class->hasAttachments && $jsonName == '_attachments') { $documentState[$class->attachmentField] = $this->createDocumentAttachments($id, $jsonValue); } else { if ($this->metadataResolver->canResolveJsonField($jsonName)) { $documentState = $this->metadataResolver->resolveJsonField($class, $this->dm, $documentState, $jsonName, $data); } else { $nonMappedData[$jsonName] = $jsonValue; } } } } } } if ($conflict && $this->evm->hasListeners(Event::onConflict)) { // there is a conflict and we have an event handler that might resolve it $this->evm->dispatchEvent(Event::onConflict, new Event\ConflictEventArgs($data, $this->dm, $type)); // the event might be resolved in the couch now, load it again: return $this->dm->find($type, $id); } // initialize inverse side collections foreach ($class->associationsMappings as $assocName => $assocOptions) { if (!$assocOptions['isOwning'] && $assocOptions['type'] & ClassMetadata::TO_MANY) { $documentState[$class->associationsMappings[$assocName]['fieldName']] = new PersistentViewCollection(new \Doctrine\Common\Collections\ArrayCollection(), $this->dm, $id, $class->associationsMappings[$assocName]); } } if (isset($this->identityMap[$id])) { $document = $this->identityMap[$id]; $overrideLocalValues = false; $this->assertValidDocumentType($documentName, $document, $type); if ($document instanceof Proxy && !$document->__isInitialized__ || isset($hints['refresh'])) { $overrideLocalValues = true; $oid = spl_object_hash($document); $this->documentRevisions[$oid] = $rev; } } else { $document = $class->newInstance(); $this->assertValidDocumentType($documentName, $document, $type); $this->identityMap[$id] = $document; $oid = spl_object_hash($document); $this->documentState[$oid] = self::STATE_MANAGED; $this->documentIdentifiers[$oid] = (string) $id; $this->documentRevisions[$oid] = $rev; $overrideLocalValues = true; } if ($overrideLocalValues) { $this->nonMappedData[$oid] = $nonMappedData; foreach ($class->reflFields as $prop => $reflFields) { $value = isset($documentState[$prop]) ? $documentState[$prop] : null; if (isset($embeddedDocumentState[$prop])) { $this->originalEmbeddedData[$oid][$prop] = $embeddedDocumentState[$prop]; } else { $this->originalData[$oid][$prop] = $value; } $reflFields->setValue($document, $value); } } if ($this->evm->hasListeners(Event::postLoad)) { $this->evm->dispatchEvent(Event::postLoad, new Event\LifecycleEventArgs($document, $this->dm)); } return $document; }