If $source is an object and already is of type $targetType, we do return the unmodified object.
public convert ( mixed $source, string $targetType, Neos\Flow\Property\PropertyMappingConfigurationInterface $configuration = null ) : mixed | ||
$source | mixed | the source data to map. MUST be a simple type, NO object allowed! |
$targetType | string | The type of the target; can be either a class name or a simple type. |
$configuration | Neos\Flow\Property\PropertyMappingConfigurationInterface | Configuration for the property mapping. If NULL, the PropertyMappingConfigurationBuilder will create a default configuration. |
return | mixed | an instance of $targetType |
/** * Returns a previously uploaded image. * If errors occurred during property mapping for this property, NULL is returned * * @return Image */ protected function getUploadedImage() { if ($this->getMappingResultsForProperty()->hasErrors()) { return null; } $image = $this->getValue(false); if ($image instanceof Image) { return $image; } return $this->propertyMapper->convert($image, Image::class); }
/** * Returns a previously uploaded resource. * If errors occurred during property mapping for this property, NULL is returned * * @return PersistentResource */ protected function getUploadedResource() { if ($this->getMappingResultsForProperty()->hasErrors()) { return null; } $resourceObject = $this->getValue(false); if ($resourceObject instanceof PersistentResource) { return $resourceObject; } return $this->propertyMapper->convert($resourceObject, PersistentResource::class); }
/** * Actually convert from $source to $targetType, taking into account the fully * built $convertedChildProperties and $configuration. * * The return value can be one of three types: * - an arbitrary object, or a simple type (which has been created while mapping). * This is the normal case. * - NULL, indicating that this object should *not* be mapped (i.e. a "File Upload" Converter could return NULL if no file has been uploaded, and a silent failure should occur. * - An instance of Error -- This will be a user-visible error message later on. * Furthermore, it should throw an Exception if an unexpected failure (like a security error) occurred or a configuration issue happened. * * @param mixed $source * @param string $targetType * @param array $convertedChildProperties * @param PropertyMappingConfigurationInterface $configuration * @return mixed|Error the target type, or an error object if a user-error occurred * @throws TypeConverterException thrown in case a developer error occurred * @api */ public function convertFrom($source, $targetType, array $convertedChildProperties = [], PropertyMappingConfigurationInterface $configuration = null) { $result = []; $convertElements = $configuration->getConfigurationValue(ArrayTypeConverter::class, self::CONFIGURATION_CONVERT_ELEMENTS); foreach ($source as $element) { if ($convertElements === true) { $element = $this->propertyMapper->convert($element, 'array', $configuration); } $result[] = $element; } return $result; }
/** * @test * @expectedException \Neos\Flow\Property\Exception */ public function entityWithImmutablePropertyCanNotBeUpdatedWhenImmutablePropertyChanged() { $result = $this->propertyMapper->convert($this->sourceProperties, Fixtures\TestEntityWithImmutableProperty::class); $identifier = $this->persistenceManager->getIdentifierByObject($result); $this->persistenceManager->add($result); $this->persistenceManager->persistAll(); $this->persistenceManager->clearState(); $update = ['__identity' => $identifier, 'age' => '25', 'name' => 'Christian D']; $result = $this->propertyMapper->convert($update, Fixtures\TestEntityWithImmutableProperty::class); $this->assertInstanceOf(Fixtures\TestEntityWithImmutableProperty::class, $result); $this->assertEquals('Christian M', $result->getName()); }
/** * Converts and adds ImageAdjustments to the ImageVariant * * @param ImageInterface $asset * @param mixed $source * @param array $convertedChildProperties * @param PropertyMappingConfigurationInterface $configuration * @return ImageInterface|NULL */ protected function applyTypeSpecificHandling($asset, $source, array $convertedChildProperties, PropertyMappingConfigurationInterface $configuration) { if ($asset instanceof ImageVariant) { $adjustments = []; if (isset($source['adjustments'])) { foreach ($source['adjustments'] as $adjustmentType => $adjustmentOptions) { if (isset($adjustmentOptions['__type'])) { $adjustmentType = $adjustmentOptions['__type']; unset($adjustmentOptions['__type']); } $identity = null; if (isset($adjustmentOptions['__identity'])) { $identity = $adjustmentOptions['__identity']; unset($adjustmentOptions['__identity']); } $adjustment = $this->propertyMapper->convert($adjustmentOptions, $adjustmentType, $configuration); if ($identity !== null) { ObjectAccess::setProperty($adjustment, 'persistence_object_identifier', $identity, true); } $adjustments[] = $adjustment; } } elseif (isset($source['processingInstructions'])) { $adjustments = $this->processingInstructionsConverter->convertFrom($source['processingInstructions'], 'array'); } if (count($adjustments) > 0) { $asset->addAdjustments($adjustments); } } return $asset; }
/** * @return \DateTime */ protected function getSelectedDate() { $date = $this->getValue(); if ($date instanceof \DateTime) { return $date; } if ($date !== null) { $date = $this->propertyMapper->convert($date, 'DateTime'); if (!$date instanceof \DateTime) { return null; } return $date; } if ($this->hasArgument('initialDate')) { return new \DateTime($this->arguments['initialDate']); } }
/** * @param array $contextArray * @return array */ public function unserializeContext(array $contextArray) { $unserializedContext = []; foreach ($contextArray as $variableName => $typeAndValue) { $value = $this->propertyMapper->convert($typeAndValue['value'], $typeAndValue['type']); $unserializedContext[$variableName] = $value; } return $unserializedContext; }
/** * Generates an array of strings from the given array of context variables * * @param array $contextVariables * @return array * @throws \InvalidArgumentException */ protected function serializeContext(array $contextVariables) { $serializedContextArray = []; foreach ($contextVariables as $variableName => $contextValue) { // TODO This relies on a converter being available from the context value type to string if ($contextValue !== null) { $serializedContextArray[$variableName]['type'] = $this->getTypeForContextValue($contextValue); $serializedContextArray[$variableName]['value'] = $this->propertyMapper->convert($contextValue, 'string'); } } return $serializedContextArray; }
/** * Parses the request body according to the media type. * * @param HttpRequest $httpRequest * @return array */ protected function parseRequestBody(HttpRequest $httpRequest) { $requestBody = $httpRequest->getContent(); if ($requestBody === null || $requestBody === '') { return []; } $mediaTypeConverter = $this->objectManager->get(MediaTypeConverterInterface::class); $propertyMappingConfiguration = new PropertyMappingConfiguration(); $propertyMappingConfiguration->setTypeConverter($mediaTypeConverter); $propertyMappingConfiguration->setTypeConverterOption(MediaTypeConverterInterface::class, MediaTypeConverterInterface::CONFIGURATION_MEDIA_TYPE, $httpRequest->getHeader('Content-Type')); $arguments = $this->propertyMapper->convert($requestBody, 'array', $propertyMappingConfiguration); return $arguments; }
/** * @param mixed $value * @return mixed */ public function process($value) { if ($this->dataType !== null) { $value = $this->propertyMapper->convert($value, $this->dataType, $this->propertyMappingConfiguration); $messages = $this->propertyMapper->getMessages(); } else { $messages = new \Neos\Error\Messages\Result(); } $validationResult = $this->validator->validate($value); $messages->merge($validationResult); $this->processingMessages->merge($messages); return $value; }
/** * Calls a behat step method * * @Flow\Internal * @param string $testHelperObjectName * @param string $methodName * @param boolean $withoutSecurityChecks */ public function callBehatStepCommand($testHelperObjectName, $methodName, $withoutSecurityChecks = false) { $testHelper = $this->objectManager->get($testHelperObjectName); $rawMethodArguments = $this->request->getExceedingArguments(); $mappedArguments = []; for ($i = 0; $i < count($rawMethodArguments); $i += 2) { $mappedArguments[] = $this->propertyMapper->convert($rawMethodArguments[$i + 1], $rawMethodArguments[$i]); } $result = null; try { if ($withoutSecurityChecks === true) { $this->securityContext->withoutAuthorizationChecks(function () use($testHelper, $methodName, $mappedArguments, &$result) { $result = call_user_func_array([$testHelper, $methodName], $mappedArguments); }); } else { $result = call_user_func_array([$testHelper, $methodName], $mappedArguments); } } catch (\Exception $exception) { $this->outputLine('EXCEPTION: %s %d %s in %s:%s %s', [get_class($exception), $exception->getCode(), $exception->getMessage(), $exception->getFile(), $exception->getLine(), $exception->getTraceAsString()]); return; } $this->output('SUCCESS: %s', [$result]); }
/** * @test */ public function persistentEntityCanBeSerializedToIdentifierUsingObjectSource() { $entity = new Fixtures\TestEntity(); $entity->setName('Egon Olsen'); $entity->setAge(42); $entity->setAverageNumberOfKids(3.5); $this->persistenceManager->add($entity); $entityIdentifier = $this->persistenceManager->getIdentifierByObject($entity); $this->persistenceManager->persistAll(); $this->persistenceManager->clearState(); $source = $entity; $result = $this->propertyMapper->convert($source, 'string'); $this->assertSame($entityIdentifier, $result); }
/** * * @param string $workspaceName * @return NodeInterface */ protected function getLastVisitedNode($workspaceName) { if (!$this->session->isStarted() || !$this->session->hasKey('lastVisitedNode')) { return null; } try { $lastVisitedNode = $this->propertyMapper->convert($this->session->getData('lastVisitedNode'), NodeInterface::class); $q = new FlowQuery([$lastVisitedNode]); $lastVisitedNodeUserWorkspace = $q->context(['workspaceName' => $workspaceName])->get(0); return $lastVisitedNodeUserWorkspace; } catch (\Exception $exception) { return null; } }
/** * Checks if the optionally given node context path, affected node context path and typoscript path are set * and overrides the rendering to use those. Will also add a "X-Neos-AffectedNodePath" header in case the * actually affected node is different from the one routing resolved. * This is used in out of band rendering for the backend. * * @return void * @throws NodeNotFoundException */ protected function overrideViewVariablesFromInternalArguments() { if (($nodeContextPath = $this->request->getInternalArgument('__nodeContextPath')) !== null) { $node = $this->propertyMapper->convert($nodeContextPath, NodeInterface::class); if (!$node instanceof NodeInterface) { throw new NodeNotFoundException(sprintf('The node with context path "%s" could not be resolved', $nodeContextPath), 1437051934); } $this->view->assign('value', $node); } if (($affectedNodeContextPath = $this->request->getInternalArgument('__affectedNodeContextPath')) !== null) { $this->response->setHeader('X-Neos-AffectedNodePath', $affectedNodeContextPath); } if (($typoScriptPath = $this->request->getInternalArgument('__typoScriptPath')) !== null) { $this->view->setTypoScriptPath($typoScriptPath); } }
/** * Returns a previously uploaded resource, or the resource specified via "value" argument if no resource has been uploaded before * If errors occurred during property mapping for this property, NULL is returned * * @return PersistentResource or NULL if no resource was uploaded and the "value" argument is not set */ protected function getUploadedResource() { $resource = null; if ($this->hasMappingErrorOccurred()) { $resource = $this->getLastSubmittedFormData(); } elseif ($this->hasArgument('value')) { $resource = $this->arguments['value']; } elseif ($this->isObjectAccessorMode()) { $resource = $this->getPropertyValue(); } if ($resource === null) { return null; } if ($resource instanceof PersistentResource) { return $resource; } return $this->propertyMapper->convert($resource, PersistentResource::class); }
/** * Sets the value of this argument. * * @param mixed $rawValue The value of this argument * @return Argument $this */ public function setValue($rawValue) { if ($rawValue === null) { $this->value = null; return $this; } if (is_object($rawValue) && $rawValue instanceof $this->dataType) { $this->value = $rawValue; return $this; } $this->value = $this->propertyMapper->convert($rawValue, $this->dataType, $this->getPropertyMappingConfiguration()); $this->validationResults = $this->propertyMapper->getMessages(); if ($this->validator !== null) { $validationMessages = $this->validator->validate($this->value); $this->validationResults->merge($validationMessages); } return $this; }
/** * 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 NodeInterface instances * @return mixed value of the property * @api */ public function getProperty($propertyName, $returnNodesAsIdentifiers = false) { $value = $this->nodeData->getProperty($propertyName); if (empty($value)) { return null; } $nodeType = $this->getNodeType(); if (!$nodeType->hasConfiguration('properties.' . $propertyName)) { return $value; } $expectedPropertyType = $nodeType->getPropertyType($propertyName); if ($expectedPropertyType === 'references') { return $returnNodesAsIdentifiers ? $value : $this->resolvePropertyReferences($value); } if ($expectedPropertyType === 'reference') { return $returnNodesAsIdentifiers ? $value : $this->context->getNodeByIdentifier($value); } return $this->propertyMapper->convert($value, $expectedPropertyType); }
/** * @param mixed $propertyValue * @param string $dataType * @return mixed * @throws PropertyException */ protected function convertValue($propertyValue, $dataType) { $rawType = TypeHandling::truncateElementType($dataType); // This hardcoded handling is to circumvent rewriting PropertyMappers that convert objects. Usually they expect the source to be an object already and break if not. if (!TypeHandling::isSimpleType($rawType) && !is_object($propertyValue) && !is_array($propertyValue)) { return null; } if ($rawType === 'array') { $conversionTargetType = 'array<string>'; } elseif (TypeHandling::isSimpleType($rawType)) { $conversionTargetType = TypeHandling::normalizeType($rawType); } else { $conversionTargetType = 'array'; } $propertyMappingConfiguration = $this->createConfiguration($dataType); $convertedValue = $this->propertyMapper->convert($propertyValue, $conversionTargetType, $propertyMappingConfiguration); if ($convertedValue instanceof \Neos\Error\Messages\Error) { throw new PropertyException($convertedValue->getMessage(), $convertedValue->getCode()); } return $convertedValue; }
/** * Publishes or discards the given nodes * * @param array $nodes <\Neos\ContentRepository\Domain\Model\NodeInterface> $nodes * @param string $action * @param Workspace $selectedWorkspace * @throws \Exception * @throws \Neos\Flow\Property\Exception * @throws \Neos\Flow\Security\Exception */ public function publishOrDiscardNodesAction(array $nodes, $action, Workspace $selectedWorkspace = null) { $propertyMappingConfiguration = $this->propertyMappingConfigurationBuilder->build(); $propertyMappingConfiguration->setTypeConverterOption(NodeConverter::class, NodeConverter::REMOVED_CONTENT_SHOWN, true); foreach ($nodes as $key => $node) { $nodes[$key] = $this->propertyMapper->convert($node, NodeInterface::class, $propertyMappingConfiguration); } switch ($action) { case 'publish': foreach ($nodes as $node) { $this->publishingService->publishNode($node); } $this->addFlashMessage($this->translator->translateById('workspaces.selectedChangesHaveBeenPublished', [], null, null, 'Modules', 'Neos.Neos')); break; case 'discard': $this->publishingService->discardNodes($nodes); $this->addFlashMessage($this->translator->translateById('workspaces.selectedChangesHaveBeenDiscarded', [], null, null, 'Modules', 'Neos.Neos')); break; default: throw new \RuntimeException('Invalid action "' . htmlspecialchars($action) . '" given.', 1346167441); } $this->redirect('show', null, null, ['workspace' => $selectedWorkspace]); }
/** * Convert an element to the value it represents. * * @param \XMLReader $reader * @param string $currentType current element (userland) type * @param string $currentEncoding date encoding of element * @param string $currentClassName class name of element * @param string $currentNodeIdentifier identifier of the node * @param string $currentProperty current property name * @return mixed * @throws ImportException */ protected function convertElementToValue(\XMLReader $reader, $currentType, $currentEncoding, $currentClassName, $currentNodeIdentifier, $currentProperty) { switch ($currentType) { case 'object': if ($currentClassName === 'DateTime') { $stringValue = trim($reader->value); $value = $this->propertyMapper->convert($stringValue, $currentClassName, $this->propertyMappingConfiguration); if ($this->propertyMapper->getMessages()->hasErrors()) { throw new ImportException(sprintf('Could not convert element <%s> to DateTime for node %s', $currentProperty, $currentNodeIdentifier), 1472992032); } } elseif ($currentEncoding === 'json') { $decodedJson = json_decode($reader->value, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new ImportException(sprintf('Could not parse encoded JSON in element <%s> for node %s: %s', $currentProperty, $currentNodeIdentifier, json_last_error_msg()), 1472992033); } $value = $this->propertyMapper->convert($decodedJson, $currentClassName, $this->propertyMappingConfiguration); if ($this->propertyMapper->getMessages()->hasErrors()) { throw new ImportException(sprintf('Could not convert element <%s> to %s for node %s', $currentProperty, $currentClassName, $currentNodeIdentifier), 1472992034); } } else { throw new ImportException(sprintf('Unsupported encoding "%s"', $currentEncoding), 1404397061); } break; case 'string': $value = $reader->value; break; default: $value = $this->propertyMapper->convert($reader->value, $currentType, $this->propertyMappingConfiguration); if ($this->propertyMapper->getMessages()->hasErrors()) { throw new ImportException(sprintf('Could not convert element <%s> to %s for node %s', $currentProperty, $currentType, $currentNodeIdentifier), 1472992035); } return $value; } $this->persistEntities($value); return $value; }
/** * @test */ public function viewHelperRendersUriViaGivenNodeObject() { $targetNode = $this->propertyMapper->convert('/sites/example/home', Node::class); $this->assertSame('<a href="/en/home.html">' . $targetNode->getLabel() . '</a>', $this->viewHelper->render($targetNode)); }
/** * Iterates through the given $properties setting them on the specified $node using the appropriate TypeConverters. * * @param object $nodeLike * @param NodeType $nodeType * @param array $properties * @param TYPO3CRContext $context * @param PropertyMappingConfigurationInterface $configuration * @return void * @throws TypeConverterException */ protected function setNodeProperties($nodeLike, NodeType $nodeType, array $properties, TYPO3CRContext $context, PropertyMappingConfigurationInterface $configuration = null) { $nodeTypeProperties = $nodeType->getProperties(); unset($properties['_lastPublicationDateTime']); foreach ($properties as $nodePropertyName => $nodePropertyValue) { if (substr($nodePropertyName, 0, 2) === '__') { continue; } $nodePropertyType = isset($nodeTypeProperties[$nodePropertyName]['type']) ? $nodeTypeProperties[$nodePropertyName]['type'] : null; switch ($nodePropertyType) { case 'reference': $nodePropertyValue = $context->getNodeByIdentifier($nodePropertyValue); break; case 'references': $nodeIdentifiers = json_decode($nodePropertyValue); $nodePropertyValue = array(); if (is_array($nodeIdentifiers)) { foreach ($nodeIdentifiers as $nodeIdentifier) { $referencedNode = $context->getNodeByIdentifier($nodeIdentifier); if ($referencedNode !== null) { $nodePropertyValue[] = $referencedNode; } } } elseif ($nodeIdentifiers !== null) { throw new TypeConverterException(sprintf('node type "%s" expects an array of identifiers for its property "%s"', $nodeType->getName(), $nodePropertyName), 1383587419); } break; case 'DateTime': if ($nodePropertyValue !== '' && ($nodePropertyValue = \DateTime::createFromFormat(\DateTime::W3C, $nodePropertyValue)) !== false) { $nodePropertyValue->setTimezone(new \DateTimeZone(date_default_timezone_get())); } else { $nodePropertyValue = null; } break; case 'integer': $nodePropertyValue = intval($nodePropertyValue); break; case 'boolean': if (is_string($nodePropertyValue)) { $nodePropertyValue = $nodePropertyValue === 'true' ? true : false; } break; case 'array': $nodePropertyValue = json_decode($nodePropertyValue, true); break; } if (substr($nodePropertyName, 0, 1) === '_') { $nodePropertyName = substr($nodePropertyName, 1); ObjectAccess::setProperty($nodeLike, $nodePropertyName, $nodePropertyValue); continue; } if (!isset($nodeTypeProperties[$nodePropertyName])) { if ($configuration !== null && $configuration->shouldSkipUnknownProperties()) { continue; } else { throw new TypeConverterException(sprintf('Node type "%s" does not have a property "%s" according to the schema', $nodeType->getName(), $nodePropertyName), 1359552744); } } $innerType = $nodePropertyType; if ($nodePropertyType !== null) { try { $parsedType = TypeHandling::parseType($nodePropertyType); $innerType = $parsedType['elementType'] ?: $parsedType['type']; } catch (InvalidTypeException $exception) { } } if (is_string($nodePropertyValue) && $this->objectManager->isRegistered($innerType) && $nodePropertyValue !== '') { $nodePropertyValue = $this->propertyMapper->convert(json_decode($nodePropertyValue, true), $nodePropertyType, $configuration); } $nodeLike->setProperty($nodePropertyName, $nodePropertyValue); } }
/** * Remove broken entity references * * This removes references from nodes to entities which don't exist anymore. * * @param string $workspaceName * @param boolean $dryRun * @return void */ public function removeBrokenEntityReferences($workspaceName, $dryRun) { $this->output->outputLine('Checking for broken entity references ...'); /** @var \Neos\ContentRepository\Domain\Model\Workspace $workspace */ $workspace = $this->workspaceRepository->findByIdentifier($workspaceName); $nodeTypesWithEntityReferences = array(); foreach ($this->nodeTypeManager->getNodeTypes() as $nodeType) { /** @var NodeType $nodeType */ foreach (array_keys($nodeType->getProperties()) as $propertyName) { $propertyType = $nodeType->getPropertyType($propertyName); if (strpos($propertyType, '\\') !== false) { if (!isset($nodeTypesWithEntityReferences[$nodeType->getName()])) { $nodeTypesWithEntityReferences[$nodeType->getName()] = array(); } $nodeTypesWithEntityReferences[$nodeType->getName()][$propertyName] = $propertyType; } } } $nodesWithBrokenEntityReferences = array(); $brokenReferencesCount = 0; foreach ($nodeTypesWithEntityReferences as $nodeTypeName => $properties) { $nodeDatas = $this->nodeDataRepository->findByParentAndNodeTypeRecursively('/', $nodeTypeName, $workspace); foreach ($nodeDatas as $nodeData) { /** @var NodeData $nodeData */ foreach ($properties as $propertyName => $propertyType) { $propertyValue = $nodeData->getProperty($propertyName); $convertedProperty = null; if (is_object($propertyValue)) { $convertedProperty = $propertyValue; } if (is_string($propertyValue) && strlen($propertyValue) === 36) { $convertedProperty = $this->propertyMapper->convert($propertyValue, $propertyType); if ($convertedProperty === null) { $nodesWithBrokenEntityReferences[$nodeData->getIdentifier()][$propertyName] = $nodeData; $this->output->outputLine('Broken reference in "%s", property "%s" (%s) referring to %s.', array($nodeData->getPath(), $nodeData->getIdentifier(), $propertyName, $propertyType, $propertyValue)); $brokenReferencesCount++; } } if ($convertedProperty instanceof Proxy) { try { $convertedProperty->__load(); } catch (EntityNotFoundException $e) { $nodesWithBrokenEntityReferences[$nodeData->getIdentifier()][$propertyName] = $nodeData; $this->output->outputLine('Broken reference in "%s", property "%s" (%s) referring to %s.', array($nodeData->getPath(), $nodeData->getIdentifier(), $propertyName, $propertyType, $propertyValue)); $brokenReferencesCount++; } } } } } if ($brokenReferencesCount > 0) { $this->output->outputLine(); if (!$dryRun) { $self = $this; $this->askBeforeExecutingTask('Do you want to remove the broken entity references?', function () use($self, $nodesWithBrokenEntityReferences, $brokenReferencesCount, $workspaceName, $dryRun) { foreach ($nodesWithBrokenEntityReferences as $nodeIdentifier => $properties) { foreach ($properties as $propertyName => $nodeData) { /** @var NodeData $nodeData */ $nodeData->setProperty($propertyName, null); } } $self->output->outputLine('Removed %s broken entity reference%s.', array($brokenReferencesCount, $brokenReferencesCount > 1 ? 's' : '')); }); } else { $this->output->outputLine('Found %s broken entity reference%s to be removed.', array($brokenReferencesCount, $brokenReferencesCount > 1 ? 's' : '')); } $this->output->outputLine(); $this->persistenceManager->persistAll(); } }
/** * @test */ public function viewHelperRendersUriViaGivenNodeObject() { $targetNode = $this->propertyMapper->convert('/sites/example/home', Node::class); $this->assertOutputLinkValid('home.html', $this->viewHelper->render($targetNode)); }
/** * 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, NodeInterface::class); } 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', 'Neos.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; }