/** * 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; }); }
/** * 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'); }
/** * Removes all personal workspaces of the given user's account if these workspaces exist. Also removes * all possibly existing content of these workspaces. * * @param string $accountIdentifier Identifier of the user's account * @return void */ protected function deletePersonalWorkspace($accountIdentifier) { $userWorkspace = $this->workspaceRepository->findByIdentifier(UserUtility::getPersonalWorkspaceNameForUsername($accountIdentifier)); if ($userWorkspace instanceof Workspace) { $this->publishingService->discardAllNodes($userWorkspace); $this->workspaceRepository->remove($userWorkspace); } }
/** * Removes all personal workspaces of the given user's account if these workspaces exist. Also removes * all possibly existing content of these workspaces. * * @param string $accountIdentifier Identifier of the user's account * @return void */ protected function deleteUserWorkspaces($accountIdentifier) { $userWorkspace = $this->workspaceRepository->findByIdentifier('user-' . $accountIdentifier); if ($userWorkspace instanceof Workspace) { $this->publishingService->discardAllNodes($userWorkspace); $this->workspaceRepository->remove($userWorkspace); } }
/** * @test */ public function publishNodePublishesTheNodeAndItsChildNodeCollectionsIfTheNodeTypeHasChildNodes() { $mockNode = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Model\\NodeInterface')->getMock(); $mockChildNode = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Model\\NodeInterface')->getMock(); $mockNodeType = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Model\\NodeType')->disableOriginalConstructor()->setMethods(array('hasConfiguration', 'isOfType'))->getMock(); $mockNodeType->expects($this->atLeastOnce())->method('hasConfiguration')->with('childNodes')->will($this->returnValue(true)); $mockNode->expects($this->atLeastOnce())->method('getNodeType')->will($this->returnValue($mockNodeType)); $mockNode->expects($this->atLeastOnce())->method('getWorkspace')->will($this->returnValue($this->mockWorkspace)); $mockNode->expects($this->atLeastOnce())->method('getChildNodes')->with('TYPO3.Neos:ContentCollection')->will($this->returnValue(array($mockChildNode))); $mockTargetWorkspace = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Model\\Workspace')->disableOriginalConstructor()->getMock(); $this->mockWorkspace->expects($this->atLeastOnce())->method('publishNodes')->with(array($mockNode, $mockChildNode), $mockTargetWorkspace); $this->publishingService->publishNode($mockNode, $mockTargetWorkspace); }
/** * 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; }
/** * Deletes a workspace * * This command deletes a workspace. If you only want to empty a workspace and not delete the * workspace itself, use <i>workspace:discard</i> instead. * * @param string $workspace Name of the workspace, for example "christmas-campaign" * @param boolean $force Delete the workspace and all of its contents * @return void * @see typo3.neos:workspace:discard */ public function deleteCommand($workspace, $force = false) { $workspaceName = $workspace; $workspace = $this->workspaceRepository->findOneByName($workspaceName); if (!$workspace instanceof Workspace) { $this->outputLine('Workspace "%s" does not exist', [$workspaceName]); $this->quit(1); } if ($workspace->isPersonalWorkspace()) { $this->outputLine('Did not delete workspace "%s" because it is a personal workspace. Personal workspaces cannot be deleted manually.', [$workspaceName]); $this->quit(2); } $dependentWorkspaces = $this->workspaceRepository->findByBaseWorkspace($workspace); if (count($dependentWorkspaces) > 0) { $this->outputLine('Workspace "%s" cannot be deleted because the following workspaces are based on it:', [$workspaceName]); $this->outputLine(); $tableRows = []; $headerRow = ['Name', 'Title', 'Description']; /** @var Workspace $workspace */ foreach ($dependentWorkspaces as $workspace) { $tableRows[] = [$workspace->getName(), $workspace->getTitle(), $workspace->getDescription()]; } $this->output->outputTable($tableRows, $headerRow); $this->quit(3); } try { $nodesCount = $this->publishingService->getUnpublishedNodesCount($workspace); } catch (\Exception $exception) { $this->outputLine('An error occurred while fetching unpublished nodes from workspace %s, nothing was deleted.', [$workspaceName]); $this->quit(4); } if ($nodesCount > 0) { if ($force === false) { $this->outputLine('Did not delete workspace "%s" because it contains %s unpublished node(s). Use --force to delete it nevertheless.', [$workspaceName, $nodesCount]); $this->quit(5); } $this->discardCommand($workspaceName); } $this->workspaceRepository->remove($workspace); $this->outputLine('Deleted workspace "%s"', [$workspaceName]); }
/** * Discard nodes * * @param array $nodeContextPaths * @return void */ public function discardAction(array $nodeContextPaths) { try { foreach ($nodeContextPaths as $contextPath) { $node = $this->nodeService->getNodeFromContextPath($contextPath); $this->publishingService->discardNode($node); $reloadDocument = new ReloadDocument(); $reloadDocument->setDocument($this->nodeService->getClosestDocument($node)); $this->feedbackCollection->add($reloadDocument); } $success = new Success(); $success->setMessage(sprintf('Discarded %d node(s).', count($nodeContextPaths))); $this->updateWorkspaceInfo($nodeContextPaths[0]); $this->feedbackCollection->add($success); $this->persistenceManager->persistAll(); } catch (\Exception $e) { $error = new Error(); $error->setMessage($e->getMessage()); $this->feedbackCollection->add($error); } $this->view->assign('value', $this->feedbackCollection); }
/** * Discard everything in the workspace with the given workspace name * * @param \TYPO3\TYPO3CR\Domain\Model\Workspace $workspace * @return void */ public function discardAllAction($workspace) { $this->publishingService->discardAllNodes($workspace); $this->throwStatus(204, 'Workspace changes have been discarded', ''); }
/** * 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); }