/**
* 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;
}