/** * Schedules flushing of the routing cache entry for the given $nodeData * Note: This is not done recursively because the nodePathChanged signal is triggered for any affected node data instance * * @param NodeInterface $node The affected node data instance * @return void */ public function registerNodePathChange(NodeInterface $node) { if (in_array($node->getIdentifier(), $this->tagsToFlush)) { return; } if (!$node->getNodeType()->isOfType('TYPO3.Neos:Document')) { return; } $this->tagsToFlush[] = $node->getIdentifier(); }
/** * Adds the given node to the cache for the given path. The node * will also be added under it's identifier. * * @param string $path * @param NodeInterface $node * @return void */ public function setByPath($path, NodeInterface $node = null) { $this->nodesByPath[$path] = $node; if ($node !== null) { $this->nodesByIdentifier[$node->getIdentifier()] = $node; } }
/** * @param string $nodePathOrIdentifier * @return boolean */ public function isDescendantNodeOf($nodePathOrIdentifier) { if ($this->node === NULL) { return TRUE; } if (preg_match(UuidValidator::PATTERN_MATCH_UUID, $nodePathOrIdentifier) === 1) { if ($this->node->getIdentifier() === $nodePathOrIdentifier) { return TRUE; } $node = $this->getNodeByIdentifier($nodePathOrIdentifier); if ($node === NULL) { return FALSE; } $nodePath = $node->getPath() . '/'; } else { $nodePath = rtrim($nodePathOrIdentifier, '/') . '/'; } return substr($this->node->getPath() . '/', 0, strlen($nodePath)) === $nodePath; }
/** * Register a node change for a later cache flush. This method is triggered by a signal sent via TYPO3CR's Node * model or the Neos Publishing Service. * * @param NodeInterface $node The node which has changed in some way * @return void */ public function registerNodeChange(NodeInterface $node) { $this->tagsToFlush[ContentCache::TAG_EVERYTHING] = 'which were tagged with "Everything".'; $nodeTypesToFlush = $this->getAllImplementedNodeTypes($node->getNodeType()); foreach ($nodeTypesToFlush as $nodeType) { $nodeTypeName = $nodeType->getName(); $this->tagsToFlush['NodeType_' . $nodeTypeName] = sprintf('which were tagged with "NodeType_%s" because node "%s" has changed and was of type "%s".', $nodeTypeName, $node->getPath(), $node->getNodeType()->getName()); } $this->tagsToFlush['Node_' . $node->getIdentifier()] = sprintf('which were tagged with "Node_%s" because node "%s" has changed.', $node->getIdentifier(), $node->getPath()); $originalNode = $node; while ($node->getDepth() > 1) { $node = $node->getParent(); // Workaround for issue #56566 in TYPO3.TYPO3CR if ($node === null) { break; } $tagName = 'DescendantOf_' . $node->getIdentifier(); $this->tagsToFlush[$tagName] = sprintf('which were tagged with "%s" because node "%s" has changed.', $tagName, $originalNode->getPath()); } }
private function renderNode(NodeInterface $node, ControllerContext $controllerContext) { $nodeInfo = ['contextPath' => $node->getContextPath(), 'name' => $node->getName(), 'identifier' => $node->getIdentifier(), 'nodeType' => $node->getNodeType()->getName(), 'properties' => $this->buildNodeProperties($node), 'label' => $node->getLabel(), 'isAutoCreated' => $node->isAutoCreated(), 'children' => []]; if ($node->getNodeType()->isOfType('TYPO3.Neos:Document')) { $nodeInfo['uri'] = $this->uri($node, $controllerContext); } foreach ($node->getChildNodes() as $childNode) { /* @var NodeInterface $childNode */ $nodeInfo['children'][] = ['contextPath' => $childNode->getContextPath(), 'nodeType' => $childNode->getNodeType()->getName()]; } return $nodeInfo; }
/** * @param NodeInterface $article * @return array */ protected function buildSingleItemJson(NodeInterface $article) { $contentCollection = $article->getChildNodes('TYPO3.Neos:ContentCollection')[0]; $articleBody = ''; if ($contentCollection instanceof NodeInterface) { $content = $contentCollection->getChildNodes(); if (is_array($content) && array_key_exists(0, $content)) { foreach ($content as $node) { /** @var NodeInterface $node */ if ($node->getNodeType()->getName() === 'TYPO3.Neos.NodeTypes:Text' || $node->getNodeType()->getName() === 'TYPO3.Neos.NodeTypes:TextWithImage') { $articleBody .= $node->getProperty('text'); } } } } $thumbnailConfiguration = new ThumbnailConfiguration(125, 125, 125, 125, true, true, false); $detailConfiguration = new ThumbnailConfiguration(300, 300, 200, 200, true, true, false); /** @var Image $image */ $image = $article->getProperty('headerImage'); $properties = ['@context' => 'http://schema.org', '@type' => 'Article', '@id' => $article->getIdentifier(), 'id' => $article->getIdentifier(), 'shortIdentifier' => explode('-', $article->getIdentifier())[0], 'title' => $article->getProperty('title'), 'articleBody' => $articleBody, 'publicationDate' => $article->getProperty('publicationDate')->format('D M d Y H:i:s O'), 'teaser' => $article->getProperty('article'), 'listImage' => $this->assetService->getThumbnailUriAndSizeForAsset($image, $thumbnailConfiguration)['src'], 'image' => $this->assetService->getThumbnailUriAndSizeForAsset($image, $detailConfiguration)['src']]; $this->processProperties($properties); return $properties; }
/** * Generates cache tags to be flushed for a node which is flushed on shutdown. * * Code duplicated from Neos' ContentCacheFlusher class * * @param NodeInterface|NodeData $node The node which has changed in some way * @return void */ protected function generateCacheTags($node) { $this->tagsToFlush[ContentCache::TAG_EVERYTHING] = 'which were tagged with "Everything".'; $nodeTypesToFlush = $this->getAllImplementedNodeTypes($node->getNodeType()); foreach ($nodeTypesToFlush as $nodeType) { /** @var NodeType $nodeType */ $nodeTypeName = $nodeType->getName(); $this->tagsToFlush['NodeType_' . $nodeTypeName] = sprintf('which were tagged with "NodeType_%s" because node "%s" has changed and was of type "%s".', $nodeTypeName, $node->getPath(), $node->getNodeType()->getName()); } $this->tagsToFlush['Node_' . $node->getIdentifier()] = sprintf('which were tagged with "Node_%s" because node "%s" has changed.', $node->getIdentifier(), $node->getPath()); while ($node->getDepth() > 1) { $node = $node->getParent(); if ($node === NULL) { break; } $this->tagsToFlush['DescendantOf_' . $node->getIdentifier()] = sprintf('which were tagged with "DescendantOf_%s" because node "%s" has changed.', $node->getIdentifier(), $node->getPath()); } if ($node instanceof NodeInterface && $node->getContext() instanceof ContentContext) { $firstActiveDomain = $node->getContext()->getCurrentSite()->getFirstActiveDomain(); if ($firstActiveDomain) { $this->domainsToFlush[] = $firstActiveDomain->getHostPattern(); } } }
/** * Resolves the given $nodePathOrIdentifier and returns its absolute path and or a boolean if the result directly matches the currently selected node * * @param string $nodePathOrIdentifier identifier or absolute path for the node to resolve * @return bool|string TRUE if the node matches the selected node, FALSE if the corresponding node does not exist. Otherwise the resolved absolute path with trailing slash */ protected function resolveNodePath($nodePathOrIdentifier) { if ($this->node === null) { return true; } if (preg_match(UuidValidator::PATTERN_MATCH_UUID, $nodePathOrIdentifier) !== 1) { return rtrim($nodePathOrIdentifier, '/') . '/'; } if ($this->node->getIdentifier() === $nodePathOrIdentifier) { return true; } $node = $this->getNodeByIdentifier($nodePathOrIdentifier); if ($node === null) { return false; } return $node->getPath() . '/'; }
/** * * * @param NodeInterface $node * @param array $fulltextIndexOfNode * @param string $targetWorkspaceName * @return void */ protected function updateFulltext(NodeInterface $node, array $fulltextIndexOfNode, $targetWorkspaceName = NULL) { if ($targetWorkspaceName !== NULL && $targetWorkspaceName !== 'live' || $node->getWorkspace()->getName() !== 'live' || count($fulltextIndexOfNode) === 0) { return; } $closestFulltextNode = $node; while (!$this->isFulltextRoot($closestFulltextNode)) { $closestFulltextNode = $closestFulltextNode->getParent(); if ($closestFulltextNode === NULL) { // root of hierarchy, no fulltext root found anymore, abort silently... $this->logger->log('No fulltext root found for ' . $node->getPath(), LOG_WARNING); return; } } $closestFulltextNodeContextPath = str_replace($closestFulltextNode->getContext()->getWorkspace()->getName(), 'live', $closestFulltextNode->getContextPath()); $closestFulltextNodeContextPathHash = sha1($closestFulltextNodeContextPath); $this->currentBulkRequest[] = array(array('update' => array('_type' => NodeTypeMappingBuilder::convertNodeTypeNameToMappingName($closestFulltextNode->getNodeType()->getName()), '_id' => $closestFulltextNodeContextPathHash)), array('script' => ' if (!ctx._source.containsKey("__fulltextParts")) { ctx._source.__fulltextParts = new LinkedHashMap(); } ctx._source.__fulltextParts[identifier] = fulltext; ctx._source.__fulltext = new LinkedHashMap(); Iterator<LinkedHashMap.Entry<String, LinkedHashMap>> fulltextByNode = ctx._source.__fulltextParts.entrySet().iterator(); for (fulltextByNode; fulltextByNode.hasNext();) { Iterator<LinkedHashMap.Entry<String, String>> elementIterator = fulltextByNode.next().getValue().entrySet().iterator(); for (elementIterator; elementIterator.hasNext();) { Map.Entry<String, String> element = elementIterator.next(); String value; if (ctx._source.__fulltext.containsKey(element.key)) { value = ctx._source.__fulltext[element.key] + " " + element.value.trim(); } else { value = element.value.trim(); } ctx._source.__fulltext[element.key] = value; } } ', 'params' => array('identifier' => $node->getIdentifier(), 'fulltext' => $fulltextIndexOfNode), 'upsert' => array('__fulltext' => $fulltextIndexOfNode, '__fulltextParts' => array($node->getIdentifier() => $fulltextIndexOfNode)), 'lang' => 'groovy')); }
/** * Set the "context node" this operation was working on. * * @param NodeInterface $node * @return void */ public function setNode(NodeInterface $node) { $this->nodeIdentifier = $node->getIdentifier(); $this->workspaceName = $node->getContext()->getWorkspaceName(); $this->dimension = $node->getContext()->getDimensions(); $context = $node->getContext(); if ($context instanceof ContentContext && $context->getCurrentSite() !== null) { $siteIdentifier = $this->persistenceManager->getIdentifierByObject($context->getCurrentSite()); } else { $siteIdentifier = null; } $this->data = Arrays::arrayMergeRecursiveOverrule($this->data, array('nodeContextPath' => $node->getContextPath(), 'nodeLabel' => $node->getLabel(), 'nodeType' => $node->getNodeType()->getName(), 'site' => $siteIdentifier)); $node = self::getClosestAggregateNode($node); if ($node !== null) { $this->documentNodeIdentifier = $node->getIdentifier(); $this->data = Arrays::arrayMergeRecursiveOverrule($this->data, array('documentNodeContextPath' => $node->getContextPath(), 'documentNodeLabel' => $node->getLabel(), 'documentNodeType' => $node->getNodeType()->getName())); } }
/** * @param NodeInterface $node * @param array $data * @param string $identifiersToCheck * @param string $dataToClear * @param string $exceptionMessage * * @throws \Exception */ protected function removeEventFromUser(NodeInterface $node, array &$data, $identifiersToCheck = 'personEventsIdentifiers', $dataToClear = 'personEvents', $exceptionMessage = '') { if (in_array($node->getIdentifier(), $data[$identifiersToCheck], true)) { $keyToRemove = []; foreach ($data[$dataToClear] as $key => $personEvent) { /** @var NodeInterface $personEvent */ if ($personEvent->getIdentifier() === $node->getIdentifier()) { $keyToRemove[] = $key; } else { continue; } } if ($keyToRemove !== []) { foreach ($keyToRemove as $key) { unset($data[$dataToClear][$key]); } } } else { throw new \Exception($exceptionMessage, 12415423123.0); } }
/** * This low-level method can be used to look up the full ElasticSearch hit given a certain node. * * @param NodeInterface $node * @return array the ElasticSearch hit for the node as array, or NULL if it does not exist. */ public function getFullElasticSearchHitForNode(NodeInterface $node) { if (isset($this->elasticSearchHitsIndexedByNodeFromLastRequest[$node->getIdentifier()])) { return $this->elasticSearchHitsIndexedByNodeFromLastRequest[$node->getIdentifier()]; } return null; }
/** * Collects metadata attributes used to allow editing of the node in the Neos backend. * * @param array $attributes * @param NodeInterface $node * @return array */ protected function addGenericEditingMetadata(array $attributes, NodeInterface $node) { $attributes['typeof'] = 'typo3:' . $node->getNodeType()->getName(); $attributes['about'] = $node->getContextPath(); $attributes['data-node-_identifier'] = $node->getIdentifier(); $attributes['data-node-__workspace-name'] = $node->getWorkspace()->getName(); $attributes['data-node-__label'] = $node->getLabel(); if ($node->getNodeType()->isOfType('TYPO3.Neos:ContentCollection')) { $attributes['rel'] = 'typo3:content-collection'; } // these properties are needed together with the current NodeType to evaluate Node Type Constraints // TODO: this can probably be greatly cleaned up once we do not use CreateJS or VIE anymore. if ($node->getParent()) { $attributes['data-node-__parent-node-type'] = $node->getParent()->getNodeType()->getName(); } if ($node->isAutoCreated()) { $attributes['data-node-_name'] = $node->getName(); $attributes['data-node-_is-autocreated'] = 'true'; } if ($node->getParent() && $node->getParent()->isAutoCreated()) { $attributes['data-node-_parent-is-autocreated'] = 'true'; // we shall only add these properties if the parent is actually auto-created; as the Node-Type-Switcher in the UI relies on that. $attributes['data-node-__parent-node-name'] = $node->getParent()->getName(); $attributes['data-node-__grandparent-node-type'] = $node->getParent()->getParent()->getNodeType()->getName(); } return $attributes; }
/** * Wrap the $content identified by $node with the needed markup for * the backend. * $parameters can be used to further pass parameters to the content element. * * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $node * @param string $typoscriptPath * @param string $content * @param boolean $isPage * @return string */ public function wrapContentObject(\TYPO3\TYPO3CR\Domain\Model\NodeInterface $node, $typoscriptPath, $content, $isPage = FALSE) { $contentType = $node->getContentType(); $tagBuilder = new \TYPO3\Fluid\Core\ViewHelper\TagBuilder('div'); $tagBuilder->forceClosingTag(TRUE); if (!$node->isRemoved()) { $tagBuilder->setContent($content); } if (!$isPage) { $cssClasses = array('t3-contentelement'); $cssClasses[] = str_replace(array(':', '.'), '-', strtolower($contentType->getName())); if ($node->isHidden()) { $cssClasses[] = 't3-contentelement-hidden'; } if ($node->isRemoved()) { $cssClasses[] = 't3-contentelement-removed'; } $tagBuilder->addAttribute('class', implode(' ', $cssClasses)); $tagBuilder->addAttribute('id', 'c' . $node->getIdentifier()); } try { $this->accessDecisionManager->decideOnResource('TYPO3_TYPO3_Backend_BackendController'); } catch (\TYPO3\FLOW3\Security\Exception\AccessDeniedException $e) { return $tagBuilder->render(); } $tagBuilder->addAttribute('typeof', 'typo3:' . $contentType->getName()); $tagBuilder->addAttribute('about', $node->getContextPath()); $this->addScriptTag($tagBuilder, '__workspacename', $node->getWorkspace()->getName()); $this->addScriptTag($tagBuilder, '_removed', $node->isRemoved() ? 'true' : 'false', 'boolean'); $this->addScriptTag($tagBuilder, '_typoscriptPath', $typoscriptPath); foreach ($contentType->getProperties() as $propertyName => $propertyConfiguration) { $dataType = isset($propertyConfiguration['type']) ? $propertyConfiguration['type'] : 'string'; if ($propertyName[0] === '_') { $propertyValue = \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($node, substr($propertyName, 1)); } else { $propertyValue = $node->getProperty($propertyName); } // Serialize boolean values to String if (isset($propertyConfiguration['type']) && $propertyConfiguration['type'] === 'boolean') { $propertyValue = $propertyValue ? 'true' : 'false'; } // Serialize date values to String if ($propertyValue !== NULL && isset($propertyConfiguration['type']) && $propertyConfiguration['type'] === 'date') { $propertyValue = $propertyValue->format('Y-m-d'); } // Serialize objects to JSON strings if (is_object($propertyValue) && $propertyValue !== NULL && isset($propertyConfiguration['type']) && $this->objectManager->isRegistered($propertyConfiguration['type'])) { $gettableProperties = \TYPO3\FLOW3\Reflection\ObjectAccess::getGettableProperties($propertyValue); $convertedProperties = array(); foreach ($gettableProperties as $key => $value) { if (is_object($value)) { $entityIdentifier = $this->persistenceManager->getIdentifierByObject($value); if ($entityIdentifier !== NULL) { $value = $entityIdentifier; } } $convertedProperties[$key] = $value; } $propertyValue = json_encode($convertedProperties); $dataType = 'jsonEncoded'; } $this->addScriptTag($tagBuilder, $propertyName, $propertyValue, $dataType); } if (!$isPage) { // add CSS classes $this->addScriptTag($tagBuilder, '__contenttype', $contentType->getName()); } else { $tagBuilder->addAttribute('id', 't3-page-metainformation'); $tagBuilder->addAttribute('data-__sitename', $this->nodeRepository->getContext()->getCurrentSite()->getName()); $tagBuilder->addAttribute('data-__siteroot', sprintf('/sites/%s@%s', $this->nodeRepository->getContext()->getCurrentSite()->getNodeName(), $this->nodeRepository->getContext()->getWorkspace()->getName())); } return $tagBuilder->render(); }
protected function getACLPropertiesForNode(NodeInterface $node) { $properties = ['nodeIdentifier' => $node->getIdentifier(), 'nodePath' => $node->getPath(), 'nodeLabel' => $node->getLabel(), 'nodeType' => $node->getNodeType()->getName(), 'nodeLevel' => $node->getDepth()]; return $properties; }
/** * @param NodeInterface $referenceNode * @param string $action * @throws AccessDeniedException */ protected function checkNodeEditAccess(NodeInterface $referenceNode, $action = 'remove') { $nodeType = $referenceNode->getNodeType()->getName(); if ($this->securityContext->hasRole('SimplyAdmire.Cap.Api:Editor')) { return; } if ($nodeType === 'SimplyAdmire.Cap.PersonBundle:Person') { $identifier = $referenceNode->getIdentifier(); if ($identifier === $this->getActiveProfile()->getIdentifier()) { return; } } $author = $referenceNode->getProperty('author'); if ($author instanceof NodeInterface) { $identifier = $referenceNode->getProperty('author')->getIdentifier(); if ($identifier === $this->getActiveProfile()->getIdentifier()) { return; } } throw new AccessDeniedException('You do not have access to ' . $action . ' this node'); }
/** * @param string $externalIdentifier * @param NodeInterface $node * @return ProcessedNodeDefinition */ public static function createFromNode($externalIdentifier, NodeInterface $node) { return new ProcessedNodeDefinition($node->getIdentifier(), $node->getPath(), $externalIdentifier); }
/** * returns a specific view node of an master plugin * or NULL if it does not exist * * @param NodeInterface $node * @param string $viewName * @return NodeInterface */ public function getPluginViewNodeByMasterPlugin(NodeInterface $node, $viewName) { /** @var $context ContentContext */ $context = $node->getContext(); foreach ($this->getNodes(['TYPO3.Neos:PluginView'], $context) as $pluginViewNode) { /** @var \TYPO3\TYPO3CR\Domain\Model\NodeInterface $pluginViewNode */ if ($pluginViewNode->isRemoved()) { continue; } if ($pluginViewNode->getProperty('plugin') === $node->getIdentifier() && $pluginViewNode->getProperty('view') === $viewName) { return $pluginViewNode; } } return null; }
/** * Adopts a node from a (possibly) different context to this context * * Check if a node variant already exists for this context and return it if found. Otherwise a new node variant for * this context is created. * * @param NodeInterface $node The node with a different context. If the context of the given node is the same as this context the operation will have no effect. * @return NodeInterface A new or existing node that matches this context */ public function adoptNode(NodeInterface $node) { if ($node->getContext() === $this) { return $node; } $existingNode = $this->getNodeByIdentifier($node->getIdentifier()); if ($existingNode !== NULL) { return $existingNode; } return $node->createVariantForContext($this); }
/** * @param NodeInterface $event * @return array */ protected function buildSingleItemJson($event) { $properties = ['@context' => ['ical' => 'http://www.w3.org/2002/12/cal/ical#', 'xsd' => 'http://www.w3.org/2001/XMLSchema#', 'ical:dtstart' => ['@type' => 'xsd:dateTime']], '@id' => $event->getIdentifier(), 'id' => $event->getIdentifier(), 'shortIdentifier' => explode('-', $event->getIdentifier())[0], 'title' => $event->getProperty('title'), 'startDate' => $event->getProperty('start')->format('D M d Y H:i:s O'), 'endDate' => $event->getProperty('end')->format('D M d Y H:i:s O')]; $this->processProperties($properties); return $properties; }
/** * Returns the NodeData instance with the given identifier from the target workspace. * If no NodeData instance is found, NULL is returned. * * @param NodeInterface $node * @param Workspace $targetWorkspace * @return NodeData */ protected function findNodeDataInTargetWorkspace(NodeInterface $node, Workspace $targetWorkspace) { $properties = $node->getContext()->getProperties(); $properties['workspaceName'] = $targetWorkspace->getName(); $targetWorkspaceContext = $this->contextFactory->create($properties); $targetNodeInstance = $targetWorkspaceContext->getNodeByIdentifier($node->getIdentifier()); $targetNode = $targetNodeInstance !== NULL ? $targetNodeInstance->getNodeData() : NULL; return $targetNode; }
/** * @param NodeInterface $node * @return void */ public function refreshCacheIfNecessary(NodeInterface $node) { if ($node->getNodeType()->isOfType('Nezaniel.SystemNodes:SystemNode')) { $currentPath = []; $recursiveIterator = function (array $items) use(&$recursiveIterator, &$currentPath, $node) { foreach ($items as $key => $entry) { $currentPath[] = $key; if (is_array($entry)) { $recursiveIterator($entry); } elseif ($entry === $node->getIdentifier()) { $this->systemNodeIdentifiers = Arrays::unsetValueByPath($this->systemNodeIdentifiers, $currentPath); } array_pop($currentPath); } }; $recursiveIterator($this->systemNodeIdentifiers); $this->initializeSystemNode($node); $this->cache->set('systemNodeIdentifiers', $this->systemNodeIdentifiers); } }
/** * @param NodeInterface $node * @return void */ protected function indexAllNodeVariants(NodeInterface $node) { $nodeIdentifier = $node->getIdentifier(); $allIndexedVariants = $this->indexClient->query('SELECT __identifier__ FROM objects WHERE __identifier = "' . $nodeIdentifier . '"'); foreach ($allIndexedVariants as $nodeVariant) { $this->indexClient->removeData($nodeVariant['__identifier__']); } foreach ($this->workspaceRepository->findAll() as $workspace) { $this->indexNodeInWorkspace($nodeIdentifier, $workspace->getName()); } }
/** * Method which does the actual work of discarding, includes a protection against endless recursions and * multiple discarding of the same node. * * @param NodeInterface $node The node to discard * @param array &$alreadyDiscardedNodeIdentifiers List of node identifiers which already have been discarded during one discardNode() run * @return void * @throws \TYPO3\TYPO3CR\Exception\WorkspaceException */ protected function doDiscardNode(NodeInterface $node, array &$alreadyDiscardedNodeIdentifiers = []) { if ($node->getWorkspace()->getBaseWorkspace() === null) { throw new WorkspaceException('Nodes in a in a workspace without a base workspace cannot be discarded.', 1395841899); } if ($node->getPath() === '/') { return; } if (array_search($node->getIdentifier(), $alreadyDiscardedNodeIdentifiers) !== false) { return; } $alreadyDiscardedNodeIdentifiers[] = $node->getIdentifier(); $possibleShadowNodeData = $this->nodeDataRepository->findOneByMovedTo($node->getNodeData()); if ($possibleShadowNodeData instanceof NodeData) { if ($possibleShadowNodeData->getMovedTo() !== null) { $parentBasePath = $node->getPath(); $affectedChildNodeDataInSameWorkspace = $this->nodeDataRepository->findByParentAndNodeType($parentBasePath, null, $node->getWorkspace(), null, false, true); foreach ($affectedChildNodeDataInSameWorkspace as $affectedChildNodeData) { /** @var NodeData $affectedChildNodeData */ $affectedChildNode = $this->nodeFactory->createFromNodeData($affectedChildNodeData, $node->getContext()); $this->doDiscardNode($affectedChildNode, $alreadyDiscardedNodeIdentifiers); } } $this->nodeDataRepository->remove($possibleShadowNodeData); } $this->nodeDataRepository->remove($node); $this->emitNodeDiscarded($node); }
/** * Retrieves the given node's corresponding node in the base workspace (that is, which would be overwritten if the * given node would be published) * * @param NodeInterface $modifiedNode * @return NodeInterface */ protected function getOriginalNode(NodeInterface $modifiedNode) { $baseWorkspaceName = $modifiedNode->getWorkspace()->getBaseWorkspace()->getName(); $contextProperties = $modifiedNode->getContext()->getProperties(); $contextProperties['workspaceName'] = $baseWorkspaceName; $contentContext = $this->contextFactory->create($contextProperties); return $contentContext->getNodeByIdentifier($modifiedNode->getIdentifier()); }
/** * Resolve an URI for the given node in the live workspace (this is where analytics usually are collected) * * @param NodeInterface $node * @param ControllerContext $controllerContext * @return \TYPO3\Flow\Http\Uri * @throws StatisticsNotAvailableException If the node was not yet published and no live workspace URI can be resolved */ protected function getLiveNodeUri(NodeInterface $node, ControllerContext $controllerContext) { $contextProperties = $node->getContext()->getProperties(); $contextProperties['workspaceName'] = 'live'; $liveContext = $this->contextFactory->create($contextProperties); $liveNode = $liveContext->getNodeByIdentifier($node->getIdentifier()); if ($liveNode === NULL) { throw new StatisticsNotAvailableException('Piwik Statistics are only available on a published node', 1445812693); } $nodeUriString = $this->linkingService->createNodeUri($controllerContext, $liveNode, NULL, 'html', TRUE); $nodeUri = new \TYPO3\Flow\Http\Uri($nodeUriString); return $nodeUri; }
/** * Returns the NodeData instance with the given identifier from the target workspace. * If no NodeData instance is found, NULL is returned. * * @param NodeInterface $node * @param Workspace $targetWorkspace * @return NodeData */ protected function findNodeDataInTargetWorkspace(NodeInterface $node, Workspace $targetWorkspace) { $nodeData = $this->nodeDataRepository->findOneByIdentifier($node->getIdentifier(), $targetWorkspace, $node->getDimensions()); return $nodeData === null || $nodeData->getWorkspace() === $targetWorkspace ? $nodeData : null; }
private function sendNewsletter(NodeInterface $node, $previewEmail = NULL, $languageKey = NULL, array $languageConfiguration = NULL) { // The Receiver Group association is specified in each individual node dimension, // but as the user submitted it in a certain Node Dimension, we're using *exactly* this // $receiverGroup which the user has submitted. /* @var $receiverGroup \Sandstorm\Newsletter\Domain\Model\ReceiverGroup */ $receiverGroup = $this->receiverGroupRepository->findByIdentifier($node->getProperty('receiverGroup')); if ($receiverGroup == NULL) { // TODO: log! return; } $context = ['workspaceName' => 'live']; if ($languageKey) { $context['dimensions'] = array('language' => $languageConfiguration['values']); $context['targetDimensions'] = array('language' => reset($languageConfiguration['values'])); } /* @var $nodeInCorrectDimension NodeInterface */ $nodeInCorrectDimension = (new FlowQuery(array($node)))->context($context)->get(0); if ($nodeInCorrectDimension == NULL) { // Skip un-existing nodes return; } $this->newsletterRenderingView->assign('value', $nodeInCorrectDimension); $html = $this->newsletterRenderingView->render(); $html = $this->styleInliningService->inlineStyles($html); $newsletter = new Newsletter(); $newsletterIdentifier = $node->getIdentifier(); if ($languageKey) { $newsletterIdentifier .= '_' . $languageKey; } if ($previewEmail) { $newsletterIdentifier .= uniqid('__', true); } $newsletter->setIdentifier($newsletterIdentifier); $newsletter->setHtmlContent($html); $newsletter->setSubject($nodeInCorrectDimension->getProperty('subjectTemplate')); if ($previewEmail !== NULL) { $newsletter->setReceiverEmailTemplate($previewEmail); $newsletter->setReceiverGroup($receiverGroup->singlePersonReceiverGroup()); } else { $newsletter->setReceiverEmailTemplate($nodeInCorrectDimension->getProperty('receiverEmailTemplate')); $newsletter->setReceiverGroup($receiverGroup); } $newsletter->setReceiverNameTemplate($nodeInCorrectDimension->getProperty('receiverNameTemplate')); $newsletter->setSenderEmailTemplate($nodeInCorrectDimension->getProperty('senderEmailTemplate')); $newsletter->setSenderNameTemplate($nodeInCorrectDimension->getProperty('senderNameTemplate')); $newsletter->setReplyToEmailTemplate($nodeInCorrectDimension->getProperty('replyToEmailTemplate')); $newsletter->setNewsletterLink($this->linkingService->createNodeUri($this->getControllerContext(), $nodeInCorrectDimension, NULL, NULL, TRUE)); $unsubscribeListIdentifier = null; if ($receiverGroup->getUnsubscribeList()) { $unsubscribeListIdentifier = $this->persistenceManager->getIdentifierByObject($receiverGroup->getUnsubscribeList()); } $newsletter->setUnsubscribeLink($this->uriBuilder->reset()->setCreateAbsoluteUri(TRUE)->uriFor('unsubscribe', array('unsubscribeList' => $unsubscribeListIdentifier), 'Unsubscribe', 'Sandstorm.Newsletter')); $this->newsletterSendingService->sendNewsletter($newsletter, $languageKey); }