/**
  * @test
  */
 public function getUnpublishedNodesCountReturnsTheNumberOfNodesInTheGivenWorkspaceMinusItsRootNode()
 {
     $this->mockWorkspace->expects($this->atLeastOnce())->method('getNodeCount')->will($this->returnValue(123));
     $actualResult = $this->publishingService->getUnpublishedNodesCount($this->mockWorkspace);
     $expectedResult = 122;
     $this->assertSame($expectedResult, $actualResult);
 }
 /**
  * Display a list of unpublished content
  *
  * @param Workspace $workspace
  * @return void
  * @todo Pagination
  * @todo Tree filtering + level limit
  * @todo Search field
  * @todo Difference mechanism
  */
 public function indexAction(Workspace $workspace = NULL)
 {
     if ($workspace === NULL) {
         $workspace = $this->userService->getUserWorkspace();
     }
     $sites = array();
     foreach ($this->publishingService->getUnpublishedNodes($workspace) as $node) {
         $pathParts = explode('/', $node->getPath());
         if (count($pathParts) > 2) {
             $siteNodeName = $pathParts[2];
             $q = new FlowQuery(array($node));
             $document = $q->closest('[instanceof TYPO3.Neos:Document]')->get(0);
             // FIXME: $document will be NULL if we have a broken rootline 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('/sites/%s/%s', $siteNodeName, $documentPath), '', $node->getPath());
                 if (!isset($sites[$siteNodeName]['siteNode'])) {
                     $sites[$siteNodeName]['siteNode'] = $this->siteRepository->findOneByNodeName($siteNodeName);
                 }
                 $sites[$siteNodeName]['documents'][$documentPath]['documentNode'] = $document;
                 $change = array('node' => $node);
                 if ($node->getNodeType()->isOfType('TYPO3.Neos:Node')) {
                     $change['configuration'] = $node->getNodeType()->getFullConfiguration();
                 }
                 $sites[$siteNodeName]['documents'][$documentPath]['changes'][$relativePath] = $change;
             }
         }
     }
     $liveContext = $this->contextFactory->create(array('workspaceName' => 'live'));
     ksort($sites);
     foreach ($sites as $siteKey => $site) {
         foreach ($site['documents'] as $documentKey => $document) {
             foreach ($document['changes'] as $changeKey => $change) {
                 $liveNode = $liveContext->getNodeByIdentifier($change['node']->getIdentifier());
                 $sites[$siteKey]['documents'][$documentKey]['changes'][$changeKey]['isNew'] = is_null($liveNode);
                 $sites[$siteKey]['documents'][$documentKey]['changes'][$changeKey]['isMoved'] = $liveNode && $change['node']->getPath() !== $liveNode->getPath();
             }
         }
         ksort($sites[$siteKey]['documents']);
     }
     $workspaces = array();
     foreach ($this->workspaceRepository->findAll() as $workspaceInstance) {
         array_push($workspaces, array('workspaceNode' => $workspaceInstance, 'unpublishedNodesCount' => $this->publishingService->getUnpublishedNodesCount($workspaceInstance)));
     }
     $this->view->assignMultiple(array('workspace' => $workspace, 'workspaces' => $workspaces, 'sites' => $sites));
 }
 /**
  * Rebase the current users personal workspace onto the given $targetWorkspace and then
  * redirects to the $targetNode in the content module.
  *
  * @param NodeInterface $targetNode
  * @param Workspace $targetWorkspace
  * @return void
  */
 public function rebaseAndRedirectAction(NodeInterface $targetNode, Workspace $targetWorkspace)
 {
     $currentAccount = $this->securityContext->getAccount();
     $personalWorkspace = $this->workspaceRepository->findOneByName('user-' . $currentAccount->getAccountIdentifier());
     /** @var Workspace $personalWorkspace */
     if ($this->publishingService->getUnpublishedNodesCount($personalWorkspace) > 0) {
         $message = $this->translator->translateById('workspaces.cantEditBecauseWorkspaceContainsChanges', [], null, null, 'Modules', 'TYPO3.Neos');
         $this->addFlashMessage($message, '', Message::SEVERITY_WARNING, [], 1437833387);
         $this->redirect('show', null, null, ['workspace' => $targetWorkspace]);
     }
     $personalWorkspace->setBaseWorkspace($targetWorkspace);
     $this->workspaceRepository->update($personalWorkspace);
     $contextProperties = $targetNode->getContext()->getProperties();
     $contextProperties['workspaceName'] = $personalWorkspace->getName();
     $context = $this->contextFactory->create($contextProperties);
     $mainRequest = $this->controllerContext->getRequest()->getMainRequest();
     /** @var ActionRequest $mainRequest */
     $this->uriBuilder->setRequest($mainRequest);
     $this->redirect('show', 'Frontend\\Node', 'TYPO3.Neos', ['node' => $context->getNode($targetNode->getPath())]);
 }
 /**
  * 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]);
 }