/**
  * @test
  */
 public function matchesWorkspaceAndDimensionsWithMatchingWorkspaceAndDimensionsReturnsTrue()
 {
     $this->nodeData = new NodeData('/foo/bar', $this->mockWorkspace, null, array('language' => array('mul_ZZ')));
     $this->mockWorkspace->expects($this->any())->method('getName')->will($this->returnValue('live'));
     $result = $this->nodeData->matchesWorkspaceAndDimensions($this->mockWorkspace, array('language' => array('de_DE', 'mul_ZZ')));
     $this->assertTrue($result);
 }
 /**
  * {@inheritdoc}
  */
 public function createRedirectsForPublishedNode(NodeInterface $node, Workspace $targetWorkspace)
 {
     $nodeType = $node->getNodeType();
     if ($targetWorkspace->getName() !== 'live' || !$nodeType->isOfType('Neos.Neos:Document')) {
         return;
     }
     $context = $this->contextFactory->create(['workspaceName' => 'live', 'invisibleContentShown' => true, 'dimensions' => $node->getContext()->getDimensions()]);
     $targetNode = $context->getNodeByIdentifier($node->getIdentifier());
     if ($targetNode === null) {
         // The page has been added
         return;
     }
     $targetNodeUriPath = $this->buildUriPathForNodeContextPath($targetNode->getContextPath());
     if ($targetNodeUriPath === null) {
         throw new Exception('The target URI path of the node could not be resolved', 1451945358);
     }
     $hosts = $this->getHostnames($node->getContext());
     // The page has been removed
     if ($node->isRemoved()) {
         $this->flushRoutingCacheForNode($targetNode);
         $statusCode = (int) $this->defaultStatusCode['gone'];
         $this->redirectStorage->addRedirect($targetNodeUriPath, '', $statusCode, $hosts);
         return;
     }
     // compare the "old" node URI to the new one
     $nodeUriPath = $this->buildUriPathForNodeContextPath($node->getContextPath());
     // use the same regexp than the ContentContextBar Ember View
     $nodeUriPath = preg_replace('/@[A-Za-z0-9;&,\\-_=]+/', '', $nodeUriPath);
     if ($nodeUriPath === null || $nodeUriPath === $targetNodeUriPath) {
         // The page node path has not been changed
         return;
     }
     $this->flushRoutingCacheForNode($targetNode);
     $statusCode = (int) $this->defaultStatusCode['redirect'];
     $this->redirectStorage->addRedirect($targetNodeUriPath, $nodeUriPath, $statusCode, $hosts);
     $q = new FlowQuery([$node]);
     foreach ($q->children('[instanceof Neos.Neos:Document]') as $childrenNode) {
         $this->createRedirectsForPublishedNode($childrenNode, $targetWorkspace);
     }
 }
 /**
  * @test
  */
 public function publishNodePublishesTheNodeAndItsChildNodeCollectionsIfTheNodeTypeHasChildNodes()
 {
     $mockNode = $this->getMockBuilder(NodeInterface::class)->getMock();
     $mockChildNode = $this->getMockBuilder(NodeInterface::class)->getMock();
     $mockNodeType = $this->getMockBuilder(NodeType::class)->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('Neos.Neos:ContentCollection')->will($this->returnValue(array($mockChildNode)));
     $mockTargetWorkspace = $this->getMockBuilder(Workspace::class)->disableOriginalConstructor()->getMock();
     $this->mockWorkspace->expects($this->atLeastOnce())->method('publishNodes')->with(array($mockNode, $mockChildNode), $mockTargetWorkspace);
     $this->publishingService->publishNode($mockNode, $mockTargetWorkspace);
 }
 /**
  * This test checks that targets for resource links are correctly replaced
  *
  * @test
  */
 public function evaluateReplaceResourceLinkTargets()
 {
     $assetIdentifier = 'aeabe76a-551a-495f-a324-ad9a86b2aff8';
     $resourceLinkTarget = '_blank';
     $value = 'This string contains two asset links and an external link: one with a target set <a target="top" href="asset://' . $assetIdentifier . '">example</a> and one without a target <a href="asset://' . $assetIdentifier . '">example2</a> and an external link <a href="http://www.example.org">example3</a>';
     $this->addValueExpectation($value, null, false, null, $resourceLinkTarget);
     $this->mockWorkspace->expects($this->any())->method('getName')->will($this->returnValue('live'));
     $self = $this;
     $this->mockLinkingService->expects($this->atLeastOnce())->method('resolveAssetUri')->will($this->returnCallback(function ($assetUri) use($self, $assetIdentifier) {
         if ($assetUri !== 'asset://' . $assetIdentifier) {
             $self->fail('Unexpected asset URI "' . $assetUri . '"');
         }
         return 'http://localhost/_Resources/01';
     }));
     $expectedResult = 'This string contains two asset links and an external link: one with a target set <a target="' . $resourceLinkTarget . '" href="http://localhost/_Resources/01">example</a> and one without a target <a target="' . $resourceLinkTarget . '" href="http://localhost/_Resources/01">example2</a> and an external link <a href="http://www.example.org">example3</a>';
     $actualResult = $this->convertUrisImplementation->evaluate();
     $this->assertSame($expectedResult, $actualResult);
 }
 /**
  * Adds this node to the Node Repository or updates it if it has been added earlier
  *
  * @param NodeData $nodeData Other NodeData object to addOrUpdate
  * @throws IllegalObjectTypeException
  */
 protected function addOrUpdate(NodeData $nodeData = null)
 {
     $nodeData = $nodeData === null ? $this : $nodeData;
     // If this NodeData was previously removed and is in live workspace we don't want to add it again to persistence.
     if ($nodeData->isRemoved() && $this->workspace->getBaseWorkspace() === null) {
         // Actually it should be removed from the identity map here.
         if ($this->persistenceManager->isNewObject($nodeData) === false) {
             $this->nodeDataRepository->remove($nodeData);
         }
         return;
     }
     // If the node is marked to be removed but didn't exist in a base workspace yet, we can delete it for real, without creating a shadow node:
     if ($nodeData->isRemoved() && $this->nodeDataRepository->findOneByIdentifier($nodeData->getIdentifier(), $this->workspace->getBaseWorkspace()) === null) {
         if ($this->persistenceManager->isNewObject($nodeData) === false) {
             $this->nodeDataRepository->remove($nodeData);
         }
         return;
     }
     if ($this->persistenceManager->isNewObject($nodeData)) {
         $this->nodeDataRepository->add($nodeData);
     } else {
         $this->nodeDataRepository->update($nodeData);
     }
 }
 /**
  * Collects all nodes with missing shadow nodes
  *
  * @param Workspace $workspace
  * @param boolean $dryRun
  * @param NodeType $nodeType
  * @return array
  */
 protected function fixShadowNodesInWorkspace(Workspace $workspace, $dryRun, NodeType $nodeType = null)
 {
     $workspaces = array_merge([$workspace], $workspace->getBaseWorkspaces());
     $fixedShadowNodes = 0;
     foreach ($workspaces as $workspace) {
         /** @var Workspace $workspace */
         if ($workspace->getBaseWorkspace() === null) {
             continue;
         }
         /** @var QueryBuilder $queryBuilder */
         $queryBuilder = $this->entityManager->createQueryBuilder();
         $queryBuilder->select('n')->from(NodeData::class, 'n')->where('n.workspace = :workspace');
         $queryBuilder->setParameter('workspace', $workspace->getName());
         if ($nodeType !== null) {
             $queryBuilder->andWhere('n.nodeType = :nodeType');
             $queryBuilder->setParameter('nodeType', $nodeType->getName());
         }
         /** @var NodeData $nodeData */
         foreach ($queryBuilder->getQuery()->getResult() as $nodeData) {
             $nodeDataSeenFromParentWorkspace = $this->nodeDataRepository->findOneByIdentifier($nodeData->getIdentifier(), $workspace->getBaseWorkspace(), $nodeData->getDimensionValues());
             // This is the good case, either the node does not exist or was shadowed
             if ($nodeDataSeenFromParentWorkspace === null) {
                 continue;
             }
             // Also good, the node was not moved at all.
             if ($nodeDataSeenFromParentWorkspace->getPath() === $nodeData->getPath()) {
                 continue;
             }
             $nodeDataOnSamePath = $this->nodeDataRepository->findOneByPath($nodeData->getPath(), $workspace->getBaseWorkspace(), $nodeData->getDimensionValues(), null);
             // We cannot just put a shadow node in the path, something exists, but that should be fine.
             if ($nodeDataOnSamePath !== null) {
                 continue;
             }
             if (!$dryRun) {
                 $nodeData->createShadow($nodeDataSeenFromParentWorkspace->getPath());
             }
             $fixedShadowNodes++;
         }
     }
     return $fixedShadowNodes;
 }
 /**
  * Creates a new content context based on the given workspace and the NodeData object.
  *
  * @param Workspace $workspace Workspace for the new context
  * @param array $dimensionValues The dimension values for the new context
  * @param array $contextProperties Additional pre-defined context properties
  * @return Context
  */
 protected function createContext(Workspace $workspace, array $dimensionValues, array $contextProperties = array())
 {
     $presetsMatchingDimensionValues = $this->contentDimensionPresetSource->findPresetsByTargetValues($dimensionValues);
     $dimensions = array_map(function ($preset) {
         return $preset['values'];
     }, $presetsMatchingDimensionValues);
     $contextProperties += array('workspaceName' => $workspace->getName(), 'inaccessibleContentShown' => true, 'invisibleContentShown' => true, 'removedContentShown' => true, 'dimensions' => $dimensions);
     return $this->contextFactory->create($contextProperties);
 }
 /**
  * Create a new workspace
  *
  * This command creates a new workspace.
  *
  * @param string $workspace Name of the workspace, for example "christmas-campaign"
  * @param string $baseWorkspace Name of the base workspace. If none is specified, "live" is assumed.
  * @param string $title Human friendly title of the workspace, for example "Christmas Campaign"
  * @param string $description A description explaining the purpose of the new workspace
  * @param string $owner The identifier of a User to own the workspace
  * @return void
  */
 public function createCommand($workspace, $baseWorkspace = 'live', $title = null, $description = null, $owner = '')
 {
     $workspaceName = $workspace;
     $workspace = $this->workspaceRepository->findOneByName($workspaceName);
     if ($workspace instanceof Workspace) {
         $this->outputLine('Workspace "%s" already exists', [$workspaceName]);
         $this->quit(1);
     }
     $baseWorkspaceName = $baseWorkspace;
     $baseWorkspace = $this->workspaceRepository->findOneByName($baseWorkspaceName);
     if (!$baseWorkspace instanceof Workspace) {
         $this->outputLine('The base workspace "%s" does not exist', [$baseWorkspaceName]);
         $this->quit(2);
     }
     if ($owner === '') {
         $owningUser = null;
     } else {
         $owningUser = $this->userService->getUser($owner);
         if ($owningUser === null) {
             $this->outputLine('The user "%s" specified as owner does not exist', [$owner]);
             $this->quit(3);
         }
     }
     if ($title === null) {
         $title = $workspaceName;
     }
     $workspace = new Workspace($workspaceName, $baseWorkspace, $owningUser);
     $workspace->setTitle($title);
     $workspace->setDescription($description);
     $this->workspaceRepository->add($workspace);
     if ($owningUser instanceof User) {
         $this->outputLine('Created a new workspace "%s", based on workspace "%s", owned by "%s".', [$workspaceName, $baseWorkspaceName, $owner]);
     } else {
         $this->outputLine('Created a new workspace "%s", based on workspace "%s".', [$workspaceName, $baseWorkspaceName]);
     }
 }
 /**
  * Creates a personal workspace for the given user's account if it does not exist already.
  *
  * @param User $user The new user to create a workspace for
  * @param Account $account The user's backend account
  * @throws IllegalObjectTypeException
  */
 protected function createPersonalWorkspace(User $user, Account $account)
 {
     $userWorkspaceName = UserUtility::getPersonalWorkspaceNameForUsername($account->getAccountIdentifier());
     $userWorkspace = $this->workspaceRepository->findByIdentifier($userWorkspaceName);
     if ($userWorkspace === null) {
         $liveWorkspace = $this->workspaceRepository->findByIdentifier('live');
         if (!$liveWorkspace instanceof Workspace) {
             $liveWorkspace = new Workspace('live');
             $liveWorkspace->setTitle('Live');
             $this->workspaceRepository->add($liveWorkspace);
         }
         $userWorkspace = new Workspace($userWorkspaceName, $liveWorkspace, $user);
         $userWorkspace->setTitle((string) $user->getName());
         $this->workspaceRepository->add($userWorkspace);
     }
 }
 /**
  *
  *
  * @param NodeInterface $node
  * @param Workspace $targetWorkspace
  * @return void
  */
 public function afterNodePublishing(NodeInterface $node, Workspace $targetWorkspace)
 {
     if (!$this->eventEmittingService->isEnabled()) {
         return;
     }
     $documentNode = NodeEvent::getClosestAggregateNode($node);
     if ($documentNode === null) {
         return;
     }
     $this->scheduledNodeEventUpdates[$documentNode->getContextPath()] = array('workspaceName' => $node->getContext()->getWorkspaceName(), 'nestedNodeIdentifiersWhichArePublished' => array(), 'targetWorkspace' => $targetWorkspace->getName(), 'documentNode' => $documentNode);
     $this->scheduledNodeEventUpdates[$documentNode->getContextPath()]['nestedNodeIdentifiersWhichArePublished'][] = $node->getIdentifier();
 }
 /**
  * This finds nodes by path and delivers a raw, unfiltered result.
  *
  * To get a "usable" set of nodes, filtering by workspaces, dimensions and
  * removed nodes must be done on the result.
  *
  * @param string $path
  * @param Workspace $workspace
  * @param array|null $dimensions
  * @param boolean $onlyShadowNodes
  * @return array
  * @throws \InvalidArgumentException
  */
 protected function findRawNodesByPath($path, Workspace $workspace, array $dimensions = null, $onlyShadowNodes = false)
 {
     $path = strtolower($path);
     if ($path === '' || $path !== '/' && ($path[0] !== '/' || substr($path, -1, 1) === '/')) {
         throw new \InvalidArgumentException('"' . $path . '" is not a valid path: must start but not end with a slash.', 1284985489);
     }
     if ($path === '/') {
         return [$workspace->getRootNodeData()];
     }
     $addedNodes = [];
     $workspaces = [];
     while ($workspace !== null) {
         /** @var $node NodeData */
         foreach ($this->addedNodes as $node) {
             if ($node->getPath() === $path && $node->matchesWorkspaceAndDimensions($workspace, $dimensions) && ($onlyShadowNodes === false || $node->isInternal())) {
                 $addedNodes[] = $node;
                 // removed nodes don't matter here because due to the identity map the right object will be returned from the query and will have "removed" set.
             }
         }
         $workspaces[] = $workspace;
         $workspace = $workspace->getBaseWorkspace();
     }
     $queryBuilder = $this->createQueryBuilder($workspaces);
     if ($dimensions !== null) {
         $this->addDimensionJoinConstraintsToQueryBuilder($queryBuilder, $dimensions);
     }
     $this->addPathConstraintToQueryBuilder($queryBuilder, $path);
     if ($onlyShadowNodes) {
         $queryBuilder->andWhere('n.movedTo IS NOT NULL AND n.removed = TRUE');
     }
     $query = $queryBuilder->getQuery();
     $nodes = $query->getResult();
     return array_merge($nodes, $addedNodes);
 }
 /**
  * Publishes the whole workspace
  *
  * @param Workspace $workspace
  * @return void
  */
 public function publishWorkspaceAction(Workspace $workspace)
 {
     if (($targetWorkspace = $workspace->getBaseWorkspace()) === null) {
         $targetWorkspace = $this->workspaceRepository->findOneByName('live');
     }
     $this->publishingService->publishNodes($this->publishingService->getUnpublishedNodes($workspace), $targetWorkspace);
     $this->addFlashMessage($this->translator->translateById('workspaces.allChangesInWorkspaceHaveBeenPublished', [htmlspecialchars($workspace->getTitle()), htmlspecialchars($targetWorkspace->getTitle())], null, null, 'Modules', 'Neos.Neos'));
     $this->redirect('index');
 }
 /**
  * Checks if the specified workspace is a base workspace of this workspace
  * and if not, throws an exception
  *
  * @param Workspace $targetWorkspace The publishing target workspace
  * @return void
  * @throws WorkspaceException if the specified workspace is not a base workspace of this workspace
  */
 protected function verifyPublishingTargetWorkspace(Workspace $targetWorkspace)
 {
     $baseWorkspace = $this;
     while ($baseWorkspace === null || $targetWorkspace->getName() !== $baseWorkspace->getName()) {
         if ($baseWorkspace === null) {
             throw new WorkspaceException(sprintf('The specified workspace "%s" is not a base workspace of "%s".', $targetWorkspace->getName(), $this->getName()), 1289499117);
         }
         $baseWorkspace = $baseWorkspace->getBaseWorkspace();
     }
 }
Example #14
0
 /**
  * Sets the workspace of this node.
  *
  * This method is only for internal use by the content repository. Changing
  * the workspace of a node manually may lead to unexpected behavior.
  *
  * @param Workspace $workspace
  * @return void
  */
 public function setWorkspace(Workspace $workspace)
 {
     if (!$this->isNodeDataMatchingContext()) {
         $this->materializeNodeData();
     }
     if ($this->getWorkspace()->getName() === $workspace->getName()) {
         return;
     }
     $this->nodeData->setWorkspace($workspace);
     $this->context->getFirstLevelNodeCache()->flush();
     $this->emitNodeUpdated($this);
 }
 /**
  * @test
  */
 public function isPersonalWorkspaceChecksIfTheWorkspaceNameStartsWithUser()
 {
     $liveWorkspace = new Workspace('live');
     $personalWorkspace = new Workspace('user-admin', $liveWorkspace);
     $this->assertFalse($liveWorkspace->isPersonalWorkspace());
     $this->assertTrue($personalWorkspace->isPersonalWorkspace());
 }