/**
  * Shows the specified node and takes visibility and access restrictions into
  * account.
  *
  * @param NodeInterface $node
  * @return string View output for the specified node
  * @Flow\SkipCsrfProtection We need to skip CSRF protection here because this action could be called with unsafe requests from widgets or plugins that are rendered on the node - For those the CSRF token is validated on the sub-request, so it is safe to be skipped here
  * @Flow\IgnoreValidation("node")
  * @throws NodeNotFoundException
  */
 public function showAction(NodeInterface $node = NULL)
 {
     if ($node === NULL) {
         throw new NodeNotFoundException('The requested node does not exist or isn\'t accessible to the current user', 1430218623);
     }
     if (!$node->getContext()->isLive() && !$this->privilegeManager->isPrivilegeTargetGranted('TYPO3.Neos:Backend.GeneralAccess')) {
         $this->redirect('index', 'Login', NULL, array('unauthorized' => TRUE));
     }
     $inBackend = $node->getContext()->isInBackend();
     if ($node->getNodeType()->isOfType('TYPO3.Neos:Shortcut') && !$inBackend) {
         $this->handleShortcutNode($node);
     }
     $this->view->assign('value', $node);
     if ($inBackend) {
         $this->overrideViewVariablesFromInternalArguments();
         /** @var UserInterfaceMode $renderingMode */
         $renderingMode = $node->getContext()->getCurrentRenderingMode();
         $this->response->setHeader('Cache-Control', 'no-cache');
         if ($renderingMode !== NULL) {
             // Deprecated TypoScript context variable from version 2.0.
             $this->view->assign('editPreviewMode', $renderingMode->getTypoScriptPath());
         }
         if (!$this->view->canRenderWithNodeAndPath()) {
             $this->view->setTypoScriptPath('rawContent');
         }
     }
     if ($this->session->isStarted() && $inBackend) {
         $this->session->putData('lastVisitedNode', $node->getContextPath());
     }
 }
 /**
  * Set the node title for the newly created Document node
  *
  * @param NodeInterface $node The newly created node
  * @param array $data incoming data from the creationDialog
  * @return void
  */
 public function handle(NodeInterface $node, array $data)
 {
     if (isset($data['title']) && $node->getNodeType()->isOfType('TYPO3.Neos:Document')) {
         $node->setProperty('title', $data['title']);
         $node->setProperty('uriPathSegment', NodeUtility::renderValidNodeName($data['title']));
     }
 }
 /**
  * Resolves a shortcut node to the target. The return value can be
  *
  * * a NodeInterface instance if the target is a node or a node:// URI
  * * a string (in case the target is a plain text URI or an asset:// URI)
  * * NULL in case the shortcut cannot be resolved
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $node
  * @return NodeInterface|string|NULL
  */
 public function resolveShortcutTarget(NodeInterface $node)
 {
     $infiniteLoopPrevention = 0;
     while ($node->getNodeType()->isOfType('TYPO3.Neos:Shortcut') && $infiniteLoopPrevention < 50) {
         $infiniteLoopPrevention++;
         switch ($node->getProperty('targetMode')) {
             case 'selectedTarget':
                 $target = $node->getProperty('target');
                 if ($this->linkingService->hasSupportedScheme($target)) {
                     $targetObject = $this->linkingService->convertUriToObject($target, $node);
                     if ($targetObject instanceof NodeInterface) {
                         $node = $targetObject;
                     } elseif ($targetObject instanceof AssetInterface) {
                         return $this->linkingService->resolveAssetUri($target);
                     }
                 } else {
                     return $target;
                 }
                 break;
             case 'parentNode':
                 $node = $node->getParent();
                 break;
             case 'firstChildNode':
             default:
                 $childNodes = $node->getChildNodes('TYPO3.Neos:Document');
                 if ($childNodes !== array()) {
                     $node = reset($childNodes);
                 } else {
                     return null;
                 }
         }
     }
     return $node;
 }
Example #4
0
 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);
 }
 /**
  * Creates a new comment
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $postNode The post node which will contain the new comment
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeTemplate<RobertLemke.Plugin.Blog:Comment> $nodeTemplate
  * @return void
  */
 public function createAction(NodeInterface $postNode, NodeTemplate $newComment)
 {
     # Workaround until we can validate node templates properly:
     if (strlen($newComment->getProperty('author')) < 2) {
         $this->addFlashMessage('Your comment was NOT created - please specify your name.');
         $this->redirect('show', 'Frontend\\Node', 'TYPO3.Neos', array('node' => $postNode));
     }
     if (strlen($newComment->getProperty('text')) < 5) {
         $this->addFlashMessage('Your comment was NOT created - it was too short.');
         $this->redirect('show', 'Frontend\\Node', 'TYPO3.Neos', array('node' => $postNode));
     }
     if (filter_var($newComment->getProperty('emailAddress'), FILTER_VALIDATE_EMAIL) === FALSE) {
         $this->addFlashMessage('Your comment was NOT created - you must specify a valid email address.');
         $this->redirect('show', 'Frontend\\Node', 'TYPO3.Neos', array('node' => $postNode));
     }
     $commentNode = $postNode->getNode('comments')->createNodeFromTemplate($newComment, uniqid('comment-'));
     $commentNode->setProperty('spam', FALSE);
     $commentNode->setProperty('datePublished', new \DateTime());
     if ($this->akismetService->isCommentSpam('', $commentNode->getProperty('text'), 'comment', $commentNode->getProperty('author'), $commentNode->getProperty('emailAddress'))) {
         $commentNode->setProperty('spam', TRUE);
     }
     $this->addFlashMessage('Your new comment was created.');
     $this->emitCommentCreated($commentNode, $postNode);
     $this->redirect('show', 'Frontend\\Node', 'TYPO3.Neos', array('node' => $postNode));
 }
 /**
  * @param NodeInterface $parentNode
  * @param NodeType $nodeType
  * @return NodeInterface|void
  */
 public function create(NodeInterface $parentNode, NodeType $nodeType)
 {
     $title = Company::name();
     $name = Utility::renderValidNodeName($title);
     $childrenNode = $parentNode->createNode($name, $nodeType);
     $childrenNode->setProperty('title', $title);
     return $childrenNode;
 }
 /**
  * Helper method to retrieve the closest document for a node
  *
  * @param NodeInterface $node
  * @return NodeInterface
  */
 public function getClosestDocument(NodeInterface $node)
 {
     if ($node->getNodeType()->isOfType('TYPO3.Neos:Document')) {
         return $node;
     }
     $flowQuery = new FlowQuery(array($node));
     return $flowQuery->closest('[instanceof TYPO3.Neos:Document]')->get(0);
 }
 /**
  * Returns TRUE if the given node has the property and the value is not empty.
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $node
  * @return boolean
  */
 public function matches(\TYPO3\TYPO3CR\Domain\Model\NodeInterface $node)
 {
     if ($node->hasProperty($this->propertyName)) {
         $propertyValue = $node->getProperty($this->propertyName);
         return !empty($propertyValue);
     }
     return FALSE;
 }
 /**
  * @param NodeInterface $contextNode The node for which the preceding node should be found
  * @return NodeInterface The following node of $contextNode or NULL
  */
 protected function getNextForNode($contextNode)
 {
     $nodesInContext = $contextNode->getParent()->getChildNodes();
     for ($i = 1; $i < count($nodesInContext); $i++) {
         if ($nodesInContext[$i - 1] === $contextNode) {
             return $nodesInContext[$i];
         }
     }
     return null;
 }
 /**
  * @test
  */
 public function overridingFromTypoScriptInFilesystemFollowingNodePathsWorks()
 {
     $typoScriptService = $this->objectManager->get('TYPO3\\TYPO3\\Domain\\Service\\TypoScriptService');
     ObjectAccess::setProperty($typoScriptService, 'typoScriptsPathPattern', __DIR__ . '/Fixtures/ResourcesFixture/TypoScripts', TRUE);
     $objectTree = $typoScriptService->getMergedTypoScriptObjectTree($this->homeNode, $this->homeNode->getNode('about-us/history'));
     $this->assertEquals('Root', $objectTree['text1']['value']);
     $this->assertEquals('AboutUs', $objectTree['text2']['value']);
     $this->assertEquals('History', $objectTree['text3']['value']);
     $this->assertEquals('Additional', $objectTree['text4']['value']);
 }
 /**
  * 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();
 }
 /**
  * @param NodeInterface $contextNode The node for which the preceding node should be found
  * @return NodeInterface The preceding node of $contextNode or NULL
  */
 protected function getPrevForNode($contextNode)
 {
     $nodesInContext = $contextNode->getParent()->getChildNodes();
     for ($i = 0; $i < count($nodesInContext) - 1; $i++) {
         if ($nodesInContext[$i + 1] === $contextNode) {
             return $nodesInContext[$i];
         }
     }
     return NULL;
 }
Example #13
0
 /**
  * Returns TRUE if the given node is of the node type this filter expects.
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $node
  * @return boolean
  */
 public function matches(\TYPO3\TYPO3CR\Domain\Model\NodeInterface $node)
 {
     if ($this->withSubTypes === TRUE) {
         return $this->nodeTypeManager->getNodeType($node->getNodeType())->isOfType($this->nodeTypeName);
     } else {
         $nodeData = \TYPO3\Flow\Reflection\ObjectAccess::getProperty($node, 'nodeData', TRUE);
         $nodeType = \TYPO3\Flow\Reflection\ObjectAccess::getProperty($nodeData, 'nodeType', TRUE);
         return $nodeType === $this->nodeTypeName;
     }
 }
 /**
  * @param NodeInterface $node A document node
  * @return string
  */
 public function render(NodeInterface $node)
 {
     $output = '/' . $node->getLabel();
     $flowQuery = new FlowQuery(array($node));
     $nodes = $flowQuery->parents('[instanceof TYPO3.Neos:Document]')->get();
     /** @var NodeInterface $node */
     foreach ($nodes as $node) {
         $output = '/' . $node->getLabel() . $output;
     }
     return $output;
 }
Example #15
0
 /**
  * Filter a node by the current context.
  * Will either return the node or NULL if it is not permitted in current context.
  *
  * @param NodeInterface $node
  * @param Context $context
  * @return \TYPO3\TYPO3CR\Domain\Model\Node|NULL
  */
 protected function filterNodeByContext(NodeInterface $node, Context $context)
 {
     if (!$context->isRemovedContentShown() && $node->isRemoved()) {
         return NULL;
     }
     if (!$context->isInvisibleContentShown() && !$node->isVisible()) {
         return NULL;
     }
     if (!$context->isInaccessibleContentShown() && !$node->isAccessible()) {
         return NULL;
     }
     return $node;
 }
 public function setUp()
 {
     $this->siteNode = $this->getMock('TYPO3\\TYPO3CR\\Domain\\Model\\NodeInterface');
     $this->firstLevelNode = $this->getMock('TYPO3\\TYPO3CR\\Domain\\Model\\NodeInterface');
     $this->secondLevelNode = $this->getMock('TYPO3\\TYPO3CR\\Domain\\Model\\NodeInterface');
     $this->siteNode->expects($this->any())->method('getPath')->will($this->returnValue('/site'));
     $this->siteNode->expects($this->any())->method('getChildNodes')->will($this->returnValue(array($this->firstLevelNode)));
     $this->mockContext = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Service\\Context')->disableOriginalConstructor()->getMock();
     $this->firstLevelNode->expects($this->any())->method('getParent')->will($this->returnValue($this->siteNode));
     $this->firstLevelNode->expects($this->any())->method('getPath')->will($this->returnValue('/site/first'));
     $this->secondLevelNode->expects($this->any())->method('getParent')->will($this->returnValue($this->siteNode));
     $this->secondLevelNode->expects($this->any())->method('getPath')->will($this->returnValue('/site/first/second'));
 }
 /**
  * @param NodeInterface $contextNode The node for which the preceding node should be found
  * @return NodeInterface The preceding nodes of $contextNode or NULL
  */
 protected function getNextForNode(NodeInterface $contextNode)
 {
     $nodesInContext = $contextNode->getParent()->getChildNodes();
     $count = count($nodesInContext);
     for ($i = 0; $i < $count; $i++) {
         if ($nodesInContext[$i] === $contextNode) {
             unset($nodesInContext[$i]);
             return array_values($nodesInContext);
         } else {
             unset($nodesInContext[$i]);
         }
     }
     return NULL;
 }
 public function setUp()
 {
     $this->convertEmailLinks = $this->getAccessibleMock('Networkteam\\Neos\\MailObfuscator\\Typoscript\\ConvertEmailLinksImplementation', array('getValue'), array(), '', FALSE);
     $this->mockContext = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Service\\Context')->disableOriginalConstructor()->getMock();
     $this->mockContext->expects($this->any())->method('getWorkspaceName')->will($this->returnValue('live'));
     $this->mockNode = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Model\\NodeInterface')->getMock();
     $this->mockNode->expects($this->any())->method('getContext')->will($this->returnValue($this->mockContext));
     $this->mockTsRuntime = $this->getMockBuilder('TYPO3\\TypoScript\\Core\\Runtime')->disableOriginalConstructor()->getMock();
     $this->mockTsRuntime->expects($this->any())->method('getCurrentContext')->will($this->returnValue(array('node' => $this->mockNode)));
     $this->convertEmailLinks->_set('tsRuntime', $this->mockTsRuntime);
     $this->convertEmailLinks->_set('linkNameConverter', new \Networkteam\Neos\MailObfuscator\String\Converter\RewriteAtCharConverter());
     $this->convertEmailLinks->_set('mailToHrefConverter', new \Networkteam\Neos\MailObfuscator\String\Converter\Mailto2HrefObfuscatingConverter());
     srand(10);
 }
 /**
  * @param NodeInterface $node
  * @return array
  */
 protected function breadcrumbNodesForNode(NodeInterface $node)
 {
     $documentNodes = [];
     $flowQuery = new FlowQuery(array($node));
     $nodes = array_reverse($flowQuery->parents('[instanceof TYPO3.Neos:Document]')->get());
     /** @var NodeInterface $node */
     foreach ($nodes as $documentNode) {
         $documentNodes[] = $documentNode;
     }
     if ($node->getNodeType()->isOfType('TYPO3.Neos:Document')) {
         $documentNodes[] = $node;
     }
     return $documentNodes;
 }
 /**
  * @param NodeInterface $contextNode The node for which the preceding node should be found
  * @return NodeInterface The preceding nodes of $contextNode or NULL
  */
 protected function getPrevForNode(NodeInterface $contextNode)
 {
     $nodesInContext = $contextNode->getParent()->getChildNodes();
     $count = count($nodesInContext) - 1;
     for ($i = $count; $i > 0; $i--) {
         if ($nodesInContext[$i] === $contextNode) {
             unset($nodesInContext[$i]);
             return array_values($nodesInContext);
         } else {
             unset($nodesInContext[$i]);
         }
     }
     return null;
 }
 /**
  * Publishes the given node to the specified targetWorkspace
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $node
  * @param string $targetWorkspaceName
  * @return void
  * @ExtDirect
  */
 public function publishNodeAction(\TYPO3\TYPO3CR\Domain\Model\NodeInterface $node, $targetWorkspaceName)
 {
     /**
      * TODO: The publishing pushes the same node twice, which causes the node to be published
      * already when it's processed the second time. This obviously leads to a problem for the
      * Workspace object which will (in the second time) try to publish a node in the live workspace
      * to the baseWorkspace of the live workspace (which does not exist).
      */
     if ($targetWorkspaceName === $node->getWorkspace()->getName()) {
         $this->view->assign('value', array('success' => TRUE));
         return;
     }
     $this->workspacesService->publishNode($node, $targetWorkspaceName);
     $this->view->assign('value', array('success' => TRUE));
 }
 /**
  * Generates a URI path segment for a given node taking it's language dimension into account
  *
  * @param NodeInterface $node Optional node to determine language dimension
  * @param string $text Optional text
  * @return string
  */
 public function generateUriPathSegment(NodeInterface $node = null, $text = null)
 {
     if ($node) {
         $text = $text ?: $node->getLabel() ?: $node->getName();
         $dimensions = $node->getContext()->getDimensions();
         if (array_key_exists('language', $dimensions) && $dimensions['language'] !== array()) {
             $locale = new Locale($dimensions['language'][0]);
             $language = $locale->getLanguage();
         }
     } elseif (strlen($text) === 0) {
         throw new Exception('Given text was empty.', 1457591815);
     }
     $text = $this->transliterationService->transliterate($text, isset($language) ? $language : null);
     return Transliterator::urlize($text);
 }
 public function setUp()
 {
     $this->siteNode = $this->createMock(NodeInterface::class);
     $this->firstNodeInLevel = $this->createMock(NodeInterface::class);
     $this->secondNodeInLevel = $this->createMock(NodeInterface::class);
     $this->thirdNodeInLevel = $this->createMock(NodeInterface::class);
     $this->siteNode->expects($this->any())->method('getPath')->will($this->returnValue('/site'));
     $this->siteNode->expects($this->any())->method('getChildNodes')->will($this->returnValue(array($this->firstNodeInLevel, $this->secondNodeInLevel, $this->thirdNodeInLevel)));
     $this->mockContext = $this->getMockBuilder(Context::class)->disableOriginalConstructor()->getMock();
     $this->firstNodeInLevel->expects($this->any())->method('getParent')->will($this->returnValue($this->siteNode));
     $this->firstNodeInLevel->expects($this->any())->method('getPath')->will($this->returnValue('/site/first'));
     $this->secondNodeInLevel->expects($this->any())->method('getParent')->will($this->returnValue($this->siteNode));
     $this->secondNodeInLevel->expects($this->any())->method('getPath')->will($this->returnValue('/site/second'));
     $this->thirdNodeInLevel->expects($this->any())->method('getParent')->will($this->returnValue($this->siteNode));
     $this->thirdNodeInLevel->expects($this->any())->method('getPath')->will($this->returnValue('/site/third'));
 }
 /**
  * Wrap the $content identified by $node with the needed markup for the backend.
  *
  * @param NodeInterface $node
  * @param string $property
  * @param string $content
  * @return string
  */
 public function wrapContentProperty(NodeInterface $node, $property, $content)
 {
     /** @var $contentContext ContentContext */
     $contentContext = $node->getContext();
     if ($contentContext->getWorkspaceName() === 'live' || !$this->privilegeManager->isPrivilegeTargetGranted('TYPO3.Neos:Backend.GeneralAccess')) {
         return $content;
     }
     if (!$this->nodeAuthorizationService->isGrantedToEditNode($node)) {
         return $content;
     }
     $attributes = array();
     $attributes['class'] = 'neos-inline-editable';
     $attributes['property'] = 'typo3:' . $property;
     $attributes['data-neos-node-type'] = $node->getNodeType()->getName();
     return $this->htmlAugmenter->addAttributes($content, $attributes, 'span');
 }
 /**
  * Search all properties for given $term
  *
  * TODO: Implement a better search when Flow offer the possibility
  *
  * @param string $term
  * @param array $searchNodeTypes
  * @param Context $context
  * @param NodeInterface $startingPoint
  * @return array <\TYPO3\TYPO3CR\Domain\Model\NodeInterface>
  */
 public function findByProperties($term, array $searchNodeTypes, Context $context, NodeInterface $startingPoint = null)
 {
     if (strlen($term) === 0) {
         throw new \InvalidArgumentException('"term" cannot be empty: provide a term to search for.', 1421329285);
     }
     $searchResult = array();
     $nodeTypeFilter = implode(',', $searchNodeTypes);
     $nodeDataRecords = $this->nodeDataRepository->findByProperties($term, $nodeTypeFilter, $context->getWorkspace(), $context->getDimensions(), $startingPoint ? $startingPoint->getPath() : null);
     foreach ($nodeDataRecords as $nodeData) {
         $node = $this->nodeFactory->createFromNodeData($nodeData, $context);
         if ($node !== null) {
             $searchResult[$node->getPath()] = $node;
         }
     }
     return $searchResult;
 }
 /**
  * Increase read counter of the node by one
  *
  * @param NodeInterface $node Node to increase the read counter for
  *
  * @throws BadRequestException
  * @return mixed[]
  */
 public function trackAction(NodeInterface $node)
 {
     // we can only count pages that include the mixin
     if ($node->getNodeType()->isOfType('Futjikato.ReadCounter:CounterMixin')) {
         $node->setProperty('readcounter', $node->getProperty('readcounter') + 1);
         /**
          * Action changes data but is accessible via GET. this issues a error if we do not manually
          * persists the object in the persistence manager
          */
         $this->persistenceManager->persistAll();
         // by default the flow JSON view uses the 'value' variable
         $this->view->assign('value', array('readcounter' => $node->getProperty('readcounter')));
     } else {
         throw new BadRequestException('Node does not contain Futjikato.ReadCounter:CounterMixin.');
     }
 }
 /**
  * Generate CSS styles from spacing* properties
  *
  * @param NodeInterface $node
  * @return string
  */
 public function generateCss(NodeInterface $node)
 {
     $css = '';
     foreach (self::PROPERTY_MAPPING as $key => $cssProperty) {
         // Get value, also check for `0` values using strlen()
         if (($value = $node->getProperty($key)) || strlen($value)) {
             // if numeric value is provided, add default unit (e.g. px)
             // but don't add it to zero values
             if ($value && is_numeric($value)) {
                 $value .= self::DEFAULT_UNIT;
             }
             $css .= "{$cssProperty}:{$value};";
         }
     }
     return $css;
 }
Example #28
0
 /**
  * Fetch thumb url from Vimeo API
  *
  * @param NodeInterface $node
  * @return void
  */
 public function fetchVimeoThumb(NodeInterface $node)
 {
     $fullVideo = $node->getProperty('fullVideo');
     $fullVideoThumb = $node->getProperty('fullVideoThumb');
     if ($fullVideo && !$fullVideoThumb) {
         $url = 'https://vimeo.com/api/oembed.json?url=http%3A//vimeo.com/' . $fullVideo;
         $content = file_get_contents($url);
         $json = json_decode($content, true);
         $node->setProperty('fullVideoThumb', $json['thumbnail_url']);
     } else {
         if (!$fullVideo && $fullVideoThumb) {
             // Clear thumb, if Vimeo video is gone. Useful for reloading thumb.
             $node->setProperty('fullVideoThumb', '');
         }
     }
 }
 /**
  * @param array $hits
  * @return array Array of Node objects
  */
 protected function convertHitsToNodes(array $hits)
 {
     $nodes = [];
     $elasticSearchHitPerNode = [];
     /**
      * TODO: This code below is not fully correct yet:
      *
      * We always fetch $limit * (numerOfWorkspaces) records; so that we find a node:
      * - *once* if it is only in live workspace and matches the query
      * - *once* if it is only in user workspace and matches the query
      * - *twice* if it is in both workspaces and matches the query *both times*. In this case we filter the duplicate record.
      * - *once* if it is in the live workspace and has been DELETED in the user workspace (STILL WRONG)
      * - *once* if it is in the live workspace and has been MODIFIED to NOT MATCH THE QUERY ANYMORE in user workspace (STILL WRONG)
      *
      * If we want to fix this cleanly, we'd need to do an *additional query* in order to filter all nodes from a non-user workspace
      * which *do exist in the user workspace but do NOT match the current query*. This has to be done somehow "recursively"; and later
      * we might be able to use https://github.com/elasticsearch/elasticsearch/issues/3300 as soon as it is merged.
      */
     foreach ($hits['hits'] as $hit) {
         $nodePath = current($hit['fields']['__path']);
         $node = $this->contextNode->getNode($nodePath);
         if ($node instanceof NodeInterface && !isset($nodes[$node->getIdentifier()])) {
             $nodes[$node->getIdentifier()] = $node;
             $elasticSearchHitPerNode[$node->getIdentifier()] = $hit;
             if ($this->limit > 0 && count($nodes) >= $this->limit) {
                 break;
             }
         }
     }
     if ($this->logThisQuery === true) {
         $this->logger->log('Returned nodes (' . $this->logMessage . '): ' . count($nodes), LOG_DEBUG);
     }
     $this->elasticSearchHitsIndexedByNodeFromLastRequest = $elasticSearchHitPerNode;
     return array_values($nodes);
 }
 /**
  * Send a new notification that a comment has been created
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $commentNode The comment node
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $postNode The post node
  * @return void
  */
 public function sendNewCommentNotification(NodeInterface $commentNode, NodeInterface $postNode)
 {
     if ($this->settings['notifications']['to']['email'] === '') {
         return;
     }
     if (!class_exists('TYPO3\\SwiftMailer\\Message')) {
         $this->systemLogger->logException(new \TYPO3\Flow\Exception('The package "TYPO3.SwiftMailer" is required to send notifications!', 1359473932));
         return;
     }
     try {
         $mail = new Message();
         $mail->setFrom(array($commentNode->getProperty('emailAddress') => $commentNode->getProperty('author')))->setTo(array($this->settings['notifications']['to']['email'] => $this->settings['notifications']['to']['name']))->setSubject('New comment on blog post "' . $postNode->getProperty('title') . '"' . ($commentNode->getProperty('spam') ? ' (SPAM)' : ''))->setBody($commentNode->getProperty('text'))->send();
     } catch (\Exception $e) {
         $this->systemLogger->logException($e);
     }
 }