/** * @param ResourceControllerEvent $event */ public function onEvent(ResourceControllerEvent $event) { $document = $event->getSubject(); $metadata = $this->documentManager->getClassMetadata(get_class($document)); if ($metadata->idGenerator !== ClassMetadata::GENERATOR_TYPE_PARENT) { throw new \RuntimeException(sprintf('Document of class "%s" must be using the GENERATOR_TYPE_PARENT identificatio strategy (value %s), it is current using "%s" (this may be an automatic configuration: be sure to map both the `nodename` and the `parentDocument`).', get_class($document), ClassMetadata::GENERATOR_TYPE_PARENT, $metadata->idGenerator)); } // NOTE: that the PHPCR-ODM requires these two fields to be set when // when the GENERATOR_TYPE_PARENT "ID" strategy is used. $nameField = $metadata->nodename; $parentField = $metadata->parentMapping; $parentDocument = $metadata->getFieldValue($document, $parentField); $phpcrNode = $this->documentManager->getNodeForDocument($parentDocument); $parentPath = $phpcrNode->getPath(); $baseCandidateName = $metadata->getFieldValue($document, $nameField); $candidateName = $baseCandidateName; $index = 1; while (true) { $candidatePath = sprintf('%s/%s', $parentPath, $candidateName); $existing = $this->documentManager->find(null, $candidatePath); // if the existing document is the document we are updating, then thats great. if ($existing === $document) { return; } if (null === $existing) { $metadata->setFieldValue($document, $nameField, $candidateName); return; } $candidateName = sprintf('%s-%d', $baseCandidateName, $index); $index++; } }
/** * @param ResourceControllerEvent $event */ public function onEvent(ResourceControllerEvent $event) { $document = $event->getSubject(); $metadata = $this->documentManager->getClassMetadata(get_class($document)); if (null === ($nameField = $metadata->nodename)) { throw new \RuntimeException(sprintf('In order to use the node name filter on "%s" it is necessary to map a field as the "nodename"', get_class($document))); } $name = $metadata->getFieldValue($document, $nameField); $name = preg_replace('/\\/|:|\\[|\\]|\\||\\*/', $this->replacementCharacter, $name); $metadata->setFieldValue($document, $nameField, $name); }
/** * {@inheritdoc} */ public function build(MetadataInterface $metadata, FormBuilderInterface $formBuilder, array $options) { $classMetadata = $this->documentManager->getClassMetadata($metadata->getClass('model')); // the field mappings should only contain standard value mappings foreach ($classMetadata->fieldMappings as $fieldName) { if ($fieldName === $classMetadata->uuidFieldName) { continue; } if ($fieldName === $classMetadata->nodename) { continue; } $options = []; $mapping = $classMetadata->mappings[$fieldName]; if ($mapping['nullable'] === false) { $options['required'] = true; } $formBuilder->add($fieldName, null, $options); } }
private function expandClassName(DocumentManagerInterface $dm, $className = null) { if (null === $className) { return null; } if (false !== strstr($className, ':')) { $className = $dm->getClassMetadata($className)->getName(); } return $className; }
function it_should_clean_the_name(ResourceControllerEvent $event, DocumentManagerInterface $documentManager, ClassMetadata $metadata) { $document = new \stdClass(); $event->getSubject()->willReturn($document); $documentManager->getClassMetadata('stdClass')->willReturn($metadata); $metadata->nodename = 'foobar'; $metadata->getFieldValue($document, 'foobar')->willReturn('Hello//Foo'); $metadata->setFieldValue($document, 'foobar', 'Hello Foo')->shouldBeCalled(); $this->onEvent($event); }
/** * Create a new repository instance for a document class. * * @param DocumentManagerInterface $dm The DocumentManager instance. * @param string $documentName The name of the document. * * @return \Doctrine\Common\Persistence\ObjectRepository */ protected function createRepository(DocumentManagerInterface $dm, $documentName) { $metadata = $dm->getClassMetadata($documentName); $repositoryClassName = $metadata->customRepositoryClassName; if ($repositoryClassName === null) { $configuration = $dm->getConfiguration(); $repositoryClassName = $configuration->getDefaultRepositoryClassName(); } return new $repositoryClassName($dm, $metadata); }
private function getVersionedNodePath($document) { $path = $this->getDocumentId($document); $metadata = $this->dm->getClassMetadata(get_class($document)); if (!$metadata->versionable) { throw new InvalidArgumentException(sprintf("The document at path '%s' is not versionable", $path)); } $node = $this->session->getNode($path); $mixin = $metadata->versionable === 'simple' ? 'mix:simpleVersionable' : 'mix:versionable'; if (!$node->isNodeType($mixin)) { $node->addMixin($mixin); } return $path; }
function it_should_auto_increment_the_name_if_a_conflict_exists(DocumentManagerInterface $documentManager, ResourceControllerEvent $event, ClassMetadata $metadata, NodeInterface $node) { $document = new \stdClass(); $parentDocument = new \stdClass(); $existingDocument = new \stdClass(); $event->getSubject()->willReturn($document); $documentManager->getClassMetadata('stdClass')->willReturn($metadata); $metadata->idGenerator = ClassMetadata::GENERATOR_TYPE_PARENT; $metadata->nodename = 'title'; $metadata->parentMapping = 'parent'; $metadata->getFieldValue($document, 'parent')->willReturn($parentDocument); $documentManager->getNodeForDocument($parentDocument)->willReturn($node); $node->getPath()->willReturn('/path/to'); $metadata->getFieldValue($document, 'title')->willReturn('Hello World'); $documentManager->find(null, '/path/to/Hello World')->willReturn($existingDocument); $documentManager->find(null, '/path/to/Hello World-1')->willReturn($existingDocument); $documentManager->find(null, '/path/to/Hello World-2')->willReturn($existingDocument); $documentManager->find(null, '/path/to/Hello World-3')->willReturn(null); $metadata->setFieldValue($document, 'title', 'Hello World-3')->shouldBeCalled(); $this->onEvent($event); }
function it_should_return_early_if_force_is_false_and_subject_already_has_a_parent(ResourceControllerEvent $event, ClassMetadata $documentMetadata, DocumentManagerInterface $documentManager) { $subjectDocument = new \stdClass(); $event->getSubject()->willReturn($subjectDocument); $documentManager->getClassMetadata(\stdClass::class)->willReturn($documentMetadata); $documentMetadata->parentMapping = 'parent'; $documentMetadata->getFieldValue($subjectDocument, 'parent')->willReturn(new \stdClass()); $documentManager->find(null, '/path/to')->shouldNotBeCalled(); $this->onPreCreate($event); }
/** * If the parent node has child restrictions, ensure that the given * class name is within them. * * @param NodeInterface $parentNode * @param string $classFqn */ private function validateChildClass(NodeInterface $parentNode, ClassMetadata $class) { $parentClass = $this->documentClassMapper->getClassName($this->dm, $parentNode); if (null === $parentClass) { return; } $metadata = $this->dm->getClassMetadata($parentClass); $metadata->assertValidChildClass($class); }
/** * {@inheritDoc} */ public function getClassMetadata($className) { return $this->wrapped->getClassMetadata($className); }
/** * Migrate content into the new translation format and remove the old properties. * * This does not commit the changes to the repository. Call save on the * PHPCR session *after each batch*. Calling flush on the document manager * *is not enough*. * * When translating, the new properties are copied into the languages * specified in $locales. When un-translating, the current locale and * language fallback is used, and $locales is ignored. * * To convert all fields into a translation, you can pass an empty array * for $fields and the information is read from the metadata. The fields * are mandatory when converting fields back to non-translated. * * To convert a single field from translated to non-translated, simply * specify that field. * * If you convert an existing translation, you need to specify the name of * the strategy that was previously used. The name is the one you would use * for DocumentManagerInterface::getTranslationStrategy, so "attribute" or * "child". * * The current strategy is read from the document metadata. * * Only documents that match $class exactly are converted, but not * descendants. You can query whether there where documents encountered * that could not be converted by calling getLastNotices() after each call * to convert(). * * @param string $class FQN of the document class * @param array $locales Locales to copy previously untranslated fields into. * Ignored when untranslating a document. * @param array $fields List of fields to convert. Required when making a * field not translated anymore * @param string $previousStrategyName Name of previous strategy or "none" if field was not * previously translated * * @return boolean true if there are more documents to convert and this method needs to be * called again. * * @throws PHPCRExceptionInterface if the document can not be found. * * @see getLastNotices() */ public function convert($class, $locales, array $fields = array(), $previousStrategyName = NonTranslatedStrategy::NAME) { /** @var ClassMetadata $currentMeta */ $currentMeta = $this->dm->getClassMetadata($class); $currentStrategyName = $currentMeta->translator ?: NonTranslatedStrategy::NAME; // sanity check strategies if ($currentStrategyName === $previousStrategyName) { $message = 'Previous and current strategy are the same.'; if (NonTranslatedStrategy::NAME === $currentStrategyName) { $message .= ' To untranslate a document, you need to specify the previous translation strategy'; } else { $message .= sprintf(' Document is currently at %s', $currentStrategyName); } throw new InvalidArgumentException($message); } if (!count($locales) && NonTranslatedStrategy::NAME !== $currentStrategyName) { throw new InvalidArgumentException('When converting to translated content, the locales must be specified.'); } $this->notices = array(); $translated = null; foreach ($fields as $field) { $current = !empty($currentMeta->mappings[$field]['translated']); if (null !== $translated && $current !== $translated) { throw new InvalidArgumentException(sprintf('The list of specified fields %s contained both translated and untranslated fields. If you want to move back to untranslated, specify only the untranslated fields.', implode(', ', $fields))); } $translated = $current; } $partialUntranslate = false; if (false === $translated && NonTranslatedStrategy::NAME !== $currentStrategyName) { // special case, convert fields back to untranslated $partialUntranslate = true; $previousStrategyName = $currentStrategyName; $currentStrategyName = NonTranslatedStrategy::NAME; $currentMeta->translator = null; } $currentStrategy = NonTranslatedStrategy::NAME === $currentStrategyName ? new NonTranslatedStrategy($this->dm) : $this->dm->getTranslationStrategy($currentMeta->translator); if (NonTranslatedStrategy::NAME === $previousStrategyName) { $previousStrategy = new NonTranslatedStrategy($this->dm); } else { $previousStrategy = $this->dm->getTranslationStrategy($previousStrategyName); } if (!$fields) { if (NonTranslatedStrategy::NAME === $currentStrategyName) { throw new InvalidArgumentException('To untranslate a document, you need to specify the fields that where previously translated'); } $fields = $currentMeta->translatableFields; } // trick query into using the previous strategy $currentMeta->translator = NonTranslatedStrategy::NAME === $previousStrategyName ? null : $previousStrategyName; if (NonTranslatedStrategy::NAME === $currentStrategyName) { $currentMeta->translatableFields = $fields; foreach ($fields as $field) { $currentMeta->mappings[$field]['translated'] = true; } } $qb = $this->dm->createQueryBuilder(); $or = $qb->fromDocument($class, 'd')->where()->orX(); foreach ($fields as $field) { $or->fieldIsset('d.' . $field); } $qb->setMaxResults($this->batchSize); $documents = $qb->getQuery()->execute(); // restore meta data to the real thing $currentMeta->translator = NonTranslatedStrategy::NAME === $currentStrategyName ? null : $currentStrategyName; if (NonTranslatedStrategy::NAME === $currentStrategyName) { $currentMeta->translatableFields = array(); foreach ($fields as $field) { unset($currentMeta->mappings[$field]['translated']); } } // fake metadata for previous $previousMeta = clone $currentMeta; $previousMeta->translator = NonTranslatedStrategy::NAME === $previousStrategyName ? null : $previousStrategyName; // even when previously not translated, we use translatableFields for the NonTranslatedStrategy $previousMeta->translatableFields = $fields; foreach ($documents as $document) { if (ClassUtils::getClass($document) !== $class) { $path = $this->dm->getUnitOfWork()->getDocumentId($document); $this->notices[$path] = ClassUtils::getClass($document); continue; } $this->convertDocument($document, $previousStrategy, $previousMeta, $currentStrategy, $currentMeta, $fields, $locales, $partialUntranslate); } return count($documents) === $this->batchSize; }
/** * @param ResourceControllerEvent $event */ public function onPreCreate(ResourceControllerEvent $event) { $document = $event->getSubject(); $class = get_class($document); $this->resolveParent($document, $this->documentManager->getClassMetadata($class)); }