Skip to content

Commit 970643b

Browse files
authored
Merge pull request #62 from Flowpack/bugfix/61-triggerPropertyMapping
BUGFIX: Use property mapping for `type: SomeClass` or `array<SomeClass>`
2 parents 2c69d58 + 847e738 commit 970643b

14 files changed

Lines changed: 276 additions & 10 deletions

Classes/Domain/NodeCreation/NodeCreationService.php

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@
88
use Flowpack\NodeTemplates\Domain\Template\Template;
99
use Flowpack\NodeTemplates\Domain\Template\Templates;
1010
use Neos\ContentRepository\Domain\Model\NodeInterface;
11+
use Neos\ContentRepository\Domain\Model\NodeType;
1112
use Neos\ContentRepository\Domain\Service\NodeTypeManager;
1213
use Neos\ContentRepository\Exception\NodeConstraintException;
1314
use Neos\Flow\Annotations as Flow;
15+
use Neos\Flow\Property\PropertyMapper;
16+
use Neos\Flow\Property\PropertyMappingConfiguration;
1417
use Neos\Neos\Service\NodeOperations;
1518
use Neos\Neos\Utility\NodeUriPathSegmentGenerator;
19+
use Neos\Flow\Property\Exception as PropertyWasNotMappedException;
1620

1721
class NodeCreationService
1822
{
@@ -34,14 +38,20 @@ class NodeCreationService
3438
*/
3539
protected $nodeUriPathSegmentGenerator;
3640

41+
/**
42+
* @Flow\Inject
43+
* @var PropertyMapper
44+
*/
45+
protected $propertyMapper;
46+
3747
/**
3848
* Applies the root template and its descending configured child node templates on the given node.
3949
* @throws \InvalidArgumentException
4050
*/
4151
public function apply(RootTemplate $template, NodeInterface $node, CaughtExceptions $caughtExceptions): void
4252
{
4353
$nodeType = $node->getNodeType();
44-
$propertiesAndReferences = PropertiesAndReferences::createFromArrayAndTypeDeclarations($template->getProperties(), $nodeType);
54+
$propertiesAndReferences = PropertiesAndReferences::createFromArrayAndTypeDeclarations($this->convertProperties($nodeType, $template->getProperties(), $caughtExceptions), $nodeType);
4555

4656
// set properties
4757
foreach ($propertiesAndReferences->requireValidProperties($nodeType, $caughtExceptions) as $key => $value) {
@@ -119,7 +129,7 @@ private function applyTemplateRecursively(Templates $templates, NodeInterface $p
119129
}
120130
}
121131
$nodeType = $node->getNodeType();
122-
$propertiesAndReferences = PropertiesAndReferences::createFromArrayAndTypeDeclarations($template->getProperties(), $nodeType);
132+
$propertiesAndReferences = PropertiesAndReferences::createFromArrayAndTypeDeclarations($this->convertProperties($nodeType, $template->getProperties(), $caughtExceptions), $nodeType);
123133

124134
// set properties
125135
foreach ($propertiesAndReferences->requireValidProperties($nodeType, $caughtExceptions) as $key => $value) {
@@ -153,4 +163,40 @@ private function ensureNodeHasUriPathSegment(NodeInterface $node, $template)
153163
}
154164
$node->setProperty('uriPathSegment', $this->nodeUriPathSegmentGenerator->generateUriPathSegment($node, $properties['title'] ?? null));
155165
}
166+
167+
private function convertProperties(NodeType $nodeType, array $properties, CaughtExceptions $caughtExceptions): array
168+
{
169+
// TODO combine with PropertiesAndReferences::requireValidProperties
170+
foreach ($nodeType->getConfiguration('properties') as $propertyName => $propertyConfiguration) {
171+
if (!isset($properties[$propertyName])) {
172+
continue;
173+
}
174+
$propertyType = $nodeType->getPropertyType($propertyName);
175+
if ($propertyType === 'references' || $propertyType === 'reference') {
176+
continue;
177+
}
178+
$propertyType = PropertyType::fromPropertyOfNodeType($propertyName, $nodeType);
179+
$propertyValue = $properties[$propertyName];
180+
if (!$propertyType->isClass() && !$propertyType->isArrayOfClass()) {
181+
// property mapping only for class types or array of classes!
182+
continue;
183+
}
184+
try {
185+
$propertyMappingConfiguration = new PropertyMappingConfiguration();
186+
$propertyMappingConfiguration->allowAllProperties();
187+
188+
$properties[$propertyName] = $this->propertyMapper->convert($propertyValue, $propertyType->getValue(), $propertyMappingConfiguration);
189+
$messages = $this->propertyMapper->getMessages();
190+
if ($messages->hasErrors()) {
191+
throw new PropertyWasNotMappedException($this->propertyMapper->getMessages()->getFirstError()->getMessage(), 1686779371122);
192+
}
193+
} catch (PropertyWasNotMappedException $exception) {
194+
$caughtExceptions->add(CaughtException::fromException(
195+
$exception
196+
)->withOrigin(sprintf('Property "%s" in NodeType "%s"', $propertyName, $nodeType->getName())));
197+
unset($properties[$propertyName]);
198+
}
199+
}
200+
return $properties;
201+
}
156202
}

Classes/Domain/NodeCreation/PropertyType.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,19 @@ public function isArrayOf(): bool
178178
return (bool)preg_match(self::PATTERN_ARRAY_OF, $this->value);
179179
}
180180

181+
public function isArrayOfClass(): bool
182+
{
183+
return $this->isArrayOf() && $this->arrayOfType->isClass();
184+
}
185+
186+
public function isClass(): bool
187+
{
188+
$className = $this->value[0] != '\\'
189+
? '\\' . $this->value
190+
: $this->value;
191+
return (class_exists($className) || interface_exists($className));
192+
}
193+
181194
public function isDate(): bool
182195
{
183196
return $this->value === self::TYPE_DATE;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Test, that asset ids are correctly resolved to asset objects (via the property mapper)
2+
# Also reference node id's should be correctly resolved
3+
---
4+
5+
'Flowpack.NodeTemplates:Content.ResolvablePropertyValues':
6+
superTypes:
7+
'Neos.Neos:Content': true
8+
properties:
9+
asset:
10+
type: Neos\Media\Domain\Model\Asset
11+
images:
12+
type: array<Neos\Media\Domain\Model\ImageInterface>
13+
reference:
14+
type: reference
15+
references:
16+
type: references
17+
options:
18+
template:
19+
properties:
20+
asset: 'c228200e-7472-4290-9936-4454a5b5692a'
21+
reference: 'some-node-id'
22+
references: "${['some-node-id', 'other-node-id', data.realNode]}"
23+
images: "${['c8ae9f9f-dd11-4373-bf42-4bf31ec5bd19']}"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# We make sure that we dont trigger unwanted property mapping, so we wont allow an array in a string field.
2+
---
3+
4+
'Flowpack.NodeTemplates:Content.UnresolvablePropertyValues':
5+
superTypes:
6+
'Neos.Neos:Content': true
7+
ui:
8+
label: UnresolvablePropertyValues
9+
properties:
10+
someString:
11+
type: string
12+
asset:
13+
type: Neos\Media\Domain\Model\Asset
14+
images:
15+
type: array<Neos\Media\Domain\Model\ImageInterface>
16+
reference:
17+
type: reference
18+
references:
19+
type: references
20+
options:
21+
template:
22+
properties:
23+
someString: "${['foo']}"
24+
reference: true
25+
references: "${['some-non-existing-node-id']}"
26+
asset: "non-existing"
27+
images: "${['non-existing']}"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"properties": {
3+
"asset": "object(Neos\\Media\\Domain\\Model\\Asset, c228200e-7472-4290-9936-4454a5b5692a)",
4+
"images": [
5+
"object(Neos\\Media\\Domain\\Model\\Image, c8ae9f9f-dd11-4373-bf42-4bf31ec5bd19)"
6+
]
7+
},
8+
"references": {
9+
"reference": [
10+
{
11+
"node": "Node(some-node-id, unstructured)"
12+
}
13+
],
14+
"references": [
15+
{
16+
"node": "Node(some-node-id, unstructured)"
17+
},
18+
{
19+
"node": "Node(other-node-id, unstructured)"
20+
},
21+
{
22+
"node": "Node(real-node-id, unstructured)"
23+
}
24+
]
25+
}
26+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"properties": {
3+
"asset": "c228200e-7472-4290-9936-4454a5b5692a",
4+
"reference": "some-node-id",
5+
"references": [
6+
"some-node-id",
7+
"other-node-id",
8+
"Node(real-node-id, unstructured)"
9+
],
10+
"images": [
11+
"c8ae9f9f-dd11-4373-bf42-4bf31ec5bd19"
12+
]
13+
},
14+
"childNodes": []
15+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'{nodeTypeName}':
2+
options:
3+
template:
4+
properties:
5+
# asset -> object(Neos\Media\Domain\Model\Asset)
6+
# images -> array(Neos\Media\Domain\Model\Image)
7+
# reference -> Reference of NodeTypes (Neos.Neos:Document) with value Node(some-node-id)
8+
# references -> Nodes(some-node-id, other-node-id, real-node-id)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[
2+
{
3+
"message": "Template for \"UnresolvablePropertyValues\" only partially applied. Please check the newly created nodes beneath Node \/sites\/test-site\/homepage\/main\/new-node@live[Flowpack.NodeTemplates:Content.UnresolvablePropertyValues].",
4+
"severity": "ERROR"
5+
},
6+
{
7+
"message": "Property \"asset\" in NodeType \"Flowpack.NodeTemplates:Content.UnresolvablePropertyValues\" | FlowException(Object of type \"Neos\\Media\\Domain\\Model\\Asset\" with identity \"non-existing\" not found., 1686779371122)",
8+
"severity": "ERROR"
9+
},
10+
{
11+
"message": "Property \"images\" in NodeType \"Flowpack.NodeTemplates:Content.UnresolvablePropertyValues\" | FlowException(Could not convert target type \"array<Neos\\Media\\Domain\\Model\\ImageInterface>\", at property path \"0\": No converter found which can be used to convert from \"string\" to \"Neos\\Media\\Domain\\Model\\ImageInterface\"., 1297759968) | TypeConverterException(No converter found which can be used to convert from \"string\" to \"Neos\\Media\\Domain\\Model\\ImageInterface\"., 0)",
12+
"severity": "ERROR"
13+
},
14+
{
15+
"message": "Property \"someString\" in NodeType \"Flowpack.NodeTemplates:Content.UnresolvablePropertyValues\" | PropertyIgnoredException(Because value `[\"foo\"]` is not assignable to property type \"string\"., 1685958105644)",
16+
"severity": "ERROR"
17+
},
18+
{
19+
"message": "Reference \"reference\" in NodeType \"Flowpack.NodeTemplates:Content.UnresolvablePropertyValues\" | RuntimeException(Reference could not be set, because node reference(s) true cannot be resolved., 1685958176560)",
20+
"severity": "ERROR"
21+
},
22+
{
23+
"message": "Reference \"references\" in NodeType \"Flowpack.NodeTemplates:Content.UnresolvablePropertyValues\" | RuntimeException(Reference could not be set, because node reference(s) [\"some-non-existing-node-id\"] cannot be resolved., 1685958176560)",
24+
"severity": "ERROR"
25+
}
26+
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"properties": {
3+
"someString": [
4+
"foo"
5+
],
6+
"reference": true,
7+
"references": [
8+
"some-non-existing-node-id"
9+
],
10+
"asset": "non-existing",
11+
"images": [
12+
"non-existing"
13+
]
14+
},
15+
"childNodes": []
16+
}

0 commit comments

Comments
 (0)