/** * Get all publishable node context paths for a workspace * * @param Workspace $workspace * @return array */ public function getPublishableNodeInfo(Workspace $workspace) { $publishableNodes = $this->publishingService->getUnpublishedNodes($workspace); $publishableNodes = array_map(function ($node) { if ($documentNode = $this->nodeService->getClosestDocument($node)) { return ['contextPath' => $node->getContextPath(), 'documentContextPath' => $documentNode->getContextPath()]; } }, $publishableNodes); return array_filter($publishableNodes, function ($item) { return (bool) $item; }); }
/** * Discard changes in workspace * * This command discards all modified, created or deleted nodes in the specified workspace. * * @param string $workspace Name of the workspace, for example "user-john" * @param boolean $verbose If enabled, information about individual nodes will be displayed * @param boolean $dryRun If set, only displays which nodes would be discarded, no real changes are committed * @return void */ public function discardCommand($workspace, $verbose = FALSE, $dryRun = FALSE) { $workspaceName = $workspace; $workspace = $this->workspaceRepository->findOneByName($workspaceName); if (!$workspace instanceof Workspace) { $this->outputLine('Workspace "%s" does not exist', array($workspaceName)); $this->quit(1); } try { $nodes = $this->publishingService->getUnpublishedNodes($workspace); } catch (\Exception $exception) { $this->outputLine('An error occurred while fetching unpublished nodes from workspace %s, discard aborted.', array($workspaceName)); $this->quit(1); } $this->outputLine('The workspace %s contains %u unpublished nodes.', array($workspaceName, count($nodes))); foreach ($nodes as $node) { /** @var \TYPO3\TYPO3CR\Domain\Model\NodeInterface $node */ if ($node->getPath() !== '/') { if ($verbose) { $this->outputLine(' ' . $node->getPath()); } if (!$dryRun) { $this->publishingService->discardNode($node); } } } if (!$dryRun) { $this->outputLine('Discarded all nodes in workspace %s', array($workspaceName)); } }
/** * Discards content of the whole workspace * * @param Workspace $workspace * @return void */ public function discardWorkspaceAction(Workspace $workspace) { $unpublishedNodes = $this->publishingService->getUnpublishedNodes($workspace); $this->publishingService->discardNodes($unpublishedNodes); $this->addFlashMessage('Changes in workspace "%s" have been discarded', 'Changes discarded', Message::SEVERITY_OK, array($workspace->getName()), 1412420835); $this->redirect('index'); }
/** * Builds an array of changes for sites in the given workspace * * @param Workspace $selectedWorkspace * @return array */ protected function computeSiteChanges(Workspace $selectedWorkspace) { $siteChanges = []; foreach ($this->publishingService->getUnpublishedNodes($selectedWorkspace) as $node) { /** @var NodeInterface $node */ if (!$node->getNodeType()->isOfType('TYPO3.Neos:ContentCollection')) { $pathParts = explode('/', $node->getPath()); if (count($pathParts) > 2) { $siteNodeName = $pathParts[2]; $q = new FlowQuery([$node]); $document = $q->closest('[instanceof TYPO3.Neos:Document]')->get(0); // $document will be null if we have a broken root line for this node. This actually should never happen, but currently can in some scenarios. if ($document !== null) { $documentPath = implode('/', array_slice(explode('/', $document->getPath()), 3)); $relativePath = str_replace(sprintf(SiteService::SITES_ROOT_PATH . '/%s/%s', $siteNodeName, $documentPath), '', $node->getPath()); if (!isset($siteChanges[$siteNodeName]['siteNode'])) { $siteChanges[$siteNodeName]['siteNode'] = $this->siteRepository->findOneByNodeName($siteNodeName); } $siteChanges[$siteNodeName]['documents'][$documentPath]['documentNode'] = $document; $change = ['node' => $node, 'contentChanges' => $this->renderContentChanges($node)]; if ($node->getNodeType()->isOfType('TYPO3.Neos:Node')) { $change['configuration'] = $node->getNodeType()->getFullConfiguration(); } $siteChanges[$siteNodeName]['documents'][$documentPath]['changes'][$relativePath] = $change; } } } } $liveContext = $this->contextFactory->create(['workspaceName' => 'live']); ksort($siteChanges); foreach ($siteChanges as $siteKey => $site) { foreach ($site['documents'] as $documentKey => $document) { $liveDocumentNode = $liveContext->getNodeByIdentifier($document['documentNode']->getIdentifier()); $siteChanges[$siteKey]['documents'][$documentKey]['isMoved'] = $liveDocumentNode && $document['documentNode']->getPath() !== $liveDocumentNode->getPath(); $siteChanges[$siteKey]['documents'][$documentKey]['isNew'] = $liveDocumentNode === null; foreach ($document['changes'] as $changeKey => $change) { $liveNode = $liveContext->getNodeByIdentifier($change['node']->getIdentifier()); $siteChanges[$siteKey]['documents'][$documentKey]['changes'][$changeKey]['isNew'] = is_null($liveNode); $siteChanges[$siteKey]['documents'][$documentKey]['changes'][$changeKey]['isMoved'] = $liveNode && $change['node']->getPath() !== $liveNode->getPath(); } } ksort($siteChanges[$siteKey]['documents']); } return $siteChanges; }
/** * @test */ public function getUnpublishedNodesDoesNotReturnInvalidNodes() { $mockContext = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Service\\Context')->disableOriginalConstructor()->getMock(); $expectedContextProperties = array('workspaceName' => $this->mockWorkspace->getName(), 'inaccessibleContentShown' => true, 'invisibleContentShown' => true, 'removedContentShown' => true, 'currentSite' => $this->mockSite, 'dimensions' => array()); $this->mockContextFactory->expects($this->any())->method('create')->with($expectedContextProperties)->will($this->returnValue($mockContext)); $mockNodeData1 = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Model\\NodeData')->disableOriginalConstructor()->getMock(); $mockNodeData2 = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Model\\NodeData')->disableOriginalConstructor()->getMock(); $mockNodeData1->expects($this->any())->method('getDimensionValues')->will($this->returnValue(array())); $mockNodeData2->expects($this->any())->method('getDimensionValues')->will($this->returnValue(array())); $mockNode1 = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Model\\NodeInterface')->getMock(); $mockNode1->expects($this->any())->method('getNodeData')->will($this->returnValue($mockNodeData1)); $mockNode1->expects($this->any())->method('getPath')->will($this->returnValue('/node1')); $this->mockNodeFactory->expects($this->at(0))->method('createFromNodeData')->with($mockNodeData1, $mockContext)->will($this->returnValue($mockNode1)); $this->mockNodeFactory->expects($this->at(1))->method('createFromNodeData')->with($mockNodeData2, $mockContext)->will($this->returnValue(null)); $this->mockNodeDataRepository->expects($this->atLeastOnce())->method('findByWorkspace')->with($this->mockWorkspace)->will($this->returnValue(array($mockNodeData1, $mockNodeData2))); $actualResult = $this->publishingService->getUnpublishedNodes($this->mockWorkspace); $this->assertSame($actualResult, array($mockNode1)); }
/** * Get every unpublished node in the workspace with the given workspace name * * @param \TYPO3\TYPO3CR\Domain\Model\Workspace $workspace * @return void */ public function getWorkspaceWideUnpublishedNodesAction($workspace) { $this->view->assignNodes($this->publishingService->getUnpublishedNodes($workspace)); }
/** * Publishes the content of this workspace to another workspace. * * The specified workspace must be a base workspace of this workspace. * * @param Workspace $targetWorkspace The workspace to publish to * @return void * @api */ public function publish(Workspace $targetWorkspace) { $sourceNodes = $this->publishingService->getUnpublishedNodes($this); $this->publishNodes($sourceNodes, $targetWorkspace); }