/** * Generate a TypoScript prototype definition for a given node type * * A node will be rendered by Neos.Neos:Content by default with a template in * resource://PACKAGE_KEY/Private/Templates/NodeTypes/NAME.html and forwards all public * node properties to the template TypoScript object. * * @param NodeType $nodeType * @return string */ public function generate(NodeType $nodeType) { if (strpos($nodeType->getName(), ':') === false) { return ''; } $output = 'prototype(' . $nodeType->getName() . ') < prototype(Neos.Neos:Plugin) {' . chr(10); list($packageKey, $relativeName) = explode(':', $nodeType->getName(), 2); $output .= "\t" . 'package = "' . $packageKey . '"' . chr(10); $output .= "\t" . 'subpackage = ""' . chr(10); $output .= "\t" . 'controller = "Standard"' . chr(10); $output .= "\t" . 'action = "index"' . chr(10); $output .= '}' . chr(10); return $output; }
/** * Generate a TypoScript prototype definition for a given node type * * A node will be rendered by Neos.Neos:Content by default with a template in * resource://PACKAGE_KEY/Private/Templates/NodeTypes/NAME.html and forwards all public * node properties to the template TypoScript object. * * @param NodeType $nodeType * @return string */ public function generate(NodeType $nodeType) { if (strpos($nodeType->getName(), ':') === false) { return ''; } $output = 'prototype(' . $nodeType->getName() . ') < prototype(' . $this->basePrototypeName . ') {' . chr(10); list($packageKey, $relativeName) = explode(':', $nodeType->getName(), 2); $templatePath = 'resource://' . $packageKey . '/Private/Templates/NodeTypes/' . $relativeName . '.html'; $output .= "\t" . 'templatePath = \'' . $templatePath . '\'' . chr(10); foreach ($nodeType->getProperties() as $propertyName => $propertyConfiguration) { if (isset($propertyName[0]) && $propertyName[0] !== '_') { $output .= "\t" . $propertyName . ' = ${q(node).property("' . $propertyName . '")}' . chr(10); if (isset($propertyConfiguration['type']) && isset($propertyConfiguration['ui']['inlineEditable']) && $propertyConfiguration['type'] === 'string' && $propertyConfiguration['ui']['inlineEditable'] === true) { $output .= "\t" . $propertyName . '.@process.convertUris = Neos.Neos:ConvertUris' . chr(10); } } } $output .= '}' . chr(10); return $output; }
/** * This method traverses the given node type to find the first super type that matches the constraint node type. * In case the hierarchy has more than one way of finding a path to the node type it's not taken into account, * since the first matched is returned. This is accepted on purpose for performance reasons and due to the fact * that such hierarchies should be avoided. * * @param NodeType $currentNodeType * @param string $constraintNodeTypeName * @param integer $distance * @return integer or NULL if no NodeType matched */ protected function traverseSuperTypes(NodeType $currentNodeType, $constraintNodeTypeName, $distance) { if ($currentNodeType->getName() === $constraintNodeTypeName) { return $distance; } $distance++; foreach ($currentNodeType->getDeclaredSuperTypes() as $superType) { $result = $this->traverseSuperTypes($superType, $constraintNodeTypeName, $distance); if ($result !== null) { return $result; } } return null; }
/** * @test */ public function aNodeTypeHasAName() { $nodeType = new NodeType('Neos.ContentRepository.Testing:Text', array(), array()); $this->assertSame('Neos.ContentRepository.Testing:Text', $nodeType->getName()); }
/** * Generate an `@cache` entry tag for a node type * A cache entry with this tag will be flushed whenever a node * (for any variant) that is of the given node type (including inheritance) * is updated. * * @param NodeType $nodeType * @return string */ public function nodeTypeTag(NodeType $nodeType) { return 'NodeType_' . $nodeType->getName(); }
/** * 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; }
/** * 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); } }
/** * Sets the node type of this node. * * @param \Neos\ContentRepository\Domain\Model\NodeType $nodeType * @return void */ public function setNodeType(NodeType $nodeType) { if ($this->nodeType !== $nodeType->getName()) { $this->nodeType = $nodeType->getName(); $this->addOrUpdate(); } }