/** * Releases any lock that exists on this document. * * @param object $document */ public function unlock($document) { $id = $this->uow->getDocumentIdentifier($document); $criteria = array('_id' => $this->class->getDatabaseIdentifierValue($id)); $lockMapping = $this->class->fieldMappings[$this->class->lockField]; $this->collection->update($criteria, array('$unset' => array($lockMapping['name'] => true))); $this->class->reflFields[$this->class->lockField]->setValue($document, null); }
/** * Prime references within a mapped field of one or more documents. * * If a $primer callable is provided, it should have the same signature as * the default primer defined in the constructor. If $primer is not * callable, the default primer will be used. * * @param ClassMetadata $class Class metadata for the document * @param array|\Traversable $documents Documents containing references to prime * @param string $fieldName Field name containing references to prime * @param array $hints UnitOfWork hints for priming queries * @param callable $primer Optional primer callable * @throws \InvalidArgumentException If the mapped field is not the owning * side of a reference relationship. * @throws \InvalidArgumentException If $primer is not callable * @throws \LogicException If the mapped field is a simple reference and is * missing a target document class. */ public function primeReferences(ClassMetadata $class, $documents, $fieldName, array $hints = array(), $primer = null) { $data = $this->parseDotSyntaxForPrimer($fieldName, $class, $documents); $mapping = $data['mapping']; $fieldName = $data['fieldName']; $class = $data['class']; $documents = $data['documents']; /* Inverse-side references would need to be populated before we can * collect references to be primed. This is not supported. */ if (!isset($mapping['reference']) || !$mapping['isOwningSide']) { throw new \InvalidArgumentException(sprintf('Field "%s" is not the owning side of a reference relationship in class "%s"', $fieldName, $class->name)); } /* Simple reference require a target document class so we can construct * the priming query. */ if (!empty($mapping['simple']) && empty($mapping['targetDocument'])) { throw new \LogicException(sprintf('Field "%s" is a simple reference without a target document class in class "%s"', $fieldName, $class->name)); } if ($primer !== null && !is_callable($primer)) { throw new \InvalidArgumentException('$primer is not callable'); } $primer = $primer ?: $this->defaultPrimer; $groupedIds = array(); /* @var $document PersistentCollection */ foreach ($documents as $document) { $fieldValue = $class->getFieldValue($document, $fieldName); /* The field will need to be either a Proxy (reference-one) or * PersistentCollection (reference-many) in order to prime anything. */ if (!is_object($fieldValue)) { continue; } if ($mapping['type'] === 'one' && $fieldValue instanceof Proxy && !$fieldValue->__isInitialized()) { $refClass = $this->dm->getClassMetadata(get_class($fieldValue)); $id = $this->uow->getDocumentIdentifier($fieldValue); $groupedIds[$refClass->name][serialize($id)] = $id; } elseif ($mapping['type'] == 'many' && $fieldValue instanceof PersistentCollection) { $this->addManyReferences($fieldValue, $groupedIds); } } foreach ($groupedIds as $className => $ids) { $refClass = $this->dm->getClassMetadata($className); call_user_func($primer, $this->dm, $refClass, array_values($ids), $hints); } }
/** * Returns a DBRef array for the supplied document. * * @param mixed $document A document object * @param array $referenceMapping Mapping for the field that references the document * * @throws \InvalidArgumentException * @return array A DBRef array */ public function createDBRef($document, array $referenceMapping = null) { if (!is_object($document)) { throw new \InvalidArgumentException('Cannot create a DBRef, the document is not an object'); } $class = $this->getClassMetadata(get_class($document)); $id = $this->unitOfWork->getDocumentIdentifier($document); if (!$id) { throw new \RuntimeException(sprintf('Cannot create a DBRef for class %s without an identifier. Have you forgotten to persist/merge the document first?', $class->name)); } if (!empty($referenceMapping['simple'])) { if ($class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION) { throw MappingException::simpleReferenceMustNotTargetDiscriminatedDocument($referenceMapping['targetDocument']); } return $class->getDatabaseIdentifierValue($id); } $dbRef = array('$ref' => $class->getCollection(), '$id' => $class->getDatabaseIdentifierValue($id), '$db' => $this->getDocumentDatabase($class->name)->getName()); /* If the class has a discriminator (field and value), use it. A child * class that is not defined in the discriminator map may only have a * discriminator field and no value, so default to the full class name. */ if (isset($class->discriminatorField)) { $dbRef[$class->discriminatorField] = isset($class->discriminatorValue) ? $class->discriminatorValue : $class->name; } /* Add a discriminator value if the referenced document is not mapped * explicitly to a targetDocument class. */ if ($referenceMapping !== null && !isset($referenceMapping['targetDocument'])) { $discriminatorField = $referenceMapping['discriminatorField']; $discriminatorValue = isset($referenceMapping['discriminatorMap']) ? array_search($class->name, $referenceMapping['discriminatorMap']) : $class->name; /* If the discriminator value was not found in the map, use the full * class name. In the future, it may be preferable to throw an * exception here (perhaps based on some strictness option). * * @see PersistenceBuilder::prepareEmbeddedDocumentValue() */ if ($discriminatorValue === false) { $discriminatorValue = $class->name; } $dbRef[$discriminatorField] = $discriminatorValue; } return $dbRef; }