Skip to content

Commit

Permalink
TASK: Move creationDialog logic of `DefaultPropertyEditorPostproces…
Browse files Browse the repository at this point in the history
…sor` to Neos.Ui

Into the `CreationDialogPostprocessor`

NodeType configuration, which resides in `ui.creationDialog` is part of the Neos.Neos.Ui
  • Loading branch information
mhsdesign committed Mar 1, 2024
1 parent 8ca3440 commit e27b791
Show file tree
Hide file tree
Showing 2 changed files with 283 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@
* 'someProperty':
* # ...
*
*
* Sets default editor configurations for elements
* -----------------------------------------------
* We add default editor configurations for elements based on type and editor.
* Similar to the process for regular properties in {@see \Neos\Neos\NodeTypePostprocessor\DefaultPropertyEditorPostprocessor}
*
*/
class CreationDialogNodeTypePostprocessor implements NodeTypePostprocessorInterface
{
Expand All @@ -80,18 +86,68 @@ class CreationDialogNodeTypePostprocessor implements NodeTypePostprocessorInterf
*/
public function process(NodeType $nodeType, array &$configuration, array $options): void
{
if (!isset($configuration['properties'])) {
return;
}
$creationDialogElements = $configuration['ui']['creationDialog']['elements'] ?? [];

$creationDialogElements = $this->promotePropertiesIntoCreationDialog($configuration['properties'], $creationDialogElements);
if (!empty($configuration['properties'] ?? null)) {
$creationDialogElements = $this->promotePropertiesIntoCreationDialog($configuration['properties'], $creationDialogElements);
}

$this->mergeDefaultCreationDialogElementEditors($creationDialogElements);

if ($creationDialogElements !== []) {
$configuration['ui']['creationDialog']['elements'] = (new PositionalArraySorter($creationDialogElements))->toArray();
}
}

/**
* @param array<string, mixed> $creationDialogElements
*/
private function mergeDefaultCreationDialogElementEditors(array &$creationDialogElements): void
{
foreach ($creationDialogElements as &$elementConfiguration) {
if (!isset($elementConfiguration['type'])) {
continue;
}

$type = $elementConfiguration['type'];
$defaultConfigurationFromDataType = $this->dataTypesDefaultConfiguration[$type] ?? [];

// FIRST STEP: Figure out which editor should be used
// - Default: editor as configured from the data type
// - Override: editor as configured from the property configuration.
if (isset($elementConfiguration['ui']['editor'])) {
$editor = $elementConfiguration['ui']['editor'];
} elseif (isset($defaultConfigurationFromDataType['editor'])) {
$editor = $defaultConfigurationFromDataType['editor'];
} else {
// No exception since the configuration could be a partial configuration overriding a property
// with showInCreationDialog flag set
continue;
}

// SECOND STEP: Build up the full UI configuration by merging:
// - take configuration from editor defaults
// - take configuration from dataType
// - take configuration from creationDialog elements (NodeTypes)
$mergedUiConfiguration = $this->editorDefaultConfiguration[$editor] ?? [];
$mergedUiConfiguration = Arrays::arrayMergeRecursiveOverrule(
$mergedUiConfiguration,
$defaultConfigurationFromDataType
);
$mergedUiConfiguration = Arrays::arrayMergeRecursiveOverrule(
$mergedUiConfiguration,
$elementConfiguration['ui'] ?? []
);
$elementConfiguration['ui'] = $mergedUiConfiguration;
$elementConfiguration['ui']['editor'] = $editor;
}
}

/**
* @param array<string, mixed> $properties
* @param array<string, mixed> $explicitCreationDialogElements
* @return array<string, mixed>
*/
private function promotePropertiesIntoCreationDialog(array $properties, array $explicitCreationDialogElements): array
{
foreach ($properties as $propertyName => $propertyConfiguration) {
Expand Down Expand Up @@ -146,6 +202,7 @@ private function promotePropertyIntoCreationDialog(string $propertyName, array $
$convertedConfiguration['ui']['hidden'] = $propertyConfiguration['ui']['inspector']['hidden'];
}

// todo maybe duplicated due to mergeDefaultCreationDialogElementEditors
$editor = $propertyConfiguration['ui']['inspector']['editor']
?? $dataTypeDefaultConfiguration['editor']
?? 'Neos.Neos/Inspector/Editors/TextFieldEditor';
Expand Down
224 changes: 222 additions & 2 deletions Tests/Unit/CreationDialogNodeTypePostprocessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public function setUp(): void
}

/**
* promoted elements (showInCreationDialog: true)
*
* @test
*/
public function processCopiesInspectorConfigurationToCreationDialogElements(): void
Expand Down Expand Up @@ -103,6 +105,8 @@ public function processDoesNotCreateEmptyCreationDialogs(): void
}

/**
* promoted elements (showInCreationDialog: true)
*
* @test
*/
public function processRespectsDataTypeDefaultConfiguration(): void
Expand Down Expand Up @@ -144,10 +148,12 @@ public function processRespectsDataTypeDefaultConfiguration(): void
],
];

self::assertSame($expectedElements, $configuration['ui']['creationDialog']['elements']);
self::assertEquals($expectedElements, $configuration['ui']['creationDialog']['elements']);
}

/**
* promoted elements (showInCreationDialog: true)
*
* @test
*/
public function processRespectsEditorDefaultConfiguration(): void
Expand Down Expand Up @@ -198,6 +204,220 @@ public function processRespectsEditorDefaultConfiguration(): void
],
];

self::assertSame($expectedElements, $configuration['ui']['creationDialog']['elements']);
self::assertEquals($expectedElements, $configuration['ui']['creationDialog']['elements']);
}

/**
* default editor
*
* @test
*/
public function processConvertsCreationDialogConfiguration(): void
{
$configuration = [
'ui' => [
'creationDialog' => [
'elements' => [
'elementWithoutType' => [
'ui' => [
'label' => 'Some Label'
]
],
'elementWithUnknownType' => [
'type' => 'TypeWithoutDataTypeConfig',
'ui' => [
'label' => 'Some Label',
'editor' => 'EditorFromPropertyConfig',
]
],
'elementWithEditorFromDataTypeConfig' => [
'type' => 'TypeWithDataTypeConfig',
'ui' => [
'value' => 'fromPropertyConfig',
'elementValue' => 'fromPropertyConfig',
]
],
'elementWithEditorFromDataTypeConfigWithoutUiConfig' => [
'type' => 'TypeWithDataTypeConfig'
],
'elementWithOverriddenEditorConfig' => [
'type' => 'TypeWithDataTypeConfig',
'ui' => [
'editor' => 'EditorFromPropertyConfig',
'value' => 'fromPropertyConfig',
'elementValue' => 'fromPropertyConfig',
]
],
'elementWithOverriddenEditorConfigAndEditorDefaultConfig' => [
'type' => 'TypeWithDataTypeConfig',
'ui' => [
'editor' => 'EditorWithDefaultConfig',
'value' => 'fromPropertyConfig',
'elementValue' => 'fromPropertyConfig',
]
],
'elementWithEditorDefaultConfig' => [
'type' => 'TypeWithDefaultEditorConfig',
'ui' => [
'value' => 'fromPropertyConfig',
'elementValue' => 'fromPropertyConfig',
]
],
'elementWithOverriddenEditorConfigAndEditorDefaultConfig2' => [
'type' => 'TypeWithDefaultEditorConfig',
'ui' => [
'editor' => 'EditorWithoutDefaultConfig',
'elementValue' => 'fromPropertyConfig',
]
],
'elementWithOverriddenEditorConfigAndEditorDefaultConfig3' => [
'type' => 'TypeWithDefaultEditorConfig2',
'ui' => [
'editor' => 'EditorWithDefaultConfig',
'elementValue' => 'fromPropertyConfig',
]
],
],
],
],
];

$this->inject($this->postprocessor, 'editorDefaultConfiguration', [
'EditorWithDefaultConfig' => [
'value' => 'fromEditorDefaultConfig',
'editorDefaultValue' => 'fromEditorDefaultConfig',
],
]);

$this->inject($this->postprocessor, 'dataTypesDefaultConfiguration', [
'TypeWithDataTypeConfig' => [
'editor' => 'EditorFromDataTypeConfig',
'value' => 'fromDataTypeConfig',
'dataTypeValue' => 'fromDataTypeConfig',
],
'TypeWithDefaultEditorConfig' => [
'editor' => 'EditorWithDefaultConfig',
'value' => 'fromDataTypeConfig',
'dataTypeValue' => 'fromDataTypeConfig',
],
'TypeWithDefaultEditorConfig2' => [
'editor' => 'EditorWithDefaultConfig',
'dataTypeValue' => 'fromDataTypeConfig',
],
]);

$expectedResult = [
'ui' => [
'creationDialog' => [
'elements' => [
'elementWithoutType' => [
'ui' => [
'label' => 'Some Label'
]
],
'elementWithUnknownType' => [
'type' => 'TypeWithoutDataTypeConfig',
'ui' => [
'label' => 'Some Label',
'editor' => 'EditorFromPropertyConfig',
]
],
'elementWithEditorFromDataTypeConfig' => [
'type' => 'TypeWithDataTypeConfig',
'ui' => [
'editor' => 'EditorFromDataTypeConfig',
'value' => 'fromPropertyConfig',
'dataTypeValue' => 'fromDataTypeConfig',
'elementValue' => 'fromPropertyConfig',
]
],
'elementWithEditorFromDataTypeConfigWithoutUiConfig' => [
'type' => 'TypeWithDataTypeConfig',
'ui' => [
'editor' => 'EditorFromDataTypeConfig',
'value' => 'fromDataTypeConfig',
'dataTypeValue' => 'fromDataTypeConfig',
]
],
'elementWithOverriddenEditorConfig' => [
'type' => 'TypeWithDataTypeConfig',
'ui' => [
'editor' => 'EditorFromPropertyConfig',
'value' => 'fromPropertyConfig',
'dataTypeValue' => 'fromDataTypeConfig',
'elementValue' => 'fromPropertyConfig',
]
],
'elementWithOverriddenEditorConfigAndEditorDefaultConfig' => [
'type' => 'TypeWithDataTypeConfig',
'ui' => [
'value' => 'fromPropertyConfig',
'editorDefaultValue' => 'fromEditorDefaultConfig',
'editor' => 'EditorWithDefaultConfig',
'dataTypeValue' => 'fromDataTypeConfig',
'elementValue' => 'fromPropertyConfig',
]
],
'elementWithEditorDefaultConfig' => [
'type' => 'TypeWithDefaultEditorConfig',
'ui' => [
'value' => 'fromPropertyConfig',
'editorDefaultValue' => 'fromEditorDefaultConfig',
'editor' => 'EditorWithDefaultConfig',
'dataTypeValue' => 'fromDataTypeConfig',
'elementValue' => 'fromPropertyConfig',
]
],
'elementWithOverriddenEditorConfigAndEditorDefaultConfig2' => [
'type' => 'TypeWithDefaultEditorConfig',
'ui' => [
'editor' => 'EditorWithoutDefaultConfig',
'value' => 'fromDataTypeConfig',
'dataTypeValue' => 'fromDataTypeConfig',
'elementValue' => 'fromPropertyConfig',
]
],
'elementWithOverriddenEditorConfigAndEditorDefaultConfig3' => [
'type' => 'TypeWithDefaultEditorConfig2',
'ui' => [
'value' => 'fromEditorDefaultConfig',
'editorDefaultValue' => 'fromEditorDefaultConfig',
'editor' => 'EditorWithDefaultConfig',
'dataTypeValue' => 'fromDataTypeConfig',
'elementValue' => 'fromPropertyConfig',
]
],
],
],
],
];

$this->postprocessor->process($this->mockNodeType, $configuration, []);

self::assertSame($expectedResult, $configuration);
}

/**
* @test
*/
public function processDoesNotThrowExceptionIfNoCreationDialogEditorCanBeResolved(): void
{
$configuration = [
'ui' => [
'creationDialog' => [
'elements' => [
'someElement' => [
'type' => 'string',
'ui' => ['label' => 'Foo']
],
],
],
],
];
$expected = $configuration;

$this->postprocessor->process($this->mockNodeType, $configuration, []);

self::assertSame($expected, $configuration);
}
}

0 comments on commit e27b791

Please sign in to comment.