/** * @test */ public function findOneByIdentifierFindsRemovedNodeInRepositoryAndRespectsWorkspaceAndDimensions() { $liveWorkspace = new Workspace('live'); $nodeData = $this->getMockBuilder('TYPO3\\TYPO3CR\\Domain\\Model\\NodeData')->disableOriginalConstructor()->getMock(); $nodeData->expects($this->any())->method('getIdentifier')->will($this->returnValue('abcd-efgh-ijkl-mnop')); $this->nodeDataRepository->remove($nodeData); $dimensions = array('persona' => array('everybody'), 'language' => array('de_DE', 'mul_ZZ')); $nodeData->expects($this->atLeastOnce())->method('matchesWorkspaceAndDimensions')->with($liveWorkspace, $dimensions)->will($this->returnValue(TRUE)); $result = $this->nodeDataRepository->findOneByIdentifier('abcd-efgh-ijkl-mnop', $liveWorkspace, $dimensions); $this->assertNull($result); }
/** * @test */ public function sortByDateTimeDescending() { $nodesToSort = [$this->nodeDataRepository->findOneByIdentifier('c381f64d-4269-429a-9c21-6d846115addd', $this->context->getWorkspace(true), array()), $this->nodeDataRepository->findOneByIdentifier('c381f64d-4269-429a-9c21-6d846115adde', $this->context->getWorkspace(true), array()), $this->nodeDataRepository->findOneByIdentifier('c381f64d-4269-429a-9c21-6d846115addf', $this->context->getWorkspace(true), array())]; $correctOrder = [$this->nodeDataRepository->findOneByIdentifier('c381f64d-4269-429a-9c21-6d846115addd', $this->context->getWorkspace(true), array()), $this->nodeDataRepository->findOneByIdentifier('c381f64d-4269-429a-9c21-6d846115addf', $this->context->getWorkspace(true), array()), $this->nodeDataRepository->findOneByIdentifier('c381f64d-4269-429a-9c21-6d846115adde', $this->context->getWorkspace(true), array())]; $flowQuery = new \TYPO3\Eel\FlowQuery\FlowQuery($nodesToSort); $operation = new SortOperation(); $operation->evaluate($flowQuery, ['_lastPublicationDateTime', 'DESC']); $this->assertEquals($correctOrder, $flowQuery->getContext()); }
/** * @Flow\Around("method(TYPO3\Flow\Mvc\Routing\Router->resolve())") * @param \TYPO3\Flow\Aop\JoinPointInterface $joinPoint The current join point * @return mixed */ public function addTargetNodeToArguments(\TYPO3\Flow\Aop\JoinPointInterface $joinPoint) { if (!isset($this->settings['targetNodeMappings']) || !is_array($this->settings['targetNodeMappings'])) { return $joinPoint->getAdviceChain()->proceed($joinPoint); } $arguments = $joinPoint->getMethodArgument('routeValues'); foreach ($this->settings['targetNodeMappings'] as $pluginNamespace => $pluginTargetNodeMappings) { $pluginNamespace = '--' . $pluginNamespace; if (!isset($arguments[$pluginNamespace]) || !is_array($arguments[$pluginNamespace])) { continue; } $pluginArguments = $arguments[$pluginNamespace]; foreach ($pluginTargetNodeMappings as $pluginTargetNodeMapping) { if (isset($pluginTargetNodeMapping['package']) && (!isset($pluginArguments['@package']) || strtolower($pluginArguments['@package']) !== strtolower($pluginTargetNodeMapping['package']))) { continue; } if (isset($pluginTargetNodeMapping['controller']) && (!isset($pluginArguments['@controller']) || strtolower($pluginArguments['@controller']) !== strtolower($pluginTargetNodeMapping['controller']))) { continue; } if (isset($pluginTargetNodeMapping['action']) && (!isset($pluginArguments['@action']) || strtolower($pluginArguments['@action']) !== strtolower($pluginTargetNodeMapping['action']))) { continue; } if (isset($pluginTargetNodeMapping['targetNamespace'])) { unset($arguments[$pluginNamespace]); $arguments['--' . $pluginTargetNodeMapping['targetNamespace']] = $pluginArguments; } $nodeIdentifier = $pluginTargetNodeMapping['targetNode']; $node = $this->nodeDataRepository->findOneByIdentifier($nodeIdentifier, $this->createContext()->getWorkspace()); if ($node === NULL) { throw new \TYPO3\Flow\Exception('no node with identifier "' . $nodeIdentifier . '" found', 1334172725); } $arguments['node'] = $node->getContextPath(); $arguments['@package'] = 'TYPO3.Neos'; $arguments['@controller'] = 'Frontend\\Node'; $arguments['@format'] = 'html'; $arguments['@action'] = 'show'; $joinPoint->setMethodArgument('routeValues', $arguments); return $joinPoint->getAdviceChain()->proceed($joinPoint); } } return $joinPoint->getAdviceChain()->proceed($joinPoint); }
/** * Change the property on the given node. * * @param NodeData $node * @return NodeData */ public function execute(NodeData $node) { $reference = (string) $node->getProperty('plugin'); $workspace = $node->getWorkspace(); do { if ($this->reverse === false && preg_match(NodeInterface::MATCH_PATTERN_PATH, $reference)) { $pluginNode = $this->nodeDataRepository->findOneByPath($reference, $node->getWorkspace()); } else { $pluginNode = $this->nodeDataRepository->findOneByIdentifier($reference, $node->getWorkspace()); } if (isset($pluginNode)) { break; } $workspace = $workspace->getBaseWorkspace(); } while ($workspace && $workspace->getName() !== 'live'); if (isset($pluginNode)) { $node->setProperty('plugin', $this->reverse === false ? $pluginNode->getIdentifier() : $pluginNode->getPath()); } return $node; }
/** * Get a node by identifier and this context * * @param string $identifier The identifier of a node * @return NodeInterface The node with the given identifier or NULL if no such node exists */ public function getNodeByIdentifier($identifier) { $node = $this->firstLevelNodeCache->getByIdentifier($identifier); if ($node !== false) { return $node; } $nodeData = $this->nodeDataRepository->findOneByIdentifier($identifier, $this->getWorkspace(), $this->dimensions); if ($nodeData !== null) { $node = $this->nodeFactory->createFromNodeData($nodeData, $this); } else { $node = null; } $this->firstLevelNodeCache->setByIdentifier($identifier, $node); return $node; }
/** * 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; }
/** * 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; }
/** * Returns the specified property. * * If the node has a content object attached, the property will be fetched * there if it is gettable. * * @param string $propertyName Name of the property * @param boolean $returnNodesAsIdentifiers If enabled, references to nodes are returned as node identifiers instead of NodeData objects * @param \TYPO3\TYPO3CR\Domain\Service\Context $context An optional Context if $returnNodesAsIdentifiers === TRUE * @return mixed value of the property * @throws \TYPO3\TYPO3CR\Exception\NodeException if the content object exists but does not contain the specified property. */ public function getProperty($propertyName, $returnNodesAsIdentifiers = FALSE, \TYPO3\TYPO3CR\Domain\Service\Context $context = NULL) { if (!is_object($this->contentObjectProxy)) { $value = isset($this->properties[$propertyName]) ? $this->properties[$propertyName] : NULL; if (!empty($value)) { // TODO: The next two lines are workarounds, actually a NodeData cannot correctly return references but should always return identifier. Node should then apply the context and return the real Node objects. $dimensions = $context !== NULL ? $context->getDimensions() : array(); $workspace = $context !== NULL ? $context->getWorkspace() : $this->getWorkspace(); switch ($this->getNodeType()->getPropertyType($propertyName)) { case 'references': $nodeDatas = array(); if (!is_array($value)) { $value = array(); } $valueNeedsToBeFixed = FALSE; foreach ($value as $nodeIdentifier) { // in cases where a reference is a NodeData instance, fix this if ($nodeIdentifier instanceof NodeData) { $nodeIdentifier = $nodeIdentifier->getIdentifier(); $valueNeedsToBeFixed = TRUE; } if ($returnNodesAsIdentifiers === FALSE) { $nodeData = $this->nodeDataRepository->findOneByIdentifier($nodeIdentifier, $workspace, $dimensions); if ($nodeData instanceof NodeData) { $nodeDatas[] = $nodeData; } } else { $nodeDatas[] = $nodeIdentifier; } } if ($valueNeedsToBeFixed === TRUE) { $fixedValue = array(); foreach ($value as $nodeIdentifier) { if ($nodeIdentifier instanceof NodeData) { $fixedValue[] = $nodeIdentifier->getIdentifier(); } else { $fixedValue[] = $nodeIdentifier; } } $this->properties[$propertyName] = $fixedValue; $this->update(); } $value = $nodeDatas; break; case 'reference': // in cases where a reference is a NodeData instance, fix this if ($value instanceof NodeData) { $value = $value->getIdentifier(); $this->properties[$propertyName] = $value; $this->update(); } if ($returnNodesAsIdentifiers === FALSE) { $nodeData = $this->nodeDataRepository->findOneByIdentifier($value, $workspace, $dimensions); if ($nodeData instanceof NodeData) { $value = $nodeData; } else { $value = NULL; } } break; } } return $value; } elseif (ObjectAccess::isPropertyGettable($this->contentObjectProxy->getObject(), $propertyName)) { return ObjectAccess::getProperty($this->contentObjectProxy->getObject(), $propertyName); } throw new \TYPO3\TYPO3CR\Exception\NodeException(sprintf('Property "%s" does not exist in content object of type %s.', $propertyName, get_class($this->contentObjectProxy->getObject())), 1291286995); }
/** * Get array of node selection properties * * * * @param Node $node * @return array */ public function prepareNodeSelectionFromNode(Node $node) { foreach ($this->contentContextFactory->getInstances() as $context) { $this->workspace = $context->getWorkspace(); break; } $limit = false; $limit_param_name = false; $offset = false; $offset_param_name = false; $filter = array(); $sort = array(); $nodetype = false; $nodetypeisabstract = false; $entryNodes = array(); $nodeParentPath = $node->getParentPath(); if ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes')) { // calculate nodetype name if ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes') && array_key_exists('nodeType', $node->getNodeData()->getNodeType()->getConfiguration('indexedNodes'))) { foreach ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes')['nodeType'] as $key => $value) { switch ($key) { case 'property': if ($node->getProperty($value)) { $nodetype = $node->getProperty($value); } break; case 'value': $nodetype = $value; break; case 'param': if ($this->httpRequest->hasArgument($value) || $nodetype == false) { $nodetype = addslashes($this->httpRequest->getArgument($value)); } break; case 'abstract': $nodetypeisabstract = TRUE; break; default: break; } } } else { throw new IndexedNodesException($node->getNodeData()->getNodeType()->getName() . ' has no nodeType definition.'); } // calculate limit if ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes') && array_key_exists('limit', $node->getNodeData()->getNodeType()->getConfiguration('indexedNodes'))) { foreach ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes')['limit'] as $key => $value) { switch ($key) { case 'property': if ($node->getProperty($value)) { $limit = $node->getProperty($value); } break; case 'value': $limit = $value; break; case 'param': if ($this->httpRequest->hasArgument($value) || $limit == false) { $limit = addslashes($this->httpRequest->getArgument($value)); } $limit_param_name = $value; if (strlen($limit) == 0) { $limit = false; } break; default: break; } } } if (!$limit) { // fetch default limit from internal params $value = "_limit-" . $node->getIdentifier(); if ($this->httpRequest->hasArgument($value)) { $limit = addslashes($this->httpRequest->getArgument($value)); } if (!$limit_param_name) { $limit_param_name = $value; } } // calculate limit offset, if limit isset if ($limit && $node->getNodeData()->getNodeType()->getConfiguration('indexedNodes') && array_key_exists('offset', $node->getNodeData()->getNodeType()->getConfiguration('indexedNodes'))) { foreach ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes')['offset'] as $key => $value) { switch ($key) { case 'property': if ($node->getProperty($value)) { $offset = $node->getProperty($value); } break; case 'value': $offset = $value; break; case 'param': if ($this->httpRequest->hasArgument($value) || $offset == false) { $offset = addslashes($this->httpRequest->getArgument($value)); } $offset_param_name = $value; if (strlen($offset) == 0) { $offset = false; } break; default: break; } } } if (!$offset) { // fetch default offset from internal params $value = "_offset-" . $node->getIdentifier(); if ($this->httpRequest->hasArgument($value)) { $offset = addslashes($this->httpRequest->getArgument($value)); } if (!$offset_param_name) { $offset_param_name = $value; } if (strlen($offset) == 0) { $offset = 0; } } // calculate filters if ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes') && $node->getNodeData()->getNodeType()->getConfiguration('indexedNodes')['filter']) { foreach ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes')['filter'] as $property => $arguments) { foreach ($arguments as $arg => $filterValues) { switch ($arg) { case 'type': $filter[$property]['type'] = $filterValues; break; case 'operand': foreach ($filterValues as $key => $value) { switch ($key) { case 'property': if ($node->getProperty($value)) { $filter[$property]['operand'] = $node->getProperty($value); } break; case 'value': $filter[$property]['operand'] = $value; break; case 'param': if ($this->httpRequest->hasArgument($value) || isset($filter[$property]['operand']) == false) { $filter[$property]['operand'] = addslashes($this->httpRequest->getArgument($value)); } break; default: break; } } break; case 'operator': foreach ($filterValues as $key => $value) { switch ($key) { case 'property': if ($node->getProperty($value)) { $filter[$property]['operator'] = $node->getProperty($value); } break; case 'value': $filter[$property]['operator'] = $value; break; case 'param': if ($this->httpRequest->hasArgument($value) || isset($filter[$property]['operator']) == false) { $filter[$property]['operator'] = addslashes($this->httpRequest->getArgument($value)); } break; default: break; } } break; } } if (isset($filter[$property]['type']) == false) { $targetNodeType = $this->nodeTypeManager->getNodeType($nodetype); // get sorting type by property definition if (isset($targetNodeType->getConfiguration('properties')['text'])) { $filter[$property]['type'] = $targetNodeType->getConfiguration('properties')['text']['type']; } else { $filter[$property]['type'] = 'string'; } } } } // calculate entry nodes if ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes') && array_key_exists('entryNodes', $node->getNodeData()->getNodeType()->getConfiguration('indexedNodes'))) { foreach ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes')['entryNodes'] as $property => $filterValues) { foreach ($filterValues as $key => $value) { switch ($key) { case 'property': if ($node->getProperty($value)) { $entryNodes[$property]['value'] = $node->getProperty($value); } break; case 'value': $entryNodes[$property]['value'] = $value; break; case 'param': if ($this->httpRequest->hasArgument($value) || isset($entryNodes[$property]['value']) == false) { $entryNodes[$property]['value'] = addslashes($this->httpRequest->getArgument($value)); } break; case 'recursive': $entryNodes[$property]['recursive'] = $value; break; case 'childNodePath': $entryNodes[$property]['childNodePath'] = $value; break; } if (isset($entryNodes[$property]['recursive']) == false) { $entryNodes[$property]['recursive'] = TRUE; } if (isset($entryNodes[$property]['childNodePath']) == false) { $entryNodes[$property]['childNodePath'] = FALSE; } if (isset($entryNodes[$property]['value']) && is_array($entryNodes[$property]['value']) == false) { $targetNode = $this->nodeDataRepository->findOneByIdentifier($entryNodes[$property]['value'], $this->workspace); if ($targetNode) { $entryNodes[$property]['path'] = $targetNode->getParentPath(); } } } if (isset($entryNodes[$property]['value']) && is_array($entryNodes[$property]['value'])) { $t = $entryNodes[$property]; unset($entryNodes[$property]); foreach ($t['value'] as $key => $val) { $entryNodes[$property . $key] = array('path' => $val->getPath(), 'childNodePath' => $t['childNodePath'], 'parentPath' => $val->getParentPath(), 'childNodes' => $val->getNodeType()->getChildNodes(), 'recursive' => $t['recursive']); } } } } else { // set reference to self node $entryNodes['self'] = array('path' => '/'); } // calculate sorting if ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes') && array_key_exists('sort', $node->getNodeData()->getNodeType()->getConfiguration('indexedNodes'))) { foreach ($node->getNodeData()->getNodeType()->getConfiguration('indexedNodes')['sort'] as $nullkey => $sortValues) { foreach ($sortValues as $key => $value) { switch ($key) { case 'property': if ($node->getProperty($value)) { $sort[$property]['value'] = $node->getProperty($value); } break; case 'value': $sort[$property]['value'] = $value; break; case 'param': if ($this->httpRequest->hasArgument($value) || isset($sort[$property]) == false) { $sort[$property]['value'] = addslashes($this->httpRequest->getArgument($value)); } break; case 'type': $sort[$property]['type'] = $value; break; case 'direction': foreach ($value as $k => $v) { switch ($k) { case 'property': if ($node->getProperty($v)) { $sort[$property]['direction'] = $node->getProperty($v); } break; case 'value': $sort[$property]['direction'] = $v; break; case 'param': if ($this->httpRequest->hasArgument($v) || isset($sort[$property]['direction']) == false) { $sort[$property]['direction'] = addslashes($this->httpRequest->getArgument($v)); } break; } } break; default: break; } if (isset($sort[$property]['type']) == false) { $targetNodeType = $this->nodeTypeManager->getNodeType($nodetype); // get sorting type by property definition if (isset($targetNodeType->getConfiguration('properties')['text'])) { $sort[$property]['type'] = $targetNodeType->getConfiguration('properties')['text']['type']; } else { $sort[$property]['type'] = 'string'; } } } } } } return array('limit' => $limit, 'limit_param_name' => $limit_param_name, 'offset' => $offset, 'offset_param_name' => $offset_param_name, 'filter' => $filter, 'sort' => $sort, 'nodetype' => $nodetype, 'nodetypeisabstract' => $nodetypeisabstract, 'entryNodes' => $entryNodes, 'workspace' => $this->workspace); }