/** * Gets the class metadata descriptor for a class. * * @param string $className The name of the class. * @return Doctrine\ODM\CouchDB\Mapping\ClassMetadata */ public function getMetadataFor($className) { if (!isset($this->loadedMetadata[$className])) { $realClassName = $className; // Check for namespace alias if (strpos($className, ':') !== false) { list($namespaceAlias, $simpleClassName) = explode(':', $className); $realClassName = $this->dm->getConfiguration()->getDocumentNamespace($namespaceAlias) . '\\' . $simpleClassName; if (isset($this->loadedMetadata[$realClassName])) { // We do not have the alias name in the map, include it $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName]; return $this->loadedMetadata[$realClassName]; } } if ($this->cacheDriver) { if (($cached = $this->cacheDriver->fetch("{$realClassName}\$COUCHDBCLASSMETADATA")) !== false) { $this->loadedMetadata[$realClassName] = $cached; } else { foreach ($this->loadMetadata($realClassName) as $loadedClassName) { $this->cacheDriver->save("{$loadedClassName}\$COUCHDBCLASSMETADATA", $this->loadedMetadata[$loadedClassName], null); } } } else { $this->loadMetadata($realClassName); } if ($className != $realClassName) { // We do not have the alias name in the map, include it $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName]; } } if (!isset($this->loadedMetadata[$className])) { throw MappingException::classNotMapped(); } return $this->loadedMetadata[$className]; }
public function generate($document, ClassMetadata $cm, DocumentManager $dm) { if (empty($this->uuids)) { $UUIDGenerationBufferSize = $dm->getConfiguration()->getUUIDGenerationBufferSize(); $this->uuids = $dm->getCouchDBClient()->getUuids($UUIDGenerationBufferSize); } $id = array_pop($this->uuids); $cm->reflFields[$cm->identifier]->setValue($document, $id); return $id; }
/** * @return array */ public function createOrUpdateDesignDocuments() { $result = array('success' => array(), 'error' => array()); $designDocumentNames = $this->documentManager->getConfiguration()->getDesignDocumentNames(); foreach ($designDocumentNames as $docName) { $designDocData = $this->documentManager->getConfiguration()->getDesignDocument($docName); $localDesignDoc = new $designDocData['className']($designDocData['options']); $localDocBody = $localDesignDoc->getData(); $remoteDocBody = $this->documentManager->getCouchDBClient()->findDocument('_design/' . $docName)->body; if ($this->isMissingOrDifferent($localDocBody, $remoteDocBody)) { $response = $this->documentManager->getCouchDBClient()->createDesignDocument($docName, $localDesignDoc); if ($response->status < 300) { $result['success'][] = $docName; } else { $result['error'][$docName] = $response->body['reason']; } } } return $result; }
/** * Flush Operation - Write all dirty entries to the CouchDB. * * @return void */ public function flush() { $this->detectChangedDocuments(); if ($this->evm->hasListeners(Event::onFlush)) { $this->evm->dispatchEvent(Event::onFlush, new Event\OnFlushEventArgs($this)); } $config = $this->dm->getConfiguration(); $bulkUpdater = $this->dm->getCouchDBClient()->createBulkUpdater(); $bulkUpdater->setAllOrNothing($config->getAllOrNothingFlush()); foreach ($this->scheduledRemovals as $oid => $document) { $bulkUpdater->deleteDocument($this->documentIdentifiers[$oid], $this->documentRevisions[$oid]); $this->removeFromIdentityMap($document); if ($this->evm->hasListeners(Event::postRemove)) { $this->evm->dispatchEvent(Event::postRemove, new Event\LifecycleEventArgs($document, $this->dm)); } } foreach ($this->scheduledUpdates as $oid => $document) { $class = $this->dm->getClassMetadata(get_class($document)); if ($this->evm->hasListeners(Event::preUpdate)) { $this->evm->dispatchEvent(Event::preUpdate, new Event\LifecycleEventArgs($document, $this->dm)); $this->computeChangeSet($class, $document); // TODO: prevent association computations in this case? } $data = $this->metadataResolver->createDefaultDocumentStruct($class); // Convert field values to json values. foreach ($this->originalData[$oid] as $fieldName => $fieldValue) { if (isset($class->fieldMappings[$fieldName])) { if ($fieldValue !== null && isset($class->fieldMappings[$fieldName]['embedded'])) { // As we store the serialized value in originalEmbeddedData, we can simply copy here. $fieldValue = $this->originalEmbeddedData[$oid][$class->fieldMappings[$fieldName]['jsonName']]; } else { if ($fieldValue !== null) { $fieldValue = Type::getType($class->fieldMappings[$fieldName]['type'])->convertToCouchDBValue($fieldValue); } } $data[$class->fieldMappings[$fieldName]['jsonName']] = $fieldValue; } else { if (isset($class->associationsMappings[$fieldName])) { if ($class->associationsMappings[$fieldName]['type'] & ClassMetadata::TO_ONE) { if (\is_object($fieldValue)) { $fieldValue = $this->getDocumentIdentifier($fieldValue); } else { $fieldValue = null; } $data = $this->metadataResolver->storeAssociationField($data, $class, $this->dm, $fieldName, $fieldValue); } else { if ($class->associationsMappings[$fieldName]['type'] & ClassMetadata::TO_MANY) { if ($class->associationsMappings[$fieldName]['isOwning']) { // TODO: Optimize when not initialized yet! In ManyToMany case we can keep track of ALL ids $ids = array(); if (is_array($fieldValue) || $fieldValue instanceof \Doctrine\Common\Collections\Collection) { foreach ($fieldValue as $key => $relatedObject) { $ids[$key] = $this->getDocumentIdentifier($relatedObject); } } $data = $this->metadataResolver->storeAssociationField($data, $class, $this->dm, $fieldName, $ids); } } } } else { if ($class->hasAttachments && $fieldName == $class->attachmentField) { if (is_array($fieldValue) && $fieldValue) { $data['_attachments'] = array(); foreach ($fieldValue as $filename => $attachment) { if (!$attachment instanceof \Doctrine\CouchDB\Attachment) { throw CouchDBException::invalidAttachment($class->name, $this->documentIdentifiers[$oid], $filename); } $data['_attachments'][$filename] = $attachment->toArray(); } } } } } } // respect the non mapped data, otherwise they will be deleted. if (isset($this->nonMappedData[$oid]) && $this->nonMappedData[$oid]) { $data = array_merge($data, $this->nonMappedData[$oid]); } $rev = $this->getDocumentRevision($document); if ($rev) { $data['_rev'] = $rev; } $bulkUpdater->updateDocument($data); } $response = $bulkUpdater->execute(); $updateConflictDocuments = array(); if ($response->status == 201) { foreach ($response->body as $docResponse) { if (!isset($this->identityMap[$docResponse['id']])) { // deletions continue; } $document = $this->identityMap[$docResponse['id']]; if (isset($docResponse['error'])) { $updateConflictDocuments[] = $document; } else { $this->documentRevisions[spl_object_hash($document)] = $docResponse['rev']; $class = $this->dm->getClassMetadata(get_class($document)); if ($class->isVersioned) { $class->reflFields[$class->versionField]->setValue($document, $docResponse['rev']); } } if ($this->evm->hasListeners(Event::postUpdate)) { $this->evm->dispatchEvent(Event::postUpdate, new Event\LifecycleEventArgs($document, $this->dm)); } } } else { if ($response->status >= 400) { throw HTTPException::fromResponse($bulkUpdater->getPath(), $response); } } foreach ($this->visitedCollections as $col) { $col->takeSnapshot(); } $this->scheduledUpdates = $this->scheduledRemovals = $this->visitedCollections = array(); if (count($updateConflictDocuments)) { throw new UpdateConflictException($updateConflictDocuments); } }
/** * {@inheritdoc} */ protected function getFqcnFromAlias($namespaceAlias, $simpleClassName) { return $this->dm->getConfiguration()->getDocumentNamespace($namespaceAlias) . '\\' . $simpleClassName; }