/** * Shows details of the given workspace * * @param string $workspaceName * @param Workspace $baseWorkspace * @return string */ public function createAction($workspaceName, Workspace $baseWorkspace) { $existingWorkspace = $this->workspaceRepository->findByIdentifier($workspaceName); if ($existingWorkspace !== NULL) { $this->throwStatus(409, 'Workspace already exists', ''); } $workspace = new Workspace($workspaceName, $baseWorkspace); $this->workspaceRepository->add($workspace); $this->throwStatus(201, 'Workspace created', ''); }
/** * Remove dimensions on nodes "/" and "/sites" * * This empties the content dimensions on those nodes, so when traversing via the Node API from the root node, * the nodes below "/sites" are always reachable. * * @param string $workspaceName * @param boolean $dryRun * @return void */ public function removeContentDimensionsFromRootAndSitesNode($workspaceName, $dryRun) { $workspace = $this->workspaceRepository->findByIdentifier($workspaceName); $rootNodes = $this->nodeDataRepository->findByPath('/', $workspace); $sitesNodes = $this->nodeDataRepository->findByPath('/sites', $workspace); $this->output->outputLine('Checking for root and site nodes with content dimensions set ...'); /** @var \TYPO3\TYPO3CR\Domain\Model\NodeData $rootNode */ foreach ($rootNodes as $rootNode) { if ($rootNode->getDimensionValues() !== []) { if ($dryRun === false) { $rootNode->setDimensions([]); $this->nodeDataRepository->update($rootNode); $this->output->outputLine('Removed content dimensions from root node'); } else { $this->output->outputLine('Found root node with content dimensions set.'); } } } /** @var \TYPO3\TYPO3CR\Domain\Model\NodeData $sitesNode */ foreach ($sitesNodes as $sitesNode) { if ($sitesNode->getDimensionValues() !== []) { if ($dryRun === false) { $sitesNode->setDimensions([]); $this->nodeDataRepository->update($sitesNode); $this->output->outputLine('Removed content dimensions from node "/sites"'); } else { $this->output->outputLine('Found node "/sites"'); } } } }
/** * 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); } }
/** * Performs checks for orphan nodes removes them if found. * * @param NodeType $nodeType Only for this node type, if specified * @param string $workspaceName * @param boolean $dryRun Simulate? * @return void */ public function removeUndefinedProperties(NodeType $nodeType = NULL, $workspaceName, $dryRun) { $this->output->outputLine('Checking for undefined properties ...'); /** @var \TYPO3\TYPO3CR\Domain\Model\Workspace $workspace */ $workspace = $this->workspaceRepository->findByIdentifier($workspaceName); $nodesWithUndefinedPropertiesNodes = array(); $undefinedPropertiesCount = 0; $nodes = $nodeType !== NULL ? $this->getNodeDataByNodeTypeAndWorkspace($nodeType, $workspaceName) : $this->nodeDataRepository->findByWorkspace($workspace); foreach ($nodes as $nodeData) { try { /** @var NodeData $nodeData */ if ($nodeData->getNodeType()->getName() === 'unstructured') { continue; } $context = $this->nodeFactory->createContextMatchingNodeData($nodeData); $node = $this->nodeFactory->createFromNodeData($nodeData, $context); if (!$node instanceof NodeInterface) { continue; } $nodeType = $node->getNodeType(); $undefinedProperties = array_diff(array_keys($node->getProperties()), array_keys($nodeType->getProperties())); if ($undefinedProperties !== array()) { $nodesWithUndefinedPropertiesNodes[$node->getIdentifier()] = array('node' => $node, 'undefinedProperties' => $undefinedProperties); foreach ($undefinedProperties as $undefinedProperty) { $undefinedPropertiesCount++; $this->output->outputLine('Found undefined property named "%s" in "%s" (%s)', array($undefinedProperty, $node->getPath(), $node->getNodeType()->getName())); } } } catch (NodeTypeNotFoundException $exception) { $this->output->outputLine('Skipped undefined node type in "%s"', array($nodeData->getPath())); } } if ($undefinedPropertiesCount > 0) { $this->output->outputLine(); if (!$dryRun) { $self = $this; $this->askBeforeExecutingTask('Do you want to remove undefined node properties?', function () use($self, $nodesWithUndefinedPropertiesNodes, $undefinedPropertiesCount, $workspaceName, $dryRun) { foreach ($nodesWithUndefinedPropertiesNodes as $nodesWithUndefinedPropertiesNode) { /** @var NodeInterface $node */ $node = $nodesWithUndefinedPropertiesNode['node']; foreach ($nodesWithUndefinedPropertiesNode['undefinedProperties'] as $undefinedProperty) { if ($node->hasProperty($undefinedProperty)) { $node->removeProperty($undefinedProperty); } } } $self->output->outputLine('Removed %s undefined propert%s.', array($undefinedPropertiesCount, $undefinedPropertiesCount > 1 ? 'ies' : 'y')); }); } else { $this->output->outputLine('Found %s undefined propert%s to be removed.', array($undefinedPropertiesCount, $undefinedPropertiesCount > 1 ? 'ies' : 'y')); } $this->output->outputLine(); } }
/** * Repair nodes whose shadow nodes are missing * * This check searches for nodes which have a corresponding node in one of the base workspaces, * have different node paths, but don't have a corresponding shadow node with a "movedto" value. * * @param string $workspaceName Currently ignored * @param boolean $dryRun Simulate? * @param NodeType $nodeType This argument will be ignored * @return void */ protected function repairShadowNodes($workspaceName, $dryRun, NodeType $nodeType = null) { /** @var Workspace $workspace */ $workspace = $this->workspaceRepository->findByIdentifier($workspaceName); if ($workspace->getBaseWorkspace() === null) { $this->output->outputLine('Repairing base workspace "%s", therefore skipping check for shadow nodes.', [$workspaceName]); $this->output->outputLine(); return; } $this->output->outputLine('Checking for nodes with missing shadow nodes ...'); $fixedShadowNodes = $this->fixShadowNodesInWorkspace($workspace, $nodeType); $this->output->outputLine('%s %s node%s with missing shadow nodes.', [$dryRun ? 'Would repair' : 'Repaired', $fixedShadowNodes, $fixedShadowNodes !== 1 ? 's' : '']); $this->output->outputLine(); }
/** * Returns the current workspace. * * @param boolean $createWorkspaceIfNecessary DEPRECATED: If enabled, creates a workspace with the configured name if it doesn't exist already. This option is DEPRECATED, create workspace explicitly instead. * @return Workspace The workspace or NULL * @api */ public function getWorkspace($createWorkspaceIfNecessary = TRUE) { if ($this->workspace !== NULL) { return $this->workspace; } $this->workspace = $this->workspaceRepository->findByIdentifier($this->workspaceName); if ($this->workspace !== NULL) { return $this->workspace; } if ($createWorkspaceIfNecessary) { $liveWorkspace = $this->workspaceRepository->findByIdentifier('live'); $this->workspace = new Workspace($this->workspaceName, $liveWorkspace); $this->workspaceRepository->add($this->workspace); $this->systemLogger->log(sprintf('Notice: %s::getWorkspace() implicitly created the new workspace "%s". This behaviour is discouraged and will be removed in future versions. Make sure to create workspaces explicitly by adding a new workspace to the Workspace Repository.', __CLASS__, $this->workspaceName), LOG_NOTICE); } }
/** * Create a workspace * * @param string $workspaceName * @param Workspace $baseWorkspace * @param string $ownerAccountIdentifier * @return string */ public function createAction($workspaceName, Workspace $baseWorkspace, $ownerAccountIdentifier = null) { $existingWorkspace = $this->workspaceRepository->findByIdentifier($workspaceName); if ($existingWorkspace !== null) { $this->throwStatus(409, 'Workspace already exists', ''); } if ($ownerAccountIdentifier !== null) { $owner = $this->userService->getUser($ownerAccountIdentifier); if ($owner === null) { $this->throwStatus(422, 'Requested owner account does not exist', ''); } } else { $owner = null; } $workspace = new Workspace($workspaceName, $baseWorkspace, $owner); $this->workspaceRepository->add($workspace); $this->throwStatus(201, 'Workspace created', ''); }
/** * Remove broken entity references * * This removes references from nodes to entities which don't exist anymore. * * @param string $workspaceName * @param boolean $dryRun * @return void */ public function removeBrokenEntityReferences($workspaceName, $dryRun) { $this->output->outputLine('Checking for broken entity references ...'); /** @var \TYPO3\TYPO3CR\Domain\Model\Workspace $workspace */ $workspace = $this->workspaceRepository->findByIdentifier($workspaceName); $nodeTypesWithEntityReferences = array(); foreach ($this->nodeTypeManager->getNodeTypes() as $nodeType) { /** @var NodeType $nodeType */ foreach (array_keys($nodeType->getProperties()) as $propertyName) { $propertyType = $nodeType->getPropertyType($propertyName); if (strpos($propertyType, '\\') !== false) { if (!isset($nodeTypesWithEntityReferences[$nodeType->getName()])) { $nodeTypesWithEntityReferences[$nodeType->getName()] = array(); } $nodeTypesWithEntityReferences[$nodeType->getName()][$propertyName] = $propertyType; } } } $nodesWithBrokenEntityReferences = array(); $brokenReferencesCount = 0; foreach ($nodeTypesWithEntityReferences as $nodeTypeName => $properties) { $nodeDatas = $this->nodeDataRepository->findByParentAndNodeTypeRecursively('/', $nodeTypeName, $workspace); foreach ($nodeDatas as $nodeData) { /** @var NodeData $nodeData */ foreach ($properties as $propertyName => $propertyType) { $propertyValue = $nodeData->getProperty($propertyName); $convertedProperty = null; if (is_object($propertyValue)) { $convertedProperty = $propertyValue; } if (is_string($propertyValue) && strlen($propertyValue) === 36) { $convertedProperty = $this->propertyMapper->convert($propertyValue, $propertyType); if ($convertedProperty === null) { $nodesWithBrokenEntityReferences[$nodeData->getIdentifier()][$propertyName] = $nodeData; $this->output->outputLine('Broken reference in "%s", property "%s" (%s) referring to %s.', array($nodeData->getPath(), $nodeData->getIdentifier(), $propertyName, $propertyType, $propertyValue)); $brokenReferencesCount++; } } if ($convertedProperty instanceof \Doctrine\ORM\Proxy\Proxy) { try { $convertedProperty->__load(); } catch (EntityNotFoundException $e) { $nodesWithBrokenEntityReferences[$nodeData->getIdentifier()][$propertyName] = $nodeData; $this->output->outputLine('Broken reference in "%s", property "%s" (%s) referring to %s.', array($nodeData->getPath(), $nodeData->getIdentifier(), $propertyName, $propertyType, $propertyValue)); $brokenReferencesCount++; } } } } } if ($brokenReferencesCount > 0) { $this->output->outputLine(); if (!$dryRun) { $self = $this; $this->askBeforeExecutingTask('Do you want to remove the broken entity references?', function () use($self, $nodesWithBrokenEntityReferences, $brokenReferencesCount, $workspaceName, $dryRun) { foreach ($nodesWithBrokenEntityReferences as $nodeIdentifier => $properties) { foreach ($properties as $propertyName => $nodeData) { /** @var NodeData $nodeData */ $nodeData->setProperty($propertyName, null); } } $self->output->outputLine('Removed %s broken entity reference%s.', array($brokenReferencesCount, $brokenReferencesCount > 1 ? 's' : '')); }); } else { $this->output->outputLine('Found %s broken entity reference%s to be removed.', array($brokenReferencesCount, $brokenReferencesCount > 1 ? 's' : '')); } $this->output->outputLine(); } }