/** * Creates a big collection of node for performance benchmarking * @param string $siteNode * @param string $preset */ public function nodesCommand($siteNode, $preset) { if (!isset($this->presets[$preset])) { $this->outputLine('Error: Invalid preset'); $this->quit(1); } $preset = $this->presets[$preset]; /** @var Site $currentSite */ $currentSite = $this->siteRepository->findOneByNodeName($siteNode); if ($currentSite === null) { $this->outputLine('Error: No site for exporting found'); $this->quit(1); } /** @var ContentContext $contentContext */ $contentContext = $this->createContext($currentSite, 'live'); $workspace = 'live'; if ($this->workspaceRepository->findByName($workspace)->count() === 0) { $this->outputLine('Workspace "%s" does not exist', array($workspace)); $this->quit(1); } /** @var Node $siteNode */ $siteNode = $contentContext->getCurrentSiteNode(); if ($siteNode === null) { $this->outputLine('Error: No site root node'); $this->quit(1); } $preset = new PresetDefinition($siteNode, $preset); $generator = new NodesGenerator($preset); $generator->generate(); }
public function isActive(NodeInterface $siteNode) { if ($siteModel = $this->siteRepository->findOneByNodeName($siteNode->getName())) { return $siteModel->isOnline(); } throw new \RuntimeException('Could not find a site for the given site node', 1473366137); }
/** * Add a domain record * * @param string $siteNodeName The nodeName of the site rootNode, e.g. "neostypo3org" * @param string $hostPattern The host pattern to match on, e.g. "neos.typo3.org" * @param string $scheme The scheme for linking (http/https) * @param integer $port The port for linking (0-49151) * @return void */ public function addCommand($siteNodeName, $hostPattern, $scheme = null, $port = null) { $site = $this->siteRepository->findOneByNodeName($siteNodeName); if (!$site instanceof Site) { $this->outputLine('<error>No site found with nodeName "%s".</error>', array($siteNodeName)); $this->quit(1); } $domains = $this->domainRepository->findByHostPattern($hostPattern); if ($domains->count() > 0) { $this->outputLine('<error>The host pattern "%s" is not unique.</error>', array($hostPattern)); $this->quit(1); } $domain = new Domain(); if ($scheme !== null) { $domain->setScheme($scheme); } if ($port !== null) { $domain->setPort($port); } $domain->setSite($site); $domain->setHostPattern($hostPattern); $domainValidator = $this->validatorResolver->getBaseValidatorConjunction(Domain::class); $result = $domainValidator->validate($domain); if ($result->hasErrors()) { foreach ($result->getFlattenedErrors() as $propertyName => $errors) { $firstError = array_pop($errors); $this->outputLine('<error>Validation failed for "' . $propertyName . '": ' . $firstError . '</error>'); $this->quit(1); } } $this->domainRepository->add($domain); $this->outputLine('Domain created.'); }
/** * Upload a new image, and return its metadata. * * Depending on the $metadata argument it will return asset metadata for the AssetEditor * or image metadata for the ImageEditor * * @param Asset $asset * @param string $metadata Type of metadata to return ("Asset" or "Image") * @return string */ public function uploadAssetAction(Asset $asset, $metadata) { $this->response->setHeader('Content-Type', 'application/json'); /** @var Site $currentSite */ $currentSite = $this->siteRepository->findOneByNodeName($this->request->getInternalArgument('__siteNodeName')); if ($currentSite !== null && $currentSite->getAssetCollection() !== null) { $currentSite->getAssetCollection()->addAsset($asset); $this->assetCollectionRepository->update($currentSite->getAssetCollection()); } switch ($metadata) { case 'Asset': $result = $this->getAssetProperties($asset); if ($this->persistenceManager->isNewObject($asset)) { $this->assetRepository->add($asset); } break; case 'Image': $result = $this->getImageInterfacePreviewData($asset); if ($this->persistenceManager->isNewObject($asset)) { $this->imageRepository->add($asset); } break; default: $this->response->setStatus(400); $result = array('error' => 'Invalid "metadata" type: ' . $metadata); } return json_encode($result); }
/** * Add a domain record * * @param string $siteNodeName The nodeName of the site rootNode, e.g. "neostypo3org" * @param string $hostPattern The host pattern to match on, e.g. "neos.typo3.org" * @return void */ public function addCommand($siteNodeName, $hostPattern) { $site = $this->siteRepository->findOneByNodeName($siteNodeName); if (!$site instanceof Site) { $this->outputLine('No site found with nodeName "%s".', array($siteNodeName)); $this->quit(1); } $domains = $this->domainRepository->findByHostPattern($hostPattern); if ($domains->count() > 0) { $this->outputLine('The host pattern "%s" is not unique.', array($hostPattern)); $this->quit(1); } $domain = new Domain(); $domain->setSite($site); $domain->setHostPattern($hostPattern); $this->domainRepository->add($domain); $this->outputLine('Domain created.'); }
/** * Updates or creates a site with the given $siteNodeName * * @param string $siteNodeName * @return Site */ protected function getSiteByNodeName($siteNodeName) { $site = $this->siteRepository->findOneByNodeName($siteNodeName); if ($site === null) { $site = new Site($siteNodeName); $this->siteRepository->add($site); return $site; } $this->siteRepository->update($site); return $site; }
/** * Deactivate a site * * This command deactivates the specified site. * * @param string $siteNode The node name of the site to deactivate * @return void */ public function deactivateCommand($siteNode) { $site = $this->siteRepository->findOneByNodeName($siteNode); if (!$site instanceof Site) { $this->outputLine('<error>Site not found.</error>'); $this->quit(1); } $site->setState(Site::STATE_OFFLINE); $this->siteRepository->update($site); $this->outputLine('Site deactivated.'); }
/** * Converts a given context path to a node object * * @param string $contextPath * @return NodeInterface */ public function getNodeFromContextPath($contextPath, Site $site = null, Domain $domain = null) { $nodePathAndContext = NodePaths::explodeContextPath($contextPath); $nodePath = $nodePathAndContext['nodePath']; $workspaceName = $nodePathAndContext['workspaceName']; $dimensions = $nodePathAndContext['dimensions']; $contextProperties = $this->prepareContextProperties($workspaceName, $dimensions); if ($site === null) { list(, , $siteNodeName) = explode('/', $nodePath); $site = $this->siteRepository->findOneByNodeName($siteNodeName); } if ($domain === null) { $domain = $this->domainRepository->findOneBySite($site); } $contextProperties['currentSite'] = $site; $contextProperties['currentDomain'] = $domain; $context = $this->contextFactory->create($contextProperties); $workspace = $context->getWorkspace(false); if (!$workspace) { return new \TYPO3\Flow\Error\Error(sprintf('Could not convert the given source to Node object because the workspace "%s" as specified in the context node path does not exist.', $workspaceName), 1451392329); } return $context->getNode($nodePath); }
/** * Remove all content and related data - for now. In the future we need some more sophisticated cleanup. * * @param string $siteNodeName Name of a site root node to clear only content of this site. * @return void */ public function pruneCommand($siteNodeName = null) { if ($siteNodeName !== null) { $possibleSite = $this->siteRepository->findOneByNodeName($siteNodeName); if ($possibleSite === null) { $this->outputLine('The given site site node did not match an existing site.'); $this->quit(1); } $this->siteService->pruneSite($possibleSite); $this->outputLine('Site with root "' . $siteNodeName . '" has been removed.'); } else { $this->siteService->pruneAll(); $this->outputLine('All sites and content have been removed.'); } }
/** * 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)); }
/** * 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; }
/** * Renders the URI to a given node instance or -path. * * @param ControllerContext $controllerContext * @param mixed $node A node object or a string node path, if a relative path is provided the baseNode argument is required * @param NodeInterface $baseNode * @param string $format Format to use for the URL, for example "html" or "json" * @param boolean $absolute If set, an absolute URI is rendered * @param array $arguments Additional arguments to be passed to the UriBuilder (for example pagination parameters) * @param string $section * @param boolean $addQueryString If set, the current query parameters will be kept in the URI * @param array $argumentsToBeExcludedFromQueryString arguments to be removed from the URI. Only active if $addQueryString = TRUE * @param boolean $resolveShortcuts INTERNAL Parameter - if FALSE, shortcuts are not redirected to their target. Only needed on rare backend occasions when we want to link to the shortcut itself. * @return string The rendered URI * @throws \InvalidArgumentException if the given node/baseNode is not valid * @throws NeosException if no URI could be resolved for the given node */ public function createNodeUri(ControllerContext $controllerContext, $node = null, NodeInterface $baseNode = null, $format = null, $absolute = false, array $arguments = array(), $section = '', $addQueryString = false, array $argumentsToBeExcludedFromQueryString = array(), $resolveShortcuts = true) { $this->lastLinkedNode = null; if (!($node instanceof NodeInterface || is_string($node) || $baseNode instanceof NodeInterface)) { throw new \InvalidArgumentException('Expected an instance of NodeInterface or a string for the node argument, or alternatively a baseNode argument.', 1373101025); } if (is_string($node)) { $nodeString = $node; if ($nodeString === '') { throw new NeosException(sprintf('Empty strings can not be resolved to nodes.', $nodeString), 1415709942); } preg_match(NodeInterface::MATCH_PATTERN_CONTEXTPATH, $nodeString, $matches); if (isset($matches['WorkspaceName']) && $matches['WorkspaceName'] !== '') { $node = $this->propertyMapper->convert($nodeString, 'TYPO3\\TYPO3CR\\Domain\\Model\\NodeInterface'); } else { if ($baseNode === null) { throw new NeosException('The baseNode argument is required for linking to nodes with a relative path.', 1407879905); } /** @var ContentContext $contentContext */ $contentContext = $baseNode->getContext(); $normalizedPath = $this->nodeService->normalizePath($nodeString, $baseNode->getPath(), $contentContext->getCurrentSiteNode()->getPath()); $node = $contentContext->getNode($normalizedPath); } if (!$node instanceof NodeInterface) { throw new NeosException(sprintf('The string "%s" could not be resolved to an existing node.', $nodeString), 1415709674); } } elseif (!$node instanceof NodeInterface) { $node = $baseNode; } if (!$node instanceof NodeInterface) { throw new NeosException(sprintf('Node must be an instance of NodeInterface or string, given "%s".', gettype($node)), 1414772029); } $this->lastLinkedNode = $node; if ($resolveShortcuts === true) { $resolvedNode = $this->nodeShortcutResolver->resolveShortcutTarget($node); } else { // this case is only relevant in extremely rare occasions in the Neos Backend, when we want to generate // a link towards the *shortcut itself*, and not to its target. $resolvedNode = $node; } if (is_string($resolvedNode)) { return $resolvedNode; } if (!$resolvedNode instanceof NodeInterface) { throw new NeosException(sprintf('Could not resolve shortcut target for node "%s"', $node->getPath()), 1414771137); } /** @var ActionRequest $request */ $request = $controllerContext->getRequest()->getMainRequest(); $uriBuilder = clone $controllerContext->getUriBuilder(); $uriBuilder->setRequest($request); $uri = $uriBuilder->reset()->setSection($section)->setArguments($arguments)->setAddQueryString($addQueryString)->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString)->setFormat($format ?: $request->getFormat())->uriFor('show', array('node' => $resolvedNode), 'Frontend\\Node', 'TYPO3.Neos'); $siteNode = $resolvedNode->getContext()->getCurrentSiteNode(); if (NodePaths::isSubPathOf($siteNode->getPath(), $resolvedNode->getPath())) { /** @var Site $site */ $site = $resolvedNode->getContext()->getCurrentSite(); } else { $nodePath = NodePaths::getRelativePathBetween(SiteService::SITES_ROOT_PATH, $resolvedNode->getPath()); list($siteNodeName) = explode('/', $nodePath); $site = $this->siteRepository->findOneByNodeName($siteNodeName); } if ($site->hasActiveDomains()) { $requestUriHost = $request->getHttpRequest()->getBaseUri()->getHost(); $activeHostPatterns = $site->getActiveDomains()->map(function ($domain) { return $domain->getHostPattern(); })->toArray(); if (!in_array($requestUriHost, $activeHostPatterns, true)) { $uri = $this->createSiteUri($controllerContext, $site) . '/' . ltrim($uri, '/'); } elseif ($absolute === true) { $uri = $request->getHttpRequest()->getBaseUri() . ltrim($uri, '/'); } } elseif ($absolute === true) { $uri = $request->getHttpRequest()->getBaseUri() . ltrim($uri, '/'); } return $uri; }