private function doSerializeResource(Resource $resource, $depth = 0) { $data = array(); $repositoryAlias = $this->registry->getRepositoryAlias($resource->getRepository()); $data['repository_alias'] = $repositoryAlias; $data['repository_type'] = $this->registry->getRepositoryType($resource->getRepository()); $data['payload_alias'] = $this->payloadAliasRegistry->getPayloadAlias($resource); $data['payload_type'] = null; if ($resource instanceof CmfResource) { $data['payload_type'] = $resource->getPayloadType(); } $data['path'] = $resource->getPath(); $data['label'] = $data['node_name'] = PathHelper::getNodeName($data['path']); $data['repository_path'] = $resource->getRepositoryPath(); $enhancers = $this->enhancerRegistry->getEnhancers($repositoryAlias); $children = array(); foreach ($resource->listChildren() as $name => $childResource) { $children[$name] = array(); if ($depth < 2) { $children[$name] = $this->doSerializeResource($childResource, $depth + 1); } } $data['children'] = $children; if ($resource instanceof BodyResource) { $data['body'] = $resource->getBody(); } foreach ($enhancers as $enhancer) { $data = $enhancer->enhance($data, $resource); } return $data; }
/** * {@inheritdoc} */ public function setDefaults(MediaInterface $media, $parentPath = null) { $class = ClassUtils::getClass($media); // check and add name if possible if (!$media->getName()) { if ($media->getId()) { $media->setName(PathHelper::getNodeName($media->getId())); } else { throw new \RuntimeException(sprintf('Unable to set defaults, Media of type "%s" does not have a name or id.', $class)); } } $rootPath = is_null($parentPath) ? $this->rootPath : $parentPath; $path = ($rootPath === '/' ? $rootPath : $rootPath . '/') . $media->getName(); /** @var DocumentManager $dm */ $dm = $this->getObjectManager(); // TODO use PHPCR autoname once this is done: http://www.doctrine-project.org/jira/browse/PHPCR-103 if ($dm->find($class, $path)) { // path already exists $media->setName($media->getName() . '_' . time() . '_' . rand()); } if (!$media->getParent()) { $parent = $dm->find(null, PathHelper::getParentPath($path)); $media->setParent($parent); } }
/** * @param PersistEvent $event * * @throws DocumentManagerException */ public function handlePersist(PersistEvent $event) { $options = $event->getOptions(); $this->validateOptions($options); $document = $event->getDocument(); $parentPath = null; $nodeName = null; if ($options['path']) { $parentPath = PathHelper::getParentPath($options['path']); $nodeName = PathHelper::getNodeName($options['path']); } if ($options['parent_path']) { $parentPath = $options['parent_path']; } if ($parentPath) { $event->setParentNode($this->resolveParent($parentPath, $options)); } if ($options['node_name']) { if (!$event->hasParentNode()) { throw new DocumentManagerException(sprintf('The "node_name" option can only be used either with the "parent_path" option ' . 'or when a parent node has been established by a previous subscriber. ' . 'When persisting document: %s', DocumentHelper::getDebugTitle($document))); } $nodeName = $options['node_name']; } if (!$nodeName) { return; } if ($event->hasNode()) { $this->renameNode($event->getNode(), $nodeName); return; } $node = $this->strategy->createNodeForDocument($document, $event->getParentNode(), $nodeName); $event->setNode($node); }
public function preFlush(ManagerEventArgs $args) { if (empty($this->stack)) { return; } $metadataFactory = $args->getObjectManager()->getMetadataFactory(); foreach ($this->stack as $data) { $children = $data['children']; $ctMetadata = $data['ct_metadata']; $childrenField = $data['field']; $index = 0; foreach ($children as $child) { $childMetadata = $metadataFactory->getMetadataFor(ClassUtils::getRealClass(get_class($child))); $expectedId = $this->encoder->encode($childrenField, $index++); $identifier = $childMetadata->getIdentifierValue($child); $idGenerator = $childMetadata->idGenerator; if ($idGenerator !== ClassMetadata::GENERATOR_TYPE_ASSIGNED) { throw new \InvalidArgumentException(sprintf('Currently, all documents which belong to a mapped collection must use the ' . 'assigned ID generator strategy, "%s" is using "%s".', $childMetadata->getName(), $idGenerator)); } if (!$identifier || PathHelper::getNodeName($identifier) !== $expectedId) { throw new \InvalidArgumentException(sprintf('Child mapped to content type "%s" on field "%s" has an unexpected ID "%s". ' . 'It is currently necessary to envoke the CollectionIdentifierUpdater on all ' . 'documents (at least those which have collections) before they are persisted.', $ctMetadata->getType(), $childrenField, $identifier)); } } } }
/** * @param string $path * * @return Route */ protected function createRoute($path) { $parentPath = PathHelper::getParentPath($path); $parent = $this->getDm()->find(null, $parentPath); $name = PathHelper::getNodeName($path); $route = new Route(); $route->setPosition($parent, $name); $this->getDm()->persist($route); $this->getDm()->flush(); return $route; }
public function removeProperty($workspace, $path) { $propertyName = PathHelper::getNodeName($path); $nodePath = PathHelper::getParentPath($path); $node = $this->nodeReader->readNode($workspace, $nodePath); $property = $node->getProperty($propertyName); if (in_array($property['type'], array('Reference', 'WeakReference'))) { $this->index->deindexReferrer($node->getPropertyValue(Storage::INTERNAL_UUID), $propertyName, $property['type'] === 'Reference' ? false : true); } $node->removeProperty($propertyName); $this->nodeWriter->writeNode($workspace, $nodePath, $node); }
private function resolveSiblingName($siblingId, NodeInterface $parentNode, NodeInterface $node) { if (null === $siblingId) { return; } $siblingPath = $siblingId; if (UUIDHelper::isUUID($siblingId)) { $siblingPath = $this->nodeManager->find($siblingId)->getPath(); } if ($siblingPath !== null && PathHelper::getParentPath($siblingPath) !== $parentNode->getPath()) { throw new DocumentManagerException(sprintf('Cannot reorder documents which are not siblings. Trying to reorder "%s" to "%s"', $node->getPath(), $siblingPath)); } if (null !== $siblingPath) { return PathHelper::getNodeName($siblingPath); } return $node->getName(); }
/** * {@inheritDoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $helper = $this->getPhpcrHelper(); $session = $this->getPhpcrSession(); $path = $input->getArgument('path'); $type = $input->getOption('type'); $dump = $input->getOption('dump'); $setProp = $input->getOption('set-prop'); $removeProp = $input->getOption('remove-prop'); $addMixins = $input->getOption('add-mixin'); $removeMixins = $input->getOption('remove-mixin'); try { $node = $session->getNode($path); } catch (PathNotFoundException $e) { $node = null; } if ($node) { $nodeType = $node->getPrimaryNodeType()->getName(); $output->writeln(sprintf('<info>Node at path </info>%s <info>already exists and has primary type</info> %s.', $path, $nodeType)); if ($nodeType != $type) { $output->writeln(sprintf('<error>You have specified node type "%s" but the existing node is of type "%s"</error>', $type, $nodeType)); return 1; } } else { $nodeName = PathHelper::getNodeName($path); $parentPath = PathHelper::getParentPath($path); try { $parentNode = $session->getNode($parentPath); } catch (PathNotFoundException $e) { $output->writeln(sprintf('<error>Parent path "%s" does not exist</error>', $parentPath)); return 2; } $output->writeln(sprintf('<info>Creating node: </info> %s [%s]', $path, $type)); $node = $parentNode->addNode($nodeName, $type); } $helper->processNode($output, $node, array('setProp' => $setProp, 'removeProp' => $removeProp, 'addMixins' => $addMixins, 'removeMixins' => $removeMixins, 'dump' => $dump)); $session->save(); return 0; }
/** * Rewrites the path of a node for the movement operation, also updating * all cached children. * * This applies both to the cache and to the items themselves so * they return the correct value on getPath calls. * * @param string $curPath Absolute path of the node to rewrite * @param string $newPath The new absolute path */ protected function rewriteItemPaths($curPath, $newPath) { // update internal references in parent $parentCurPath = PathHelper::getParentPath($curPath); $parentNewPath = PathHelper::getParentPath($newPath); if (isset($this->objectsByPath['Node'][$parentCurPath])) { /** @var $node Node */ $node = $this->objectsByPath['Node'][$parentCurPath]; if (!$node->hasNode(PathHelper::getNodeName($curPath))) { throw new PathNotFoundException("Source path can not be found: {$curPath}"); } $node->unsetChildNode(PathHelper::getNodeName($curPath), true); } if (isset($this->objectsByPath['Node'][$parentNewPath])) { /** @var $node Node */ $node = $this->objectsByPath['Node'][$parentNewPath]; $node->addChildNode($this->getNodeByPath($curPath), true, PathHelper::getNodeName($newPath)); } // propagate to current and children items of $curPath, updating internal path /** @var $node Node */ foreach ($this->objectsByPath['Node'] as $path => $node) { // is it current or child? if (strpos($path, $curPath . '/') === 0 || $path == $curPath) { // curPath = /foo // newPath = /mo // path = /foo/bar // newItemPath= /mo/bar $newItemPath = substr_replace($path, $newPath, 0, strlen($curPath)); if (isset($this->objectsByPath['Node'][$path])) { $node = $this->objectsByPath['Node'][$path]; $this->objectsByPath['Node'][$newItemPath] = $node; unset($this->objectsByPath['Node'][$path]); $node->setPath($newItemPath, true); } // update uuid cache $this->objectsByUuid[$node->getIdentifier()] = $node->getPath(); } } }
/** * @dataProvider provideOrder */ public function testOrder($nodes, $orderBy, $expectedOrder) { $rootNode = $this->session->getNode('/'); foreach ($nodes as $nodeName => $nodeProperties) { $node = $rootNode->addNode($nodeName); foreach ($nodeProperties as $name => $value) { $node->setProperty($name, $value); } } $this->session->save(); $qm = $this->session->getWorkspace()->getQueryManager(); $query = $qm->createQuery('SELECT * FROM [nt:unstructured] WHERE value IS NOT NULL ORDER BY ' . $orderBy, \PHPCR\Query\QueryInterface::JCR_SQL2); $result = $query->execute(); $rows = $result->getRows(); $this->assertGreaterThan(0, count($rows)); foreach ($rows as $index => $row) { $path = $row->getNode()->getPath(); $name = PathHelper::getNodeName($path); $expectedName = $expectedOrder[$index]; $this->assertEquals($expectedName, $name); } }
/** * Return file name * * @param string $path file path * @return string * @author Dmitry (dio) Levashov **/ protected function _basename($path) { return PathHelper::getNodeName($path); }
/** * Set or update the path, depth, name and parent reference * * @param string $path the new path this item lives at * @param boolean $move whether this item is being moved in session context * and should store the current path until the next save operation. * * @private */ public function setPath($path, $move = false) { if ($move && is_null($this->oldPath)) { try { $this->checkState(); } catch (InvalidItemStateException $e) { // do not break if object manager tells the move to a child that was removed in backend return; } $this->oldPath = $this->path; } $this->path = $path; $this->depth = '/' === $path ? 0 : substr_count($path, '/'); $this->name = PathHelper::getNodeName($path); $this->parentPath = 0 === $this->depth ? null : PathHelper::getParentPath($path); }
/** * Reorder $moved (child of $parent) before or after $target * * @param string $parent the id of the parent * @param string $moved the id of the child being moved * @param string $target the id of the target node * @param bool $before insert before or after the target * * @return void */ public function reorder($parent, $moved, $target, $before) { $parentNode = $this->session->getNode($parent); $targetName = PathHelper::getNodeName($target); if (!$before) { $nodesIterator = $parentNode->getNodes(); $nodesIterator->rewind(); while ($nodesIterator->valid()) { if ($nodesIterator->key() == $targetName) { break; } $nodesIterator->next(); } $targetName = null; if ($nodesIterator->valid()) { $nodesIterator->next(); if ($nodesIterator->valid()) { $targetName = $nodesIterator->key(); } } } $parentNode->orderBefore(PathHelper::getNodeName($moved), $targetName); $this->session->save(); }
/** * Copy or move a node by UUID to a detination parent. * * Note that the bulk of this method is about the resource locator and can * be removed if we integrate the RoutingAuto component. * * @param string $webspaceKey * @param string $locale * @param bool $move * * @return StructureInterface */ private function copyOrMove($uuid, $destParentUuid, $userId, $webspaceKey, $locale, $move = true) { // find localizations $webspace = $this->webspaceManager->findWebspaceByKey($webspaceKey); $localizations = $webspace->getAllLocalizations(); // load from phpcr $document = $this->documentManager->find($uuid, $locale); $parentDocument = $this->documentManager->find($destParentUuid, $locale); if ($move) { // move node $this->documentManager->move($document, $destParentUuid); } else { // copy node $copiedPath = $this->documentManager->copy($document, $destParentUuid); $document = $this->documentManager->find($copiedPath, $locale); $this->documentManager->refresh($parentDocument); } $originalLocale = $locale; // modifiy the resource locators -- note this can be removed once the routing auto // system is implemented. foreach ($localizations as $locale) { $locale = $locale->getLocalization(); if (!$document instanceof ResourceSegmentBehavior) { break; } // prepare parent content node // finding the document will update the locale without reloading from PHPCR $this->documentManager->find($document->getUuid(), $locale); $this->documentManager->find($parentDocument->getUuid(), $locale); $parentResourceLocator = '/'; if ($parentDocument instanceof ResourceSegmentBehavior) { $parentResourceLocator = $parentDocument->getResourceSegment(); } // TODO: This could be optimized $localizationState = $this->inspector->getLocalizationState($document); if ($localizationState !== LocalizationState::LOCALIZED) { continue; } if ($document->getRedirectType() !== RedirectType::NONE) { continue; } $strategy = $this->getResourceLocator()->getStrategy(); $nodeName = PathHelper::getNodeName($document->getResourceSegment()); $newResourceLocator = $strategy->generate($nodeName, $parentDocument->getResourceSegment(), $webspaceKey, $locale); $document->setResourceSegment($newResourceLocator); $this->documentManager->persist($document, $locale, array('user' => $userId)); } $this->documentManager->flush(); // $this->documentManager->find($document->getUuid(), $originalLocale); return $this->documentToStructure($document); }
/** * @param Request $request * * @return Response * * @throws AccessDeniedException */ public function autoCompleteAction(Request $request) { /** @var Admin $admin */ $admin = $this->pool->getInstance($request->get('code')); $admin->setRequest($request); // check user permission if (false === $admin->isGranted('LIST')) { throw new AccessDeniedException(); } // subject will be empty to avoid unnecessary database requests and keep auto-complete function fast $admin->setSubject($admin->getNewInstance()); $fieldDescription = $this->retrieveFieldDescription($admin, $request->get('field')); $formAutocomplete = $admin->getForm()->get($fieldDescription->getName()); if ($formAutocomplete->getConfig()->getAttribute('disabled')) { throw new AccessDeniedException('Autocomplete list can`t be retrieved because the form element is disabled or read_only.'); } $class = $formAutocomplete->getConfig()->getOption('class'); $property = $formAutocomplete->getConfig()->getAttribute('property'); $minimumInputLength = $formAutocomplete->getConfig()->getAttribute('minimum_input_length'); $itemsPerPage = $formAutocomplete->getConfig()->getAttribute('items_per_page'); $reqParamPageNumber = $formAutocomplete->getConfig()->getAttribute('req_param_name_page_number'); $toStringCallback = $formAutocomplete->getConfig()->getAttribute('to_string_callback'); $searchText = $request->get('q'); if (mb_strlen($searchText, 'UTF-8') < $minimumInputLength) { return new JsonResponse(array('status' => 'KO', 'message' => 'Too short search string.'), 403); } $page = $request->get($reqParamPageNumber); $offset = ($page - 1) * $itemsPerPage; /** @var ModelManager $modelManager */ $modelManager = $formAutocomplete->getConfig()->getOption('model_manager'); $dm = $modelManager->getDocumentManager(); if ($class) { /** @var $qb \Doctrine\ODM\PHPCR\Query\Builder\QueryBuilder */ $qb = $dm->getRepository($class)->createQueryBuilder('a'); $qb->where()->fullTextSearch("a.{$property}", '*' . $searchText . '*'); $qb->setFirstResult($offset); //fetch one more to determine if there are more pages $qb->setMaxResults($itemsPerPage + 1); $query = $qb->getQuery(); $results = $query->execute(); } else { /** @var $qb \PHPCR\Util\QOM\QueryBuilder */ $qb = $dm->createPhpcrQueryBuilder(); // TODO: node type should probably be configurable $qb->from($qb->getQOMFactory()->selector('a', 'nt:unstructured')); $qb->where($qb->getQOMFactory()->fullTextSearch('a', $property, '*' . $searchText . '*')); // handle attribute translation $qb->orWhere($qb->getQOMFactory()->fullTextSearch('a', $dm->getTranslationStrategy('attribute')->getTranslatedPropertyName($request->getLocale(), $property), '*' . $searchText . '*')); $qb->setFirstResult($offset); //fetch one more to determine if there are more pages $qb->setMaxResults($itemsPerPage + 1); $results = $dm->getDocumentsByPhpcrQuery($qb->getQuery()); } //did we max out x+1 $more = count($results) == $itemsPerPage + 1; $method = $request->get('_method_name'); $items = array(); foreach ($results as $path => $document) { // handle child translation if (strpos(PathHelper::getNodeName($path), Translation::LOCALE_NAMESPACE . ':') === 0) { $document = $dm->find(null, PathHelper::getParentPath($path)); } if (!method_exists($document, $method)) { continue; } $label = $document->{$method}(); if ($toStringCallback !== null) { if (!is_callable($toStringCallback)) { throw new \RuntimeException('Option "to_string_callback" does not contain callable function.'); } $label = call_user_func($toStringCallback, $document, $property); } $items[] = array('id' => $admin->id($document), 'label' => $label); } return new JsonResponse(array('status' => 'OK', 'more' => $more, 'items' => $items)); }
/** * Search for a next document. * * @param string|object $path document instance or path from which to search * @param string|object $anchor document instance or path which serves as an anchor from which to flatten the hierarchy * @param null|int $depth depth up to which to traverse down the tree when an anchor is provided * @param bool $ignoreRole if to ignore the role * @param null|string $class the class to filter by * * @return null|object */ private function searchDepthNext($path, $anchor, $depth = null, $ignoreRole = false, $class = null) { if (is_object($path)) { $path = $this->getDm()->getUnitOfWork()->getDocumentId($path); } if (null === $path || '/' === $path) { return; } $node = $this->getDm()->getPhpcrSession()->getNode($path); if (is_object($anchor)) { $anchor = $this->getDm()->getUnitOfWork()->getDocumentId($anchor); } if (0 !== strpos($path, $anchor)) { throw new \RuntimeException("The anchor path '{$anchor}' is not a parent of the current path '{$path}'."); } // take the first eligible child if there are any if (null === $depth || PathHelper::getPathDepth($path) - PathHelper::getPathDepth($anchor) < $depth) { $childNames = $node->getNodeNames()->getArrayCopy(); $result = $this->checkChildren($childNames, $path, $ignoreRole, $class); if ($result) { return $result; } } $parent = $node->getParent(); $parentPath = PathHelper::getParentPath($path); // take the first eligible sibling if (0 === strpos($parentPath, $anchor)) { $childNames = $parent->getNodeNames()->getArrayCopy(); $key = array_search($node->getName(), $childNames); $childNames = array_slice($childNames, $key + 1); $result = $this->checkChildren($childNames, $parentPath, $ignoreRole, $class); if ($result) { return $result; } } // take the first eligible parent, traverse up while ('/' !== $parentPath) { $parent = $parent->getParent(); if (false === strpos($parent->getPath(), $anchor)) { return; } $childNames = $parent->getNodeNames()->getArrayCopy(); $key = array_search(PathHelper::getNodeName($parentPath), $childNames); $childNames = array_slice($childNames, $key + 1); $parentPath = $parent->getPath(); $result = $this->checkChildren($childNames, $parentPath, $ignoreRole, $class); if ($result) { return $result; } } return; }
/** * {@inheritdoc} */ public function toString($object) { if (!is_object($object)) { return parent::toString($object); } if (method_exists($object, '__toString') && null !== $object->__toString()) { $string = (string) $object; return '' !== $string ? $string : $this->trans('link_add', array(), 'SonataAdminBundle'); } $dm = $this->getModelManager()->getDocumentManager(); if ($dm->contains($object)) { return PathHelper::getNodeName($dm->getUnitOfWork()->getDocumentId($object)); } return parent::toString($object); }
/** * @expectedException \PHPCR\RepositoryException * @expectedExceptionMessage must be an absolute path */ public function testGetNodeNameMustBeAbsolute() { PathHelper::getNodeName('foobar'); }
/** * @param string $path the path for which we need the references * @param string $name the name of the referencing properties or null for all * @param bool $weak_reference whether to get weak or strong references * * @return array list of paths to nodes that reference $path */ protected function getNodeReferences($path, $name = null, $weak_reference = false) { $path = $this->encodeAndValidatePathForDavex($path); $identifier = $weak_reference ? 'weakreferences' : 'references'; $request = $this->getRequest(Request::PROPFIND, $path); $request->setBody($this->buildPropfindRequest(array('dcr:' . $identifier))); $request->setDepth(0); $dom = $request->executeDom(); $references = array(); foreach ($dom->getElementsByTagNameNS(self::NS_DCR, $identifier) as $node) { foreach ($node->getElementsByTagNameNS(self::NS_DAV, 'href') as $ref) { $refpath = str_replace($this->workspaceUriRoot, '', urldecode($ref->textContent)); $refpath = $this->removeTrailingSlash($refpath); if (null === $name || PathHelper::getNodeName($refpath) === $name) { $references[] = $refpath; } } } return $references; }
/** * {@inheritDoc} * * @api */ public function move($srcAbsPath, $destAbsPath) { try { $parent = $this->objectManager->getNodeByPath(PathHelper::getParentPath($destAbsPath)); } catch (ItemNotFoundException $e) { throw new PathNotFoundException("Target path can not be found: {$destAbsPath}", $e->getCode(), $e); } if ($parent->hasNode(PathHelper::getNodeName($destAbsPath))) { // TODO same-name siblings throw new ItemExistsException('Target node already exists at ' . $destAbsPath); } if ($parent->hasProperty(PathHelper::getNodeName($destAbsPath))) { throw new ItemExistsException('Target property already exists at ' . $destAbsPath); } $this->objectManager->moveNode($srcAbsPath, $destAbsPath); }
/** * {@inheritdoc} */ public function setDefaults(MediaInterface $media, $parentPath = null) { $class = ClassUtils::getClass($media); // check and add name if possible if (!$media->getName()) { if ($media->getId()) { $media->setName(PathHelper::getNodeName($media->getId())); } else { throw new \RuntimeException(sprintf('Unable to set defaults, Media of type "%s" does not have a name or id.', $class)); } } $rootPath = is_null($parentPath) ? $this->rootPath : $parentPath; $path = ($rootPath === '/' ? $rootPath : $rootPath . '/') . $media->getName(); /** @var DocumentManager $dm */ $dm = $this->getObjectManager(); // TODO use PHPCR autoname if ($dm->find($class, $path)) { // path already exists $ext = pathinfo($media->getName(), PATHINFO_EXTENSION); $media->setName($media->getName() . '_' . time() . '_' . rand() . ($ext ? '.' . $ext : '')); } if (!$media->getParent()) { $parent = $dm->find(null, PathHelper::getParentPath($path)); $media->setParent($parent); } }
/** * {@inheritDoc} */ public function index($workspace, $path, Node $node) { $index = $this->getIndex($workspace); $document = new Document(); $nodeName = PathHelper::getNodeName($path); $localNodeName = $nodeName; // PathHelper::getLocalNodeName($path); $parentPath = PathHelper::getParentPath($path); $document->addField(Field::Keyword(self::IDX_PATH, $path)); $document->addField(Field::Keyword(self::IDX_NODENAME, $nodeName)); $document->addField(Field::Keyword(self::IDX_NODELOCALNAME, $localNodeName)); $document->addField(Field::Keyword(self::IDX_PARENTPATH, $parentPath)); foreach ($node->getProperties() as $propertyName => $property) { $propertyValue = $property['value']; $propertyType = $property['type']; if ($propertyName === Storage::INTERNAL_UUID) { $document->addField(Field::Keyword(Storage::INTERNAL_UUID, $propertyValue)); continue; } switch ($propertyType) { case PropertyType::TYPENAME_STRING: case PropertyType::TYPENAME_NAME: case PropertyType::TYPENAME_PATH: case PropertyType::TYPENAME_URI: $value = (array) $propertyValue; $value = join(self::MULTIVALUE_SEPARATOR, $value); $document->addField(Field::Text($propertyName, $value)); break; case PropertyType::TYPENAME_DATE: $values = (array) $propertyValue; foreach ($values as $i => $value) { if ($value instanceof \DateTime) { $values[$i] = $value->format('c'); } } $value = join(self::MULTIVALUE_SEPARATOR, $values); $document->addField(Field::Text($propertyName, $value)); break; case PropertyType::TYPENAME_DECIMAL: case PropertyType::TYPENAME_LONG: case PropertyType::TYPENAME_DOUBLE: $values = (array) $propertyValue; foreach ($values as &$value) { $value = sprintf('%0' . strlen(PHP_INT_MAX) . 's', $value); } $value = join(self::MULTIVALUE_SEPARATOR, $values); $document->addField(Field::Text($propertyName, $value)); break; case PropertyType::TYPENAME_BOOLEAN: $values = (array) $propertyValue; foreach ($values as &$value) { if ($propertyValue === 'false') { $value = self::VALUE_BOOLEAN_FALSE; } else { $value = 1; } } $value = join(self::MULTIVALUE_SEPARATOR, $values); $document->addField(Field::Text($propertyName, $value)); break; } } $index->addDocument($document); }
/** * {@inheritDoc} */ public function getBinaryStream($path) { $this->assertLoggedIn(); $nodePath = PathHelper::getParentPath($path); $nodeId = $this->pathExists($nodePath); $propertyName = PathHelper::getNodeName($path); $data = $this->conn->fetchAll( 'SELECT data, idx FROM phpcr_binarydata WHERE node_id = ? AND property_name = ? AND workspace_name = ?', array($nodeId, $propertyName, $this->workspaceName) ); $streams = array(); foreach ($data as $row) { if (is_resource($row['data'])) { $stream = $row['data']; } else { $stream = fopen('php://memory', 'rwb+'); fwrite($stream, $row['data']); rewind($stream); } $streams[] = $stream; } // TODO even a multi value field could have only one value stored // we need to also fetch if the property is multi valued instead of this count() check if (count($data) > 1) { return $streams; } return reset($streams); }
/** * {@inheritDoc} */ public function getBinaryStream($path) { $this->assertLoggedIn(); $nodePath = PathHelper::getParentPath($path); $propertyName = PathHelper::getNodeName($path); $streams = array(); // TODO implement $data = array(); foreach ($data as $row) { if (is_resource($row['data'])) { $stream = $row['data']; } else { $stream = fopen('php://memory', 'rwb+'); fwrite($stream, $row['data']); rewind($stream); } $streams[] = $stream; } // TODO even a multi value field could have only one value stored // we need to also fetch if the property is multi valued instead of this count() check if (count($data) > 1) { return $streams; } return reset($streams); }
/** * {@inheritDoc} * @throws RepositoryException when no binary data found */ public function getBinaryStream($path) { $this->assertLoggedIn(); $nodePath = PathHelper::getParentPath($path); $nodeId = $this->getSystemIdForNode($nodePath); $propertyName = PathHelper::getNodeName($path); $data = $this->getConnection()->fetchAll('SELECT data, idx FROM phpcr_binarydata WHERE node_id = ? AND property_name = ? AND workspace_name = ?', array($nodeId, $propertyName, $this->workspaceName)); if (count($data) === 0) { throw new RepositoryException('No binary data found in stream'); } $streams = array(); foreach ($data as $row) { if (is_resource($row['data'])) { $stream = $row['data']; } else { $stream = fopen('php://memory', 'rwb+'); fwrite($stream, $row['data']); rewind($stream); } $streams[] = $stream; } if (count($data) === 1) { // we don't know if this is a multivalue property or not. // TODO we should have something more efficient to know this. a flag in the database? // TODO use self::getProperty()->isMultiple() once implemented $node = $this->getNode($nodePath); if (!is_array($node->{':' . $propertyName})) { return reset($streams); } } return $streams; }
/** * Returns an array representation of the document * * @param ModelManager $manager the manager to use with this document * @param object $document * * @return array */ protected function documentToArray(ModelManager $manager, $document) { $className = ClassUtils::getClass($document); $rel = in_array($className, array_keys($this->validClasses)) ? $className : 'undefined'; $rel = $this->normalizeClassname($rel); $admin = $this->getAdmin($document); if (null !== $admin) { $label = $admin->toString($document); $id = $admin->getNormalizedIdentifier($document); $urlSafeId = $admin->getUrlsafeIdentifier($document); } else { $label = method_exists($document, '__toString') ? (string) $document : ClassUtils::getClass($document); $id = $manager->getNormalizedIdentifier($document); $urlSafeId = $manager->getUrlsafeIdentifier($document); } if (substr($label, 0, 1) === '/') { $label = PathHelper::getNodeName($label); } // TODO: ideally the tree should simply not make the node clickable $label .= $admin ? '' : ' ' . $this->translator->trans('not_editable', array(), 'SonataDoctrinePHPCRAdmin'); $hasChildren = false; if (isset($this->validClasses[$className]['valid_children']) && count($this->validClasses[$className]['valid_children'])) { if ($this->preciseChildren) { // determine if a node has children the accurate way. we need to // loop over all documents, as a PHPCR node might have children but // only invalid ones. this is quite costly. $hasChildren = (bool) count($this->getDocumentChildren($manager, $document)); } else { // just check if there is any child node $hasChildren = $manager->getDocumentManager()->getNodeForDocument($document)->hasNodes(); } } return array('data' => $label, 'attr' => array('id' => $id, 'url_safe_id' => $urlSafeId, 'rel' => $rel), 'state' => $hasChildren ? 'closed' : null); }
/** * Executes all document insertions * * @param array $documents array of all to be inserted documents */ private function executeInserts($documents) { // sort the documents to insert parents first but maintain child order $oids = array(); foreach ($documents as $oid => $document) { if (!$this->contains($oid)) { continue; } $oids[$oid] = $this->getDocumentId($document); } $order = array_flip(array_values($oids)); uasort($oids, function ($a, $b) use($order) { // compute the node depths $aCount = substr_count($a, '/'); $bCount = substr_count($b, '/'); // ensure that the original order is maintained for nodes with the same depth if ($aCount === $bCount) { return $order[$a] < $order[$b] ? -1 : 1; } return $aCount < $bCount ? -1 : 1; }); $associationChangesets = $associationUpdates = array(); foreach ($oids as $oid => $id) { $document = $documents[$oid]; $class = $this->dm->getClassMetadata(get_class($document)); // PHPCR does not validate nullable unless we would start to // generate custom node types, which we at the moment don't. // the ORM can delegate this validation to the relational database // that is using a strict schema foreach ($class->fieldMappings as $fieldName) { if (!isset($this->documentChangesets[$oid]['fields'][$fieldName]) && !$class->isNullable($fieldName) && !$this->isAutocreatedProperty($class, $fieldName)) { throw new PHPCRException(sprintf('Field "%s" of class "%s" is not nullable', $fieldName, $class->name)); } } $parentNode = $this->session->getNode(PathHelper::getParentPath($id)); $nodename = PathHelper::getNodeName($id); $node = $parentNode->addNode($nodename, $class->nodeType); if ($class->node) { $this->originalData[$oid][$class->node] = $node; } if ($class->nodename) { $this->originalData[$oid][$class->nodename] = $nodename; } try { $node->addMixin('phpcr:managed'); } catch (NoSuchNodeTypeException $e) { throw new PHPCRException('Register phpcr:managed node type first. See https://github.com/doctrine/phpcr-odm/wiki/Custom-node-type-phpcr:managed'); } foreach ($class->mixins as $mixin) { $node->addMixin($mixin); } if ($class->identifier) { $class->setIdentifierValue($document, $id); } if ($class->node) { $class->reflFields[$class->node]->setValue($document, $node); } if ($class->nodename) { // make sure this reflects the id generator strategy generated id $class->reflFields[$class->nodename]->setValue($document, $node->getName()); } // make sure this reflects the id generator strategy generated id if ($class->parentMapping && !$class->reflFields[$class->parentMapping]->getValue($document)) { $class->reflFields[$class->parentMapping]->setValue($document, $this->getOrCreateProxyFromNode($parentNode, $this->getCurrentLocale($document, $class))); } if ($this->writeMetadata) { $this->documentClassMapper->writeMetadata($this->dm, $node, $class->name); } $this->setMixins($class, $node, $document); $fields = isset($this->documentChangesets[$oid]['fields']) ? $this->documentChangesets[$oid]['fields'] : array(); foreach ($fields as $fieldName => $fieldValue) { // Ignore translatable fields (they will be persisted by the translation strategy) if (in_array($fieldName, $class->translatableFields)) { continue; } if (in_array($fieldName, $class->fieldMappings)) { $mapping = $class->mappings[$fieldName]; $type = PropertyType::valueFromName($mapping['type']); if (null === $fieldValue) { continue; } if ($mapping['multivalue'] && $fieldValue) { $fieldValue = (array) $fieldValue; if (isset($mapping['assoc'])) { $fieldValue = $this->processAssoc($node, $mapping, $fieldValue); } } $node->setProperty($mapping['property'], $fieldValue, $type); } elseif (in_array($fieldName, $class->referenceMappings) || in_array($fieldName, $class->referrersMappings)) { $associationUpdates[$oid] = $document; //populate $associationChangesets to force executeUpdates($associationUpdates) //to only update association fields $data = isset($associationChangesets[$oid]['fields']) ? $associationChangesets[$oid]['fields'] : array(); $data[$fieldName] = array(null, $fieldValue); $associationChangesets[$oid] = array('fields' => $data); } } $this->doSaveTranslation($document, $node, $class); if ($invoke = $this->eventListenersInvoker->getSubscribedSystems($class, Event::postPersist)) { $this->eventListenersInvoker->invoke($class, Event::postPersist, $document, new LifecycleEventArgs($document, $this->dm), $invoke); } } $this->documentChangesets = array_merge($this->documentChangesets, $associationChangesets); $this->executeUpdates($associationUpdates, false); }
/** * Creates a new node at the specified $relPath * * {@inheritDoc} * * In Jackalope, the child node type definition is immediately applied if no * primaryNodeTypeName is specified. * * The PathNotFoundException and ConstraintViolationException are thrown * immediately. * Version and Lock related exceptions are delayed until save. * * @api */ public function addNode($relPath, $primaryNodeTypeName = null) { $relPath = (string) $relPath; $this->checkState(); $ntm = $this->session->getWorkspace()->getNodeTypeManager(); // are we not the immediate parent? if (strpos($relPath, '/') !== false) { // forward to real parent $relPath = PathHelper::absolutizePath($relPath, $this->getPath(), true); $parentPath = PathHelper::getParentPath($relPath); $newName = PathHelper::getNodeName($relPath); try { $parentNode = $this->objectManager->getNodeByPath($parentPath); } catch (ItemNotFoundException $e) { //we have to throw a different exception if there is a property // with that name than if there is nothing at the path at all. // lets see if the property exists if ($this->session->propertyExists($parentPath)) { throw new ConstraintViolationException("Node '{$this->path}': Not allowed to add a node below property at {$parentPath}"); } throw new PathNotFoundException($e->getMessage(), $e->getCode(), $e); } return $parentNode->addNode($newName, $primaryNodeTypeName); } if (is_null($primaryNodeTypeName)) { if ($this->primaryType === 'rep:root') { $primaryNodeTypeName = 'nt:unstructured'; } else { $type = $ntm->getNodeType($this->primaryType); $nodeDefinitions = $type->getChildNodeDefinitions(); foreach ($nodeDefinitions as $def) { if (!is_null($def->getDefaultPrimaryType())) { $primaryNodeTypeName = $def->getDefaultPrimaryTypeName(); break; } } } if (is_null($primaryNodeTypeName)) { throw new ConstraintViolationException("No matching child node definition found for `{$relPath}' in type `{$this->primaryType}' for node '{$this->path}'. Please specify the type explicitly."); } } // create child node //sanity check: no index allowed. TODO: we should verify this is a valid node name if (false !== strpos($relPath, ']')) { throw new RepositoryException("The node '{$this->path}' does not allow an index in name of newly created node: {$relPath}"); } if (in_array($relPath, $this->nodes, true)) { throw new ItemExistsException("The node '{$this->path}' already has a child named '{$relPath}''."); //TODO: same-name siblings if nodetype allows for them } $data = array('jcr:primaryType' => $primaryNodeTypeName); $path = $this->getChildPath($relPath); $node = $this->factory->get('Node', array($data, $path, $this->session, $this->objectManager, true)); $this->addChildNode($node, false); // no need to check the state, we just checked when entering this method $this->objectManager->addNode($path, $node); if (is_array($this->originalNodesOrder)) { // new nodes are added at the end $this->originalNodesOrder[] = $relPath; } //by definition, adding a node sets the parent to modified $this->setModified(); return $node; }
/** * @see StaticPathHelper::getNodeName */ public function getNodeName($path) { return StaticPathHelper::getNodeName($path); }
/** {@inheritDoc} */ public function contains($element) { if (!$this->isInitialized()) { $uow = $this->dm->getUnitOfWork(); // Shortcut for new documents $documentState = $uow->getDocumentState($element); if ($documentState === UnitOfWork::STATE_NEW) { return false; } // Document is scheduled for inclusion if ($documentState === UnitOfWork::STATE_MANAGED && $uow->isScheduledForInsert($element)) { return false; } $documentId = $uow->getDocumentId($element); if (PathHelper::getParentPath($documentId) !== PathHelper::getParentPath($uow->getDocumentId($this->document))) { return false; } $nodeName = PathHelper::getNodeName($documentId); return in_array($nodeName, $this->getOriginalNodeNames()); } return parent::contains($element); }