/**
  * Repair inconsistent nodes
  *
  * This command analyzes and repairs the node tree structure and individual nodes
  * based on the current node type configuration.
  *
  * The following checks will be performed:
  *
  * {pluginDescriptions}
  * <b>Examples:</b>
  *
  * ./flow node:repair
  *
  * ./flow node:repair --node-type TYPO3.Neos.NodeTypes:Page
  *
  * @param string $nodeType Node type name, if empty update all declared node types
  * @param string $workspace Workspace name, default is 'live'
  * @param boolean $dryRun Don't do anything, but report actions
  * @param boolean $cleanup If FALSE, cleanup tasks are skipped
  * @return void
  */
 public function repairCommand($nodeType = null, $workspace = 'live', $dryRun = false, $cleanup = true)
 {
     $this->pluginConfigurations = self::detectPlugins($this->objectManager);
     if ($this->workspaceRepository->countByName($workspace) === 0) {
         $this->outputLine('Workspace "%s" does not exist', array($workspace));
         exit(1);
     }
     if ($nodeType !== null) {
         if ($this->nodeTypeManager->hasNodeType($nodeType)) {
             $nodeType = $this->nodeTypeManager->getNodeType($nodeType);
         } else {
             $this->outputLine('Node type "%s" does not exist', array($nodeType));
             exit(1);
         }
     }
     if ($dryRun) {
         $this->outputLine('Dry run, not committing any changes.');
     }
     foreach ($this->pluginConfigurations as $pluginConfiguration) {
         /** @var NodeCommandControllerPluginInterface $plugin */
         $plugin = $pluginConfiguration['object'];
         $this->outputLine('<b>' . $plugin->getSubCommandShortDescription('repair') . '</b>');
         $this->outputLine();
         $plugin->invokeSubCommand('repair', $this->output, $nodeType, $workspace, $dryRun, $cleanup);
         $this->outputLine();
     }
     $this->outputLine('Node repair finished.');
 }
 /**
  * Render the label for the given $nodeTypeName
  *
  * @param string $nodeTypeName
  * @throws \TYPO3\TYPO3CR\Exception\NodeTypeNotFoundException
  * @return string
  */
 public function labelForNodeType($nodeTypeName)
 {
     if (!$this->nodeTypeManager->hasNodeType($nodeTypeName)) {
         $explodedNodeTypeName = explode(':', $nodeTypeName);
         return end($explodedNodeTypeName);
     }
     $nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName);
     return $nodeType->getLabel();
 }
 /**
  * Shows a list of nodes
  *
  * @param string $searchTerm An optional search term used for filtering the list of nodes
  * @param string $workspaceName Name of the workspace to search in, "live" by default
  * @param array $dimensions Optional list of dimensions and their values which should be used for querying
  * @param array $nodeTypes A list of node types the list should be filtered by
  * @param NodeInterface $contextNode a node to use as context for the search
  * @return string
  */
 public function indexAction($searchTerm = '', $workspaceName = 'live', array $dimensions = array(), array $nodeTypes = array('TYPO3.Neos:Document'), NodeInterface $contextNode = null)
 {
     $searchableNodeTypeNames = array();
     foreach ($nodeTypes as $nodeTypeName) {
         if (!$this->nodeTypeManager->hasNodeType($nodeTypeName)) {
             $this->throwStatus(400, sprintf('Unknown node type "%s"', $nodeTypeName));
         }
         $searchableNodeTypeNames[$nodeTypeName] = $nodeTypeName;
         /** @var NodeType $subNodeType */
         foreach ($this->nodeTypeManager->getSubNodeTypes($nodeTypeName, false) as $subNodeTypeName => $subNodeType) {
             $searchableNodeTypeNames[$subNodeTypeName] = $subNodeTypeName;
         }
     }
     $contentContext = $this->createContentContext($workspaceName, $dimensions);
     $nodes = $this->nodeSearchService->findByProperties($searchTerm, $searchableNodeTypeNames, $contentContext, $contextNode);
     $this->view->assign('nodes', $nodes);
 }
 /**
  * Detects and retrieves the NodeType of the given $nodeXml
  *
  * @param \SimpleXMLElement $nodeXml
  * @return NodeType
  * @throws \TYPO3\Neos\Domain\Exception
  */
 protected function parseNodeType(\SimpleXMLElement $nodeXml)
 {
     $nodeTypeName = (string) $nodeXml['type'];
     if ($this->nodeTypeManager->hasNodeType($nodeTypeName)) {
         $nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName);
         if ($nodeType->isAbstract()) {
             throw new DomainException(sprintf('The node type "%s" is marked as abstract and cannot be assigned to nodes.', $nodeTypeName), 1386590052);
         }
         return $nodeType;
     }
     return $this->nodeTypeManager->createNodeType($nodeTypeName);
 }
 /**
  * Reorder child nodes for the given node type
  *
  * @param NodeType $nodeType
  * @param string $workspaceName
  * @param boolean $dryRun
  * @return void
  */
 protected function reorderChildNodesByNodeType(NodeType $nodeType, $workspaceName, $dryRun)
 {
     $nodeTypes = $this->nodeTypeManager->getSubNodeTypes($nodeType->getName(), false);
     $nodeTypes[$nodeType->getName()] = $nodeType;
     if ($this->nodeTypeManager->hasNodeType((string) $nodeType)) {
         $nodeType = $this->nodeTypeManager->getNodeType((string) $nodeType);
         $nodeTypeNames[$nodeType->getName()] = $nodeType;
     } else {
         $this->output->outputLine('Node type "%s" does not exist', array((string) $nodeType));
         exit(1);
     }
     /** @var $nodeType NodeType */
     foreach ($nodeTypes as $nodeTypeName => $nodeType) {
         $childNodes = $nodeType->getAutoCreatedChildNodes();
         if ($childNodes === array()) {
             continue;
         }
         foreach ($this->getNodeDataByNodeTypeAndWorkspace($nodeTypeName, $workspaceName) as $nodeData) {
             /** @var NodeInterface $childNodeBefore */
             $childNodeBefore = null;
             $context = $this->nodeFactory->createContextMatchingNodeData($nodeData);
             $node = $this->nodeFactory->createFromNodeData($nodeData, $context);
             if (!$node instanceof NodeInterface) {
                 continue;
             }
             foreach ($childNodes as $childNodeName => $childNodeType) {
                 $childNode = $node->getNode($childNodeName);
                 if ($childNode) {
                     if ($childNodeBefore) {
                         if ($dryRun === false) {
                             if ($childNodeBefore->getIndex() >= $childNode->getIndex()) {
                                 $childNode->moveAfter($childNodeBefore);
                                 $this->output->outputLine('Moved node named "%s" after node named "%s" in "%s"', array($childNodeName, $childNodeBefore->getName(), $node->getPath()));
                             }
                         } else {
                             $this->output->outputLine('Should move node named "%s" after node named "%s" in "%s"', array($childNodeName, $childNodeBefore->getName(), $node->getPath()));
                         }
                     }
                 } else {
                     $this->output->outputLine('Missing child node named "%s" in "%s".', array($childNodeName, $node->getPath()));
                 }
                 $childNodeBefore = $childNode;
             }
         }
     }
 }
 /**
  * If the given node has the property this transformation should work on, this
  * returns TRUE if the given NodeType is registered with the NodeTypeManager and is not abstract.
  *
  * @param NodeData $node
  * @return boolean
  */
 public function isTransformable(NodeData $node)
 {
     return $this->nodeTypeManager->hasNodeType($this->newType) && !$this->nodeTypeManager->getNodeType($this->newType)->isAbstract();
 }
 /**
  * @test
  */
 public function hasNodeTypeReturnsTrueForAbstractNodeTypes()
 {
     $this->assertTrue($this->nodeTypeManager->hasNodeType('TYPO3.TYPO3CR.Testing:ContentObject'));
 }
 /**
  * Exports a single Node into the XML structure
  *
  * @param array $nodeData The node data as an array
  * @param array $nodesStack The stack keeping track of open tags, as passed by exportNodeDataList()
  * @return void The result is written directly into $this->xmlWriter
  */
 protected function exportNodeData(array &$nodeData, array &$nodesStack)
 {
     if ($nodeData['path'] !== '/' && !isset($this->exportedNodePaths[$nodeData['parentPath']])) {
         $this->xmlWriter->writeComment(sprintf('Skipped node with identifier "%s" and path "%s" because of a missing parent path. This is caused by a broken rootline and needs to be fixed with the "node:repair" command.', $nodeData['identifier'], $nodeData['path']));
         return;
     }
     $this->exportedNodePaths[$nodeData['path']] = true;
     if ($nodeData['parentPath'] === '/') {
         $nodeName = substr($nodeData['path'], 1);
     } else {
         $nodeName = substr($nodeData['path'], strlen($nodeData['parentPath']) + 1);
     }
     // is this a variant of currently open node?
     // then close all open nodes until parent is currently open and start new node element
     // else reuse the currently open node element and add a new variant element
     // @todo what about nodes with a different path in some dimension
     $parentNode = end($nodesStack);
     if (!$parentNode || $parentNode['path'] !== $nodeData['path'] || $parentNode['identifier'] !== $nodeData['identifier']) {
         while ($parentNode && $nodeData['parentPath'] !== $parentNode['path']) {
             $this->xmlWriter->endElement();
             array_pop($nodesStack);
             $parentNode = end($nodesStack);
         }
         $nodesStack[] = $nodeData;
         $this->xmlWriter->startElement('node');
         $this->xmlWriter->writeAttribute('identifier', $nodeData['identifier']);
         $this->xmlWriter->writeAttribute('nodeName', $nodeName);
     }
     $this->xmlWriter->startElement('variant');
     if ($nodeData['sortingIndex'] !== null) {
         // the "/" node has no sorting index by default; so we should only write it if it has been set.
         $this->xmlWriter->writeAttribute('sortingIndex', $nodeData['sortingIndex']);
     }
     foreach (array('workspace', 'nodeType', 'version', 'removed', 'hidden', 'hiddenInIndex') as $propertyName) {
         $this->xmlWriter->writeAttribute($propertyName, $nodeData[$propertyName]);
     }
     $this->xmlWriter->startElement('dimensions');
     foreach ($nodeData['dimensionValues'] as $dimensionKey => $dimensionValues) {
         foreach ($dimensionValues as $dimensionValue) {
             $this->xmlWriter->writeElement($dimensionKey, $dimensionValue);
         }
     }
     $this->xmlWriter->endElement();
     foreach (array('accessRoles', 'hiddenBeforeDateTime', 'hiddenAfterDateTime', 'creationDateTime', 'lastModificationDateTime', 'lastPublicationDateTime', 'contentObjectProxy') as $propertyName) {
         $this->writeConvertedElement($nodeData, $propertyName);
     }
     $this->xmlWriter->startElement('properties');
     if ($this->nodeTypeManager->hasNodeType($nodeData['nodeType'])) {
         $nodeType = $this->nodeTypeManager->getNodeType($nodeData['nodeType']);
         foreach ($nodeData['properties'] as $propertyName => $propertyValue) {
             if ($nodeType->hasConfiguration('properties.' . $propertyName)) {
                 $declaredPropertyType = $nodeType->getPropertyType($propertyName);
                 $this->writeConvertedElement($nodeData['properties'], $propertyName, null, $declaredPropertyType);
             }
         }
     } else {
         foreach ($nodeData['properties'] as $propertyName => $propertyValue) {
             $this->writeConvertedElement($nodeData['properties'], $propertyName);
         }
     }
     $this->xmlWriter->endElement();
     // "properties"
     $this->xmlWriter->endElement();
     // "variant"
 }
 /**
  * If the given node has the property this transformation should work on, this
  * returns TRUE if the given NodeType is registered with the NodeTypeManager and is not abstract.
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeData $node
  * @return boolean
  */
 public function isTransformable(\TYPO3\TYPO3CR\Domain\Model\NodeData $node)
 {
     return $this->nodeTypeManager->hasNodeType($this->newType) && !$this->nodeTypeManager->getNodeType($this->newType)->isAbstract();
 }