-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathPropertiesProcessor.php
More file actions
107 lines (99 loc) · 5.23 KB
/
PropertiesProcessor.php
File metadata and controls
107 lines (99 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<?php
namespace Flowpack\NodeTemplates\Domain\NodeCreation;
use Flowpack\NodeTemplates\Domain\ErrorHandling\ProcessingError;
use Flowpack\NodeTemplates\Domain\ErrorHandling\ProcessingErrors;
use Neos\Error\Messages\Error;
use Neos\Flow\Property\Exception as PropertyMappingException;
use Neos\Flow\Property\PropertyMapper;
use Neos\Flow\Property\PropertyMappingConfiguration;
class PropertiesProcessor
{
private PropertyMapper $propertyMapper;
public function __construct(PropertyMapper $propertyMapper)
{
$this->propertyMapper = $propertyMapper;
}
/**
* We run a few checks and convert the properties.
* If any of the checks fails we append an exception to the $processingErrors.
*
* 1. Check if the NodeType schema has the property declared.
*
* 2. It is checked, that the property value is assignable to the property type.
* In case the type is class or an array of classes, the property mapper will be used map the given type to it. If it doesn't succeed, we will log an error.
*/
public function processAndValidateProperties(TransientNode $node, ProcessingErrors $processingErrors): array
{
$nodeType = $node->getNodeType();
$validProperties = [];
foreach ($node->getProperties() as $propertyName => $propertyValue) {
try {
$this->assertValidPropertyName($propertyName);
if (!isset($nodeType->getProperties()[$propertyName])) {
throw new PropertyIgnoredException(
sprintf(
'Because property is not declared in NodeType. Got value `%s`.',
json_encode($propertyValue)
),
1685869035209
);
}
$propertyType = PropertyType::fromPropertyOfNodeType($propertyName, $nodeType);
if (!$propertyType->isMatchedBy($propertyValue)
&& ($propertyType->isClass() || $propertyType->isArrayOfClass())) {
// we try property mapping only for class types or array of classes
$propertyMappingConfiguration = new PropertyMappingConfiguration();
$propertyMappingConfiguration->allowAllProperties();
$propertyValue = $this->propertyMapper->convert($propertyValue, $propertyType->getValue(), $propertyMappingConfiguration);
$messages = $this->propertyMapper->getMessages();
if ($messages->hasErrors()) {
// $messages->getFirstError() doesnt work see https://github.com/neos/flow-development-collection/issues/3370
$flattenedErrors = $messages->getFlattenedErrors();
/** @var Error $firstError */
$firstError = current(current($flattenedErrors));
throw new PropertyIgnoredException($firstError->getMessage(), 1686779371122);
}
}
if (!$propertyType->isMatchedBy($propertyValue)) {
throw new PropertyIgnoredException(
sprintf(
'Because value `%s` is not assignable to property type "%s".',
json_encode($propertyValue),
$propertyType->getValue()
),
1685958105644
);
}
$validProperties[$propertyName] = $propertyValue;
} catch (PropertyIgnoredException|PropertyMappingException $exception) {
$processingErrors->add(
ProcessingError::fromException($exception)->withOrigin(sprintf('Property "%s" in NodeType "%s"', $propertyName, $nodeType->getName()))
);
}
}
return $validProperties;
}
/**
* In the old CR, it was common practice to set internal or meta properties via this syntax: `_hidden` but we don't allow this anymore.
* @throws PropertyIgnoredException
*/
private function assertValidPropertyName($propertyName): void
{
$legacyInternalProperties = ['_accessRoles', '_contentObject', '_hidden', '_hiddenAfterDateTime', '_hiddenBeforeDateTime', '_hiddenInIndex',
'_index', '_name', '_nodeType', '_removed', '_workspace'];
if (!is_string($propertyName) || $propertyName === '') {
throw new PropertyIgnoredException(sprintf('Because property name must be a non empty string. Got "%s".', $propertyName), 1686149518395);
}
if ($propertyName[0] === '_') {
$lowerPropertyName = strtolower($propertyName);
if ($lowerPropertyName === '_hidden') {
throw new PropertyIgnoredException('Using "_hidden" as property declaration was removed. Please use "tags.disabled" instead.', 1719079679);
}
foreach ($legacyInternalProperties as $legacyInternalProperty) {
if ($lowerPropertyName === strtolower($legacyInternalProperty)) {
throw new PropertyIgnoredException(sprintf('Because internal legacy property "%s" not implement.', $propertyName), 1686149513158);
}
}
}
}
}