/**
  * Add the current node and all parent identifiers to be used for cache entry tagging
  *
  * @Flow\Before("method(TYPO3\Flow\Mvc\Routing\RouterCachingService->extractUuids())")
  * @param \TYPO3\Flow\Aop\JoinPointInterface $joinPoint The current join point
  * @return void
  */
 public function addCurrentNodeIdentifier(JoinPointInterface $joinPoint)
 {
     $values = $joinPoint->getMethodArgument('values');
     if (!isset($values['node']) || strpos($values['node'], '@') === false) {
         return;
     }
     // Build context explicitly without authorization checks because the security context isn't available yet
     // anyway and any Entity Privilege targeted on Workspace would fail at this point:
     $this->securityContext->withoutAuthorizationChecks(function () use($joinPoint, $values) {
         $contextPathPieces = NodePaths::explodeContextPath($values['node']);
         $context = $this->contextFactory->create(['workspaceName' => $contextPathPieces['workspaceName'], 'dimensions' => $contextPathPieces['dimensions'], 'invisibleContentShown' => true]);
         $node = $context->getNode($contextPathPieces['nodePath']);
         if (!$node instanceof NodeInterface) {
             return;
         }
         $values['node-identifier'] = $node->getIdentifier();
         $node = $node->getParent();
         $values['node-parent-identifier'] = array();
         while ($node !== null) {
             $values['node-parent-identifier'][] = $node->getIdentifier();
             $node = $node->getParent();
         }
         $joinPoint->setMethodArgument('values', $values);
     });
 }
 /**
  * Normalizes the given node path to a reference path and returns an absolute path.
  *
  * @param string $path The non-normalized path
  * @param string $referencePath a reference path in case the given path is relative.
  * @param string $siteNodePath Reference path to a site node. Relative paths starting with "~" will be based on the siteNodePath.
  * @return string The normalized absolute path
  * @throws \InvalidArgumentException if the node path was invalid.
  */
 public function normalizePath($path, $referencePath = NULL, $siteNodePath = NULL)
 {
     if (strpos($path, '~') === 0) {
         $path = NodePaths::addNodePathSegment($siteNodePath, substr($path, 1));
     }
     return parent::normalizePath($path, $referencePath);
 }
 /**
  * Generates a Context that exactly fits the given NodeData Workspace, Dimensions & Site.
  *
  * @param NodeData $nodeData
  * @return ContentContext
  */
 protected function createContextMatchingNodeData(NodeData $nodeData)
 {
     $nodePath = NodePaths::getRelativePathBetween(SiteService::SITES_ROOT_PATH, $nodeData->getPath());
     list($siteNodeName) = explode('/', $nodePath);
     $site = $this->siteRepository->findOneByNodeName($siteNodeName);
     $contextProperties = ['workspaceName' => $nodeData->getWorkspace()->getName(), 'invisibleContentShown' => true, 'inaccessibleContentShown' => true, 'removedContentShown' => true, 'dimensions' => $nodeData->getDimensionValues(), 'currentSite' => $site];
     if ($domain = $site->getFirstActiveDomain()) {
         $contextProperties['currentDomain'] = $domain;
     }
     return $this->_contextFactory->create($contextProperties);
 }
 /**
  * Change the property on the given node.
  *
  * @param NodeData $node
  * @return NodeData
  */
 public function execute(NodeData $node)
 {
     $node = $this->nodeFactory->createFromNodeData($node, $this->contextFactory->create(array('workspaceName' => $node->getWorkspace()->getName(), 'invisibleContentShown' => true, 'inaccessibleContentShown' => true)));
     if (!$node) {
         return;
     }
     $column0 = $node->getPrimaryChildNode();
     if (!$column0) {
         return;
     }
     foreach ($column0->getChildNodes() as $childNode) {
         $node = $childNode->copyAfter($node, NodePaths::generateRandomNodeName());
     }
     return $node;
 }
 /**
  * Remove given site all nodes for that site and all domains associated.
  *
  * @param Site $site
  * @return void
  */
 public function pruneSite(Site $site)
 {
     $siteNodePath = NodePaths::addNodePathSegment(static::SITES_ROOT_PATH, $site->getNodeName());
     $this->nodeDataRepository->removeAllInPath($siteNodePath);
     $siteNodes = $this->nodeDataRepository->findByPath($siteNodePath);
     foreach ($siteNodes as $siteNode) {
         $this->nodeDataRepository->remove($siteNode);
     }
     $domainsForSite = $this->domainRepository->findBySite($site);
     foreach ($domainsForSite as $domain) {
         $this->domainRepository->remove($domain);
     }
     $this->siteRepository->remove($site);
     $this->emitSitePruned($site);
 }
 /**
  * Converts a given context path to a node object
  *
  * @param string $contextPath
  * @return NodeInterface
  */
 public function getNodeFromContextPath($contextPath, Site $site = null, Domain $domain = null)
 {
     $nodePathAndContext = NodePaths::explodeContextPath($contextPath);
     $nodePath = $nodePathAndContext['nodePath'];
     $workspaceName = $nodePathAndContext['workspaceName'];
     $dimensions = $nodePathAndContext['dimensions'];
     $contextProperties = $this->prepareContextProperties($workspaceName, $dimensions);
     if ($site === null) {
         list(, , $siteNodeName) = explode('/', $nodePath);
         $site = $this->siteRepository->findOneByNodeName($siteNodeName);
     }
     if ($domain === null) {
         $domain = $this->domainRepository->findOneBySite($site);
     }
     $contextProperties['currentSite'] = $site;
     $contextProperties['currentDomain'] = $domain;
     $context = $this->contextFactory->create($contextProperties);
     $workspace = $context->getWorkspace(false);
     if (!$workspace) {
         return new \TYPO3\Flow\Error\Error(sprintf('Could not convert the given source to Node object because the workspace "%s" as specified in the context node path does not exist.', $workspaceName), 1451392329);
     }
     return $context->getNode($nodePath);
 }
 /**
  * Update a site
  *
  * @param Site $site A site to update
  * @param string $newSiteNodeName A new site node name
  * @return void
  * @Flow\Validate(argumentName="$site", type="UniqueEntity")
  * @Flow\Validate(argumentName="$newSiteNodeName", type="NotEmpty")
  * @Flow\Validate(argumentName="$newSiteNodeName", type="StringLength", options={ "minimum"=1, "maximum"=250 })
  * @Flow\Validate(argumentName="$newSiteNodeName", type="TYPO3.Neos:NodeName")
  */
 public function updateSiteAction(Site $site, $newSiteNodeName)
 {
     if ($site->getNodeName() !== $newSiteNodeName) {
         $oldSiteNodePath = NodePaths::addNodePathSegment(SiteService::SITES_ROOT_PATH, $site->getNodeName());
         $newSiteNodePath = NodePaths::addNodePathSegment(SiteService::SITES_ROOT_PATH, $newSiteNodeName);
         /** @var $workspace Workspace */
         foreach ($this->workspaceRepository->findAll() as $workspace) {
             $siteNode = $this->nodeDataRepository->findOneByPath($oldSiteNodePath, $workspace);
             if ($siteNode !== null) {
                 $siteNode->setPath($newSiteNodePath);
             }
         }
         $site->setNodeName($newSiteNodeName);
         $this->nodeDataRepository->persistEntities();
     }
     $this->siteRepository->update($site);
     $this->addFlashMessage('The site "%s" has been updated.', 'Update', null, array(htmlspecialchars($site->getName())), 1412371798);
     $this->unsetLastVisitedNodeAndRedirect('index');
 }
 /**
  * Generate missing URI path segments
  *
  * This generates URI path segment properties for all document nodes which don't have
  * a path segment set yet.
  *
  * @param string $workspaceName
  * @param boolean $dryRun
  * @return void
  */
 public function generateUriPathSegments($workspaceName, $dryRun)
 {
     $baseContext = $this->createContext($workspaceName, []);
     $baseContextSitesNode = $baseContext->getNode(SiteService::SITES_ROOT_PATH);
     if (!$baseContextSitesNode) {
         $this->output->outputLine('<error>Could not find "' . SiteService::SITES_ROOT_PATH . '" root node</error>');
         return;
     }
     $baseContextSiteNodes = $baseContextSitesNode->getChildNodes();
     if ($baseContextSiteNodes === []) {
         $this->output->outputLine('<error>Could not find any site nodes in "' . SiteService::SITES_ROOT_PATH . '" root node</error>');
         return;
     }
     foreach ($this->dimensionCombinator->getAllAllowedCombinations() as $dimensionCombination) {
         $flowQuery = new FlowQuery($baseContextSiteNodes);
         $siteNodes = $flowQuery->context(['dimensions' => $dimensionCombination, 'targetDimensions' => []])->get();
         if (count($siteNodes) > 0) {
             $this->output->outputLine('Checking for nodes with missing URI path segment in dimension "%s"', array(trim(NodePaths::generateContextPath('', '', $dimensionCombination), '@;')));
             foreach ($siteNodes as $siteNode) {
                 $this->generateUriPathSegmentsForNode($siteNode, $dryRun);
             }
         }
     }
     $this->persistenceManager->persistAll();
 }
 /**
  * Moves this node into the given node
  *
  * @param NodeInterface $referenceNode
  * @return void
  * @throws NodeExistsException
  * @throws NodeException
  * @throws NodeConstraintException
  * @api
  */
 public function moveInto(NodeInterface $referenceNode)
 {
     if ($referenceNode === $this || $referenceNode === $this->getParent()) {
         return;
     }
     if ($this->getPath() === '/') {
         throw new NodeException('The root node cannot be moved.', 1346769001);
     }
     if ($referenceNode !== $this->getParent() && $referenceNode->getNode($this->getName()) !== null) {
         throw new NodeExistsException('Node with path "' . $this->getName() . '" already exists.', 1292503470);
     }
     if (!$referenceNode->willChildNodeBeAutoCreated($this->getName()) && !$referenceNode->isNodeTypeAllowedAsChildNode($this->getNodeType())) {
         throw new NodeConstraintException('Cannot move ' . $this->__toString() . ' into ' . $referenceNode->__toString(), 1404648124);
     }
     $this->emitBeforeNodeMove($this, $referenceNode, NodeDataRepository::POSITION_LAST);
     $this->setPath(NodePaths::addNodePathSegment($referenceNode->getPath(), $this->getName()));
     $this->nodeDataRepository->persistEntities();
     $this->nodeDataRepository->setNewIndex($this->nodeData, NodeDataRepository::POSITION_LAST);
     $this->context->getFirstLevelNodeCache()->flush();
     $this->emitAfterNodeMove($this, $referenceNode, NodeDataRepository::POSITION_LAST);
     $this->emitNodeUpdated($this);
 }
 /**
  * Find all node data in a path matching the given workspace hierarchy
  *
  * Internal method, used by Node::setPath
  *
  * @param string $path
  * @param Workspace $workspace
  * @param boolean $includeRemovedNodes Should removed nodes be included in the result (defaults to FALSE)
  * @param boolean $recursive
  * @return array<NodeData> Node data reduced by workspace but with all existing content dimension variants, includes removed nodes
  */
 public function findByPathWithoutReduce($path, Workspace $workspace, $includeRemovedNodes = false, $recursive = false)
 {
     $path = strtolower($path);
     $workspaces = array();
     while ($workspace !== null) {
         $workspaces[] = $workspace;
         $workspace = $workspace->getBaseWorkspace();
     }
     $queryBuilder = $this->createQueryBuilder($workspaces);
     $this->addPathConstraintToQueryBuilder($queryBuilder, $path, $recursive);
     $query = $queryBuilder->getQuery();
     $foundNodes = $query->getResult();
     // Consider materialized, but not yet persisted nodes
     foreach ($this->addedNodes as $addedNode) {
         if (($addedNode->getPath() === $path || $recursive && NodePaths::isSubPathOf($path, $addedNode->getPath())) && in_array($addedNode->getWorkspace(), $workspaces)) {
             $foundNodes[] = $addedNode;
         }
     }
     $foundNodes = $this->reduceNodeVariantsByWorkspaces($foundNodes, $workspaces);
     if ($includeRemovedNodes === false) {
         $foundNodes = $this->filterRemovedNodes($foundNodes, false);
     }
     return $foundNodes;
 }
 /**
  * If the node is not found, we *first* want to figure out whether the node exists in other dimensions or is really non-existent
  *
  * @param $identifier
  * @param ContentContext $context
  * @return void
  */
 protected function addExistingNodeVariantInformationToResponse($identifier, ContentContext $context)
 {
     $nodeVariants = $context->getNodeVariantsByIdentifier($identifier);
     if (count($nodeVariants) > 0) {
         $this->response->setHeader('X-Neos-Node-Exists-In-Other-Dimensions', true);
         // If the node exists in another dimension, we want to know how many nodes in the rootline are also missing for the target
         // dimension. This is needed in the UI to tell the user if nodes will be materialized recursively upwards in the rootline.
         // To find the node path for the given identifier, we just use the first result. This is a safe assumption at least for
         // "Document" nodes (aggregate=TRUE), because they are always moved in-sync.
         $node = reset($nodeVariants);
         /** @var NodeInterface $node */
         if ($node->getNodeType()->isAggregate()) {
             $pathSegmentsToSites = NodePaths::getPathDepth(SiteService::SITES_ROOT_PATH);
             $pathSegmentsToNodeVariant = NodePaths::getPathDepth($node->getPath());
             // Segments between the sites root "/sites" and the node variant (minimum 1)
             $pathSegments = $pathSegmentsToNodeVariant - $pathSegmentsToSites;
             // Nodes between (and including) the site root node and the node variant (minimum 1)
             $siteNodePath = NodePaths::addNodePathSegment(SiteService::SITES_ROOT_PATH, $context->getCurrentSite()->getNodeName());
             $nodes = $context->getNodesOnPath($siteNodePath, $node->getPath());
             $missingNodesOnRootline = $pathSegments - count($nodes);
             if ($missingNodesOnRootline > 0) {
                 $this->response->setHeader('X-Neos-Nodes-Missing-On-Rootline', $missingNodesOnRootline);
             }
         }
     }
 }
 /**
  * Creates, adds and returns a child node of this node, without setting default
  * properties or creating subnodes.
  *
  * @param string $name Name of the new node
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeType $nodeType Node type of the new node (optional)
  * @param string $identifier The identifier of the node, unique within the workspace, optional(!)
  * @param \TYPO3\TYPO3CR\Domain\Model\Workspace $workspace
  * @param array $dimensions An array of dimension name to dimension values
  * @throws NodeExistsException if a node with this path already exists.
  * @throws \InvalidArgumentException if the node name is not accepted.
  * @return \TYPO3\TYPO3CR\Domain\Model\NodeData
  */
 public function createSingleNodeData($name, NodeType $nodeType = null, $identifier = null, Workspace $workspace = null, array $dimensions = null)
 {
     if (!is_string($name) || preg_match(NodeInterface::MATCH_PATTERN_NAME, $name) !== 1) {
         throw new \InvalidArgumentException('Invalid node name "' . $name . '" (a node name must only contain lowercase characters, numbers and the "-" sign).', 1292428697);
     }
     $nodeWorkspace = $workspace ?: $this->workspace;
     $newPath = NodePaths::addNodePathSegment($this->path, $name);
     if ($this->nodeDataRepository->findOneByPath($newPath, $nodeWorkspace, $dimensions, null) !== null) {
         throw new NodeExistsException(sprintf('Node with path "' . $newPath . '" already exists in workspace %s and given dimensions %s.', $nodeWorkspace->getName(), var_export($dimensions, true)), 1292503471);
     }
     $newNodeData = new NodeData($newPath, $nodeWorkspace, $identifier, $dimensions);
     if ($nodeType !== null) {
         $newNodeData->setNodeType($nodeType);
     }
     $this->nodeDataRepository->setNewIndex($newNodeData, NodeDataRepository::POSITION_LAST);
     return $newNodeData;
 }
 /**
  * @param string $path an absolute or relative node path which possibly contains context information, for example "/sites/somesite/the/node/path@some-workspace"
  * @return string the same path without context information
  */
 protected function removeContextFromPath($path)
 {
     if ($path === '' || NodePaths::isContextPath($path) === FALSE) {
         return $path;
     }
     try {
         $nodePathAndContext = NodePaths::explodeContextPath($path);
         return $nodePathAndContext['nodePath'];
     } catch (\InvalidArgumentException $exception) {
     }
     return NULL;
 }
 /**
  * Converts the specified $source into a Node.
  *
  * If $source is a UUID it is expected to refer to the identifier of a NodeData record of the "live" workspace
  *
  * Otherwise $source has to be a valid node path:
  *
  * The node path must be an absolute context node path and can be specified as a string or as an array item with the
  * key "__contextNodePath". The latter case is for updating existing nodes.
  *
  * This conversion method does not support / allow creation of new nodes because new nodes should be created through
  * the createNode() method of an existing reference node.
  *
  * Also note that the context's "current node" is not affected by this object converter, you will need to set it to
  * whatever node your "current" node is, if any.
  *
  * All elements in the source array which start with two underscores (like __contextNodePath) are specially treated
  * by this converter.
  *
  * All elements in the source array which start with a *single underscore (like _hidden) are *directly* set on the Node
  * object.
  *
  * All other elements, not being prefixed with underscore, are properties of the node.
  *
  * @param string|array $source Either a string or array containing the absolute context node path which identifies the node. For example "/sites/mysitecom/homepage/about@user-admin"
  * @param string $targetType not used
  * @param array $subProperties not used
  * @param PropertyMappingConfigurationInterface $configuration
  * @return mixed An object or \TYPO3\Flow\Error\Error if the input format is not supported or could not be converted for other reasons
  * @throws NodeException
  */
 public function convertFrom($source, $targetType = null, array $subProperties = array(), PropertyMappingConfigurationInterface $configuration = null)
 {
     if (is_string($source)) {
         $source = array('__contextNodePath' => $source);
     }
     if (!is_array($source) || !isset($source['__contextNodePath'])) {
         return new Error('Could not convert ' . gettype($source) . ' to Node object, a valid absolute context node path as a string or array is expected.', 1302879936);
     }
     try {
         $nodePathAndContext = NodePaths::explodeContextPath($source['__contextNodePath']);
         $nodePath = $nodePathAndContext['nodePath'];
         $workspaceName = $nodePathAndContext['workspaceName'];
         $dimensions = $nodePathAndContext['dimensions'];
     } catch (\InvalidArgumentException $exception) {
         return new Error('Could not convert array to Node object because the node path was invalid.', 1285162903);
     }
     $context = $this->contextFactory->create($this->prepareContextProperties($workspaceName, $configuration, $dimensions));
     $workspace = $context->getWorkspace(false);
     if (!$workspace) {
         return new Error(sprintf('Could not convert the given source to Node object because the workspace "%s" as specified in the context node path does not exist.', $workspaceName), 1383577859);
     }
     $node = $context->getNode($nodePath);
     if (!$node) {
         return new Error(sprintf('Could not convert array to Node object because the node "%s" does not exist.', $nodePath), 1370502328);
     }
     if (isset($source['_nodeType']) && $source['_nodeType'] !== $node->getNodeType()->getName()) {
         if ($context->getWorkspace()->getName() === 'live') {
             throw new NodeException('Could not convert the node type in live workspace', 1429989736);
         }
         $oldNodeType = $node->getNodeType();
         $targetNodeType = $this->nodeTypeManager->getNodeType($source['_nodeType']);
         $node->setNodeType($targetNodeType);
         $this->nodeService->setDefaultValues($node);
         $this->nodeService->cleanUpAutoCreatedChildNodes($node, $oldNodeType);
         $this->nodeService->createChildNodes($node);
     }
     unset($source['_nodeType']);
     $this->setNodeProperties($node, $node->getNodeType(), $source, $context, $configuration);
     return $node;
 }
 /**
  * Imports one or multiple sites from the XML file at $pathAndFilename
  *
  * @param string $pathAndFilename
  * @return Site The imported site
  * @throws UnknownPackageException|InvalidPackageStateException|NeosException
  */
 public function importFromFile($pathAndFilename)
 {
     /** @var Site $importedSite */
     $site = null;
     $xmlReader = new \XMLReader();
     $xmlReader->open($pathAndFilename, null, LIBXML_PARSEHUGE);
     if ($this->workspaceRepository->findOneByName('live') === null) {
         $this->workspaceRepository->add(new Workspace('live'));
         $this->persistenceManager->persistAll();
     }
     while ($xmlReader->read()) {
         if ($xmlReader->nodeType != \XMLReader::ELEMENT || $xmlReader->name !== 'site') {
             continue;
         }
         $isLegacyFormat = $xmlReader->getAttribute('nodeName') !== null && $xmlReader->getAttribute('state') === null && $xmlReader->getAttribute('siteResourcesPackageKey') === null;
         if ($isLegacyFormat) {
             $site = $this->legacySiteImportService->importSitesFromFile($pathAndFilename);
             $this->emitSiteImported($site);
             return $site;
         }
         $site = $this->getSiteByNodeName($xmlReader->getAttribute('siteNodeName'));
         $site->setName($xmlReader->getAttribute('name'));
         $site->setState((int) $xmlReader->getAttribute('state'));
         $siteResourcesPackageKey = $xmlReader->getAttribute('siteResourcesPackageKey');
         if (!$this->packageManager->isPackageAvailable($siteResourcesPackageKey)) {
             throw new UnknownPackageException(sprintf('Package "%s" specified in the XML as site resources package does not exist.', $siteResourcesPackageKey), 1303891443);
         }
         if (!$this->packageManager->isPackageActive($siteResourcesPackageKey)) {
             throw new InvalidPackageStateException(sprintf('Package "%s" specified in the XML as site resources package is not active.', $siteResourcesPackageKey), 1303898135);
         }
         $site->setSiteResourcesPackageKey($siteResourcesPackageKey);
         $rootNode = $this->contextFactory->create()->getRootNode();
         // We fetch the workspace to be sure it's known to the persistence manager and persist all
         // so the workspace and site node are persisted before we import any nodes to it.
         $rootNode->getContext()->getWorkspace();
         $this->persistenceManager->persistAll();
         $sitesNode = $rootNode->getNode(SiteService::SITES_ROOT_PATH);
         if ($sitesNode === null) {
             $sitesNode = $rootNode->createNode(NodePaths::getNodeNameFromPath(SiteService::SITES_ROOT_PATH));
         }
         $this->nodeImportService->import($xmlReader, $sitesNode->getPath(), dirname($pathAndFilename) . '/Resources');
     }
     if ($site === null) {
         throw new NeosException(sprintf('The XML file did not contain a valid site node.'), 1418999522);
     }
     $this->emitSiteImported($site);
     return $site;
 }
 /**
  * Generate missing URI path segments
  *
  * This generates URI path segment properties for all document nodes which don't have
  * a path segment set yet.
  *
  * @param string $workspaceName
  * @param boolean $dryRun
  * @return void
  */
 public function generateUriPathSegments($workspaceName, $dryRun)
 {
     $baseContext = $this->createContext($workspaceName, []);
     $baseContextSiteNodes = $baseContext->getNode('/sites')->getChildNodes();
     if ($baseContextSiteNodes === []) {
         return;
     }
     foreach ($this->dimensionCombinator->getAllAllowedCombinations() as $dimensionCombination) {
         $flowQuery = new FlowQuery($baseContextSiteNodes);
         $siteNodes = $flowQuery->context(['dimensions' => $dimensionCombination, 'targetDimensions' => []])->get();
         if (count($siteNodes) > 0) {
             $this->output->outputLine('Searching for nodes with missing URI path segment in dimension "%s"', array(trim(NodePaths::generateContextPath('', '', $dimensionCombination), '@;')));
             foreach ($siteNodes as $siteNode) {
                 $this->generateUriPathSegmentsForNode($siteNode, $dryRun);
             }
         }
     }
 }
 /**
  * Generate possible node name. When an idealNodeName is given then this is put into a valid format for a node name,
  * otherwise a random node name in the form "node-alphanumeric" is generated.
  *
  * @param string $idealNodeName
  * @return string
  */
 protected function generatePossibleNodeName($idealNodeName = null)
 {
     if ($idealNodeName !== null) {
         $possibleNodeName = \TYPO3\TYPO3CR\Utility::renderValidNodeName($idealNodeName);
     } else {
         $possibleNodeName = NodePaths::generateRandomNodeName();
     }
     return $possibleNodeName;
 }
 /**
  * Imports one or multiple sites from the XML file at $pathAndFilename
  *
  * @param string $pathAndFilename
  * @return Site The imported site or NULL if not successful
  * @throws UnknownPackageException
  * @throws InvalidPackageStateException
  */
 public function importSitesFromFile($pathAndFilename)
 {
     $contentContext = $this->createContext();
     $sitesXmlString = $this->loadSitesXml($pathAndFilename);
     if (defined('LIBXML_PARSEHUGE')) {
         $options = LIBXML_PARSEHUGE;
     } else {
         $options = 0;
     }
     $site = null;
     $sitesXml = new \SimpleXMLElement($sitesXmlString, $options);
     foreach ($sitesXml->site as $siteXml) {
         $site = $this->getSiteByNodeName((string) $siteXml['nodeName']);
         if ((string) $siteXml->properties->name !== '') {
             $site->setName((string) $siteXml->properties->name);
         }
         $site->setState((int) $siteXml->properties->state);
         $siteResourcesPackageKey = (string) $siteXml->properties->siteResourcesPackageKey;
         if (!$this->packageManager->isPackageAvailable($siteResourcesPackageKey)) {
             throw new UnknownPackageException(sprintf('Package "%s" specified in the XML as site resources package does not exist.', $siteResourcesPackageKey), 1303891443);
         }
         if (!$this->packageManager->isPackageActive($siteResourcesPackageKey)) {
             throw new InvalidPackageStateException(sprintf('Package "%s" specified in the XML as site resources package is not active.', $siteResourcesPackageKey), 1303898135);
         }
         $site->setSiteResourcesPackageKey($siteResourcesPackageKey);
         $rootNode = $contentContext->getRootNode();
         $sitesNode = $rootNode->getNode(SiteService::SITES_ROOT_PATH);
         if ($sitesNode === null) {
             $sitesNode = $rootNode->createSingleNode(NodePaths::getNodeNameFromPath(SiteService::SITES_ROOT_PATH));
         }
         // We fetch the workspace to be sure it's known to the persistence manager and persist all
         // so the workspace and site node are persisted before we import any nodes to it.
         $rootNode->getContext()->getWorkspace();
         $this->persistenceManager->persistAll();
         if ($siteXml['type'] === null) {
             $this->upgradeLegacySiteXml($siteXml, $site);
         }
         $this->importNode($siteXml, $sitesNode);
     }
     return $site;
 }
 /**
  * @param string $path an absolute or relative node path which possibly contains context information, for example "/sites/somesite/the/node/path@some-workspace"
  * @return string the same path without context information
  */
 protected function removeContextFromPath($path)
 {
     if ($path === '' || NodePaths::isContextPath($path) === false) {
         return $path;
     }
     try {
         $nodePathAndContext = NodePaths::explodeContextPath($path);
         // This is a workaround as we potentially prepend the context path with "/" in buildContextFromRequestPath to create a valid context path,
         // the code in this class expects an empty nodePath though for the site node, so we remove it again at this point.
         return $nodePathAndContext['nodePath'] === '/' ? '' : $nodePathAndContext['nodePath'];
     } catch (\InvalidArgumentException $exception) {
     }
     return null;
 }
 /**
  * Move $node before, into or after $targetNode
  *
  * @param NodeInterface $node
  * @param NodeInterface $targetNode
  * @param string $position where the node should be added (allowed: before, into, after)
  * @return NodeInterface The same node given as first argument
  * @throws NodeException
  */
 public function move(NodeInterface $node, NodeInterface $targetNode, $position)
 {
     if (!in_array($position, array('before', 'into', 'after'), true)) {
         throw new NodeException('The position should be one of the following: "before", "into", "after".', 1296132542);
     }
     $designatedParentNode = $this->getDesignatedParentNode($targetNode, $position);
     // If we stay inside the same parent we basically just reorder, no rename needed or wanted.
     if ($designatedParentNode !== $node->getParent()) {
         $designatedNodePath = NodePaths::addNodePathSegment($designatedParentNode->getPath(), $node->getName());
         if ($this->nodeService->nodePathAvailableForNode($designatedNodePath, $node) === false) {
             $nodeName = $this->nodeService->generateUniqueNodeName($designatedParentNode->getPath(), $node->getName());
             if ($nodeName !== $node->getName()) {
                 // FIXME: This can be removed if $node->move* supports additionally changing the name of the node.
                 $node->setName($nodeName);
             }
         }
     }
     switch ($position) {
         case 'before':
             $node->moveBefore($targetNode);
             break;
         case 'into':
             $node->moveInto($targetNode);
             break;
         case 'after':
             $node->moveAfter($targetNode);
     }
     return $node;
 }
 /**
  * Create a new site
  *
  * This command allows to create a blank site with just a single empty document in the default dimension.
  * The name of the site, the packageKey must be specified.
  *
  * If no ``nodeType`` option is specified the command will use `TYPO3.Neos.NodeTypes:Page` as fallback. The node type
  * must already exists and have the superType ``TYPO3.Neos:Document``.
  *
  * If no ``nodeName` option is specified the command will create a unique node-name from the name of the site.
  * If a node name is given it has to be unique for the setup.
  *
  * If the flag ``activate` is set to false new site will not be activated.
  *
  * @param string $name The name of the site
  * @param string $packageKey The site package
  * @param string $nodeType The node type to use for the site node. (Default = TYPO3.Neos.NodeTypes:Page)
  * @param string $nodeName The name of the site node. If no nodeName is given it will be determined from the siteName.
  * @param boolean $inactive The new site is not activated immediately (default = false).
  * @return void
  */
 public function createCommand($name, $packageKey, $nodeType = 'TYPO3.Neos.NodeTypes:Page', $nodeName = null, $inactive = false)
 {
     if ($nodeName === null) {
         $nodeName = $this->nodeService->generateUniqueNodeName(SiteService::SITES_ROOT_PATH, $name);
     }
     if ($this->siteRepository->findOneByNodeName($nodeName)) {
         $this->outputLine('<error>A site with siteNodeName "%s" already exists</error>', [$nodeName]);
         $this->quit(1);
     }
     if ($this->packageManager->isPackageAvailable($packageKey) === false) {
         $this->outputLine('<error>Could not find package "%s"</error>', [$packageKey]);
         $this->quit(1);
     }
     $siteNodeType = $this->nodeTypeManager->getNodeType($nodeType);
     if ($siteNodeType === null || $siteNodeType->getName() === 'TYPO3.Neos:FallbackNode') {
         $this->outputLine('<error>The given node type "%s" was not found</error>', [$nodeType]);
         $this->quit(1);
     }
     if ($siteNodeType->isOfType('TYPO3.Neos:Document') === false) {
         $this->outputLine('<error>The given node type "%s" is not based on the superType "%s"</error>', [$nodeType, 'TYPO3.Neos:Document']);
         $this->quit(1);
     }
     $rootNode = $this->nodeContextFactory->create()->getRootNode();
     // We fetch the workspace to be sure it's known to the persistence manager and persist all
     // so the workspace and site node are persisted before we import any nodes to it.
     $rootNode->getContext()->getWorkspace();
     $this->persistenceManager->persistAll();
     $sitesNode = $rootNode->getNode(SiteService::SITES_ROOT_PATH);
     if ($sitesNode === null) {
         $sitesNode = $rootNode->createNode(NodePaths::getNodeNameFromPath(SiteService::SITES_ROOT_PATH));
     }
     $siteNode = $sitesNode->createNode($nodeName, $siteNodeType);
     $siteNode->setProperty('title', $name);
     $site = new Site($nodeName);
     $site->setSiteResourcesPackageKey($packageKey);
     $site->setState($inactive ? Site::STATE_OFFLINE : Site::STATE_ONLINE);
     $site->setName($name);
     $this->siteRepository->add($site);
     $this->outputLine('Successfully created site "%s" with siteNode "%s", type "%s", packageKey "%s" and state "%s"', [$name, $nodeName, $nodeType, $packageKey, $inactive ? 'offline' : 'online']);
 }
 /**
  * Get the name of this node template.
  *
  * If a name has been set using setName(), it is returned. If not, but the
  * template has a (non-empty) title property, this property is used to
  * generate a valid name. As a last resort a random name is returned (in
  * the form "name-XXXXX").
  *
  * @return string
  * @api
  */
 public function getName()
 {
     if ($this->name !== null) {
         return $this->name;
     }
     return NodePaths::generateRandomNodeName();
 }
 /**
  * Renders the URI to a given node instance or -path.
  *
  * @param ControllerContext $controllerContext
  * @param mixed $node A node object or a string node path, if a relative path is provided the baseNode argument is required
  * @param NodeInterface $baseNode
  * @param string $format Format to use for the URL, for example "html" or "json"
  * @param boolean $absolute If set, an absolute URI is rendered
  * @param array $arguments Additional arguments to be passed to the UriBuilder (for example pagination parameters)
  * @param string $section
  * @param boolean $addQueryString If set, the current query parameters will be kept in the URI
  * @param array $argumentsToBeExcludedFromQueryString arguments to be removed from the URI. Only active if $addQueryString = TRUE
  * @param boolean $resolveShortcuts INTERNAL Parameter - if FALSE, shortcuts are not redirected to their target. Only needed on rare backend occasions when we want to link to the shortcut itself.
  * @return string The rendered URI
  * @throws \InvalidArgumentException if the given node/baseNode is not valid
  * @throws NeosException if no URI could be resolved for the given node
  */
 public function createNodeUri(ControllerContext $controllerContext, $node = null, NodeInterface $baseNode = null, $format = null, $absolute = false, array $arguments = array(), $section = '', $addQueryString = false, array $argumentsToBeExcludedFromQueryString = array(), $resolveShortcuts = true)
 {
     $this->lastLinkedNode = null;
     if (!($node instanceof NodeInterface || is_string($node) || $baseNode instanceof NodeInterface)) {
         throw new \InvalidArgumentException('Expected an instance of NodeInterface or a string for the node argument, or alternatively a baseNode argument.', 1373101025);
     }
     if (is_string($node)) {
         $nodeString = $node;
         if ($nodeString === '') {
             throw new NeosException(sprintf('Empty strings can not be resolved to nodes.', $nodeString), 1415709942);
         }
         preg_match(NodeInterface::MATCH_PATTERN_CONTEXTPATH, $nodeString, $matches);
         if (isset($matches['WorkspaceName']) && $matches['WorkspaceName'] !== '') {
             $node = $this->propertyMapper->convert($nodeString, 'TYPO3\\TYPO3CR\\Domain\\Model\\NodeInterface');
         } else {
             if ($baseNode === null) {
                 throw new NeosException('The baseNode argument is required for linking to nodes with a relative path.', 1407879905);
             }
             /** @var ContentContext $contentContext */
             $contentContext = $baseNode->getContext();
             $normalizedPath = $this->nodeService->normalizePath($nodeString, $baseNode->getPath(), $contentContext->getCurrentSiteNode()->getPath());
             $node = $contentContext->getNode($normalizedPath);
         }
         if (!$node instanceof NodeInterface) {
             throw new NeosException(sprintf('The string "%s" could not be resolved to an existing node.', $nodeString), 1415709674);
         }
     } elseif (!$node instanceof NodeInterface) {
         $node = $baseNode;
     }
     if (!$node instanceof NodeInterface) {
         throw new NeosException(sprintf('Node must be an instance of NodeInterface or string, given "%s".', gettype($node)), 1414772029);
     }
     $this->lastLinkedNode = $node;
     if ($resolveShortcuts === true) {
         $resolvedNode = $this->nodeShortcutResolver->resolveShortcutTarget($node);
     } else {
         // this case is only relevant in extremely rare occasions in the Neos Backend, when we want to generate
         // a link towards the *shortcut itself*, and not to its target.
         $resolvedNode = $node;
     }
     if (is_string($resolvedNode)) {
         return $resolvedNode;
     }
     if (!$resolvedNode instanceof NodeInterface) {
         throw new NeosException(sprintf('Could not resolve shortcut target for node "%s"', $node->getPath()), 1414771137);
     }
     /** @var ActionRequest $request */
     $request = $controllerContext->getRequest()->getMainRequest();
     $uriBuilder = clone $controllerContext->getUriBuilder();
     $uriBuilder->setRequest($request);
     $uri = $uriBuilder->reset()->setSection($section)->setArguments($arguments)->setAddQueryString($addQueryString)->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString)->setFormat($format ?: $request->getFormat())->uriFor('show', array('node' => $resolvedNode), 'Frontend\\Node', 'TYPO3.Neos');
     $siteNode = $resolvedNode->getContext()->getCurrentSiteNode();
     if (NodePaths::isSubPathOf($siteNode->getPath(), $resolvedNode->getPath())) {
         /** @var Site $site */
         $site = $resolvedNode->getContext()->getCurrentSite();
     } else {
         $nodePath = NodePaths::getRelativePathBetween(SiteService::SITES_ROOT_PATH, $resolvedNode->getPath());
         list($siteNodeName) = explode('/', $nodePath);
         $site = $this->siteRepository->findOneByNodeName($siteNodeName);
     }
     if ($site->hasActiveDomains()) {
         $requestUriHost = $request->getHttpRequest()->getBaseUri()->getHost();
         $activeHostPatterns = $site->getActiveDomains()->map(function ($domain) {
             return $domain->getHostPattern();
         })->toArray();
         if (!in_array($requestUriHost, $activeHostPatterns, true)) {
             $uri = $this->createSiteUri($controllerContext, $site) . '/' . ltrim($uri, '/');
         } elseif ($absolute === true) {
             $uri = $request->getHttpRequest()->getBaseUri() . ltrim($uri, '/');
         }
     } elseif ($absolute === true) {
         $uri = $request->getHttpRequest()->getBaseUri() . ltrim($uri, '/');
     }
     return $uri;
 }
 /**
  * Returns the node of the current site.
  *
  * @return NodeInterface
  */
 public function getCurrentSiteNode()
 {
     if ($this->currentSite !== null && $this->currentSiteNode === null) {
         $siteNodePath = NodePaths::addNodePathSegment(SiteService::SITES_ROOT_PATH, $this->currentSite->getNodeName());
         $this->currentSiteNode = $this->getNode($siteNodePath);
         if (!$this->currentSiteNode instanceof NodeInterface) {
             $this->systemLogger->log(sprintf('Warning: %s::getCurrentSiteNode() couldn\'t load the site node for path "%s" in workspace "%s". This is probably due to a missing baseworkspace for the workspace of the current user.', __CLASS__, $siteNodePath, $this->workspaceName), LOG_WARNING);
         }
     }
     return $this->currentSiteNode;
 }
 /**
  * Normalizes the given node path to a reference path and returns an absolute path.
  *
  * You should usually use \TYPO3\TYPO3CR\Domain\Service\NodeService::normalizePath()  because functionality could be overloaded,
  * this is here only for low level operations.
  *
  *
  * @see \TYPO3\TYPO3CR\Domain\Service\NodeService::normalizePath()
  * @param $path
  * @param string $referencePath
  * @return string
  */
 public static function normalizePath($path, $referencePath = NULL)
 {
     if ($path === '.') {
         return $referencePath;
     }
     if (!is_string($path)) {
         throw new \InvalidArgumentException(sprintf('An invalid node path was specified: is of type %s but a string is expected.', gettype($path)), 1357832901);
     }
     if (strpos($path, '//') !== FALSE) {
         throw new \InvalidArgumentException('Paths must not contain two consecutive slashes.', 1291371910);
     }
     if ($path[0] === '/') {
         $absolutePath = $path;
     } else {
         $absolutePath = NodePaths::addNodePathSegment($referencePath, $path);
     }
     $normalizedPath = NodePaths::replaceRelativePathElements($absolutePath);
     return strtolower($normalizedPath);
 }