/** * @test */ public function aWorkspaceCanBeBasedOnAnotherWorkspace() { $baseWorkspace = new Workspace('BaseWorkspace'); $workspace = new Workspace('MyWorkspace', $baseWorkspace); $this->assertSame('MyWorkspace', $workspace->getName()); $this->assertSame($baseWorkspace, $workspace->getBaseWorkspace()); }
/** * Returns a list of nodes contained in the given workspace which are not yet published * * @param Workspace $workspace * @return array<\TYPO3\TYPO3CR\Domain\Model\NodeInterface> * @api */ public function getUnpublishedNodes(Workspace $workspace) { if ($workspace->getBaseWorkspace() === NULL) { return array(); } $nodeData = $this->nodeDataRepository->findByWorkspace($workspace); $unpublishedNodes = array(); foreach ($nodeData as $singleNodeData) { /** @var NodeData $singleNodeData */ // Skip the root entry from the workspace as it can't be published if ($singleNodeData->getPath() === '/') { continue; } $node = $this->nodeFactory->createFromNodeData($singleNodeData, $this->createContext($workspace, $singleNodeData->getDimensionValues())); if ($node !== NULL) { $unpublishedNodes[] = $node; } } $unpublishedNodes = $this->sortNodesForPublishing($unpublishedNodes); return $unpublishedNodes; }
/** * Move the given node instance to the target workspace * * If no target node variant (having the same dimension values) exists in the target workspace, the node that * is published will be used as a new node variant in the target workspace. * * @param NodeInterface $node The node to publish * @param Workspace $targetWorkspace The workspace to publish to * @return void */ protected function moveNodeVariantToTargetWorkspace(NodeInterface $node, Workspace $targetWorkspace) { $nodeData = $node->getNodeData(); $movedShadowNodeData = $this->nodeDataRepository->findOneByMovedTo($nodeData); if ($movedShadowNodeData instanceof NodeData && $movedShadowNodeData->isRemoved()) { $this->nodeDataRepository->remove($movedShadowNodeData); } if ($targetWorkspace->getBaseWorkspace() === null && $node->isRemoved()) { $this->nodeDataRepository->remove($nodeData); } else { $nodeData->setWorkspace($targetWorkspace); $nodeData->setLastPublicationDateTime($this->now); $this->nodeService->cleanUpProperties($node); } $node->setNodeDataIsMatchingContext(null); }
/** * 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 \TYPO3\Flow\Persistence\Exception\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); } } else { if ($this->persistenceManager->isNewObject($nodeData)) { $this->nodeDataRepository->add($nodeData); } else { $this->nodeDataRepository->update($nodeData); } } }
/** * Look for a shadow node of $publishedNodeData either adjust or remove it based on $targetWorkspace if the shadow * node is marked as removed. * * @param NodeData $publishedNodeData * @param Workspace $targetWorkspace * @param NodeData $targetNodeData * @return boolean false if no shadow node was found, true otherwise */ protected function handleShadowNodeData(NodeData $publishedNodeData, Workspace $targetWorkspace, NodeData $targetNodeData) { /** @var NodeData $shadowNodeData */ $shadowNodeData = $this->nodeDataRepository->findOneByMovedTo($publishedNodeData); if ($shadowNodeData === null) { return false; } // Technically this is not a shadow node if ($shadowNodeData->isRemoved() === false) { return true; } $targetWorkspaceBase = $targetWorkspace->getBaseWorkspace(); if ($targetWorkspaceBase !== null) { $this->adjustShadowNodeData($shadowNodeData, $publishedNodeData, $targetWorkspace, $targetNodeData); } else { $this->nodeDataRepository->remove($shadowNodeData); } return true; }
/** * 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; }
/** * Publishes the whole workspace * * @param Workspace $workspace * @return void */ public function publishWorkspaceAction(Workspace $workspace) { if (($targetWorkspace = $workspace->getBaseWorkspace()) === null) { $targetWorkspace = $this->workspaceRepository->findOneByName('live'); } $workspace->publish($targetWorkspace); $this->addFlashMessage($this->translator->translateById('workspaces.allChangesInWorkspaceHaveBeenPublished', [htmlspecialchars($workspace->getTitle()), htmlspecialchars($targetWorkspace->getTitle())], null, null, 'Modules', 'TYPO3.Neos')); $this->redirect('index'); }
/** * Removes this node and all its child nodes. * * @return void */ public function remove() { /** @var $childNode NodeData */ foreach ($this->getChildNodeData() as $childNode) { $childNode->remove(); } if ($this->workspace->getBaseWorkspace() === NULL) { $this->nodeDataRepository->remove($this); } else { $this->removed = TRUE; $this->nodeDataRepository->update($this); } }
/** * 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); } }