diff --git a/modules/ui_patterns_layouts/tests/src/Functional/LayoutBuilderRenderTest.php b/modules/ui_patterns_layouts/tests/src/Functional/LayoutBuilderRenderTest.php index 8b23c5b2631f808a8bc2f25489f2bc04d34d1392..50ece86a78d026a11504ceca76470d7c7d9bd5e0 100644 --- a/modules/ui_patterns_layouts/tests/src/Functional/LayoutBuilderRenderTest.php +++ b/modules/ui_patterns_layouts/tests/src/Functional/LayoutBuilderRenderTest.php @@ -58,24 +58,30 @@ class LayoutBuilderRenderTest extends UiPatternsFunctionalTestBase { $test_data = $this->loadTestDataFixture(); $tests = [ + $test_data->getTestSet('attributes_empty'), + $test_data->getTestSet('attributes_default'), $test_data->getTestSet('textfield_default'), $test_data->getTestSet('token_default'), $test_data->getTestSet('context_exists_default'), ]; foreach ($tests as $test_set) { - $node = $this->createTestContentNode('page', $test_set['entity'] ?? []); $ui_patterns_config = $this->buildUiPatternsConfig($test_set); + $config_import['third_party_settings']['layout_builder']['sections'][0]['layout_id'] = 'ui_patterns:' . str_replace('-', '_', $test_set['component']['component_id']); $this->importConfigFixture( 'core.entity_view_display.node.page.full', $config_import ); - + $node = $this->createTestContentNode('page', $test_set['entity'] ?? []); $this->drupalGet('admin/structure/types/manage/page/display/full/layout'); - $assert_session->elementExists('css', '.ui-patterns-test-component'); + $assert_session->statusCodeEquals(200); + $component_id = str_replace('_', '-', explode(':', $test_set['component']['component_id'])[1]); + $assert_session->elementExists('css', '.ui-patterns-' . $component_id); $this->drupalGet('node/' . $node->id()); - $assert_session->elementExists('css', '.ui-patterns-test-component'); + $assert_session->statusCodeEquals(200); + $assert_session->elementExists('css', '.ui-patterns-' . $component_id); $this->validateRenderedComponent($test_set); + $node->delete(); } } diff --git a/src/Element/ComponentElementAlter.php b/src/Element/ComponentElementAlter.php index 70f43f295ecfa9c3528d841159c5c709a0d0969a..5e9b62e75e30a5df9fa3905025fa635ba5988697 100644 --- a/src/Element/ComponentElementAlter.php +++ b/src/Element/ComponentElementAlter.php @@ -8,6 +8,7 @@ use Drupal\Core\Plugin\Component; use Drupal\Core\Security\TrustedCallbackInterface; use Drupal\Core\Theme\ComponentPluginManager; use Drupal\ui_patterns\Plugin\UiPatterns\PropType\SlotPropType; +use Drupal\ui_patterns\PropTypeAdapterPluginManager; /** * Our additions to the SDC render element. @@ -17,7 +18,7 @@ class ComponentElementAlter implements TrustedCallbackInterface { /** * Constructs a ComponentElementAlter. */ - public function __construct(protected ComponentPluginManager $componentPluginManager) { + public function __construct(protected ComponentPluginManager $componentPluginManager, protected PropTypeAdapterPluginManager $adaptersManager) { } /** @@ -68,8 +69,19 @@ class ComponentElementAlter implements TrustedCallbackInterface { if (!isset($props[$prop_id])) { continue; } - $prop_type = $props[$prop_id]['ui_patterns']['type_definition']; - $element["#props"][$prop_id] = $prop_type->normalize($prop); + $definition = $props[$prop_id]; + $prop_type = $definition['ui_patterns']['type_definition']; + // Normalizing attributes to an array is not working + // if the prop type is defined by type=Drupal\Core\Template\Attribute + // This should actually be done by the normalize function. + $data = $prop_type->normalize($prop); + if (isset($definition['ui_patterns']['prop_type_adapter'])) { + $prop_type_adapter_id = $definition['ui_patterns']['prop_type_adapter']; + /** @var \Drupal\ui_patterns\PropTypeAdapterInterface $prop_type_adapter */ + $prop_type_adapter = $this->adaptersManager->createInstance($prop_type_adapter_id); + $data = $prop_type_adapter->transform($data); + } + $element["#props"][$prop_id] = $data; } return $element; } diff --git a/src/Element/ComponentElementBuilder.php b/src/Element/ComponentElementBuilder.php index ec87c5904b9037d672265e737234e23c7907d238..544168bd0fd8ea418785bc105494e55666a897ba 100644 --- a/src/Element/ComponentElementBuilder.php +++ b/src/Element/ComponentElementBuilder.php @@ -32,7 +32,6 @@ class ComponentElementBuilder implements TrustedCallbackInterface { public function __construct( protected SourcePluginManager $sourcesManager, protected PropTypePluginManager $propTypeManager, - protected PropTypeAdapterPluginManager $adaptersManager, protected ComponentPluginManager $componentPluginManager, ) { } @@ -86,12 +85,7 @@ class ComponentElementBuilder implements TrustedCallbackInterface { $prop_type = $definition['ui_patterns']['type_definition']; $build = $source->alterComponent($build); $data = $source->getValue($prop_type); - if (isset($definition['ui_patterns']['prop_type_adapter'])) { - $prop_type_adapter_id = $definition['ui_patterns']['prop_type_adapter']; - /** @var \Drupal\ui_patterns\PropTypeAdapterInterface $prop_type_adapter */ - $prop_type_adapter = $this->adaptersManager->createInstance($prop_type_adapter_id); - $data = $prop_type_adapter->transform($data); - } + if (empty($data) && $prop_type->getPluginId() !== 'attributes') { // For JSON Schema validator, empty value is not the same as missing // value, and we want to prevent some of the prop types rules to be diff --git a/tests/fixtures/TestDataSet.yml b/tests/fixtures/TestDataSet.yml index 154710146cee1aae1d56b1f48a9831c3dd8e771a..246d9d8bd4e8f39ed1134dffaef56e004d01f945 100644 --- a/tests/fixtures/TestDataSet.yml +++ b/tests/fixtures/TestDataSet.yml @@ -1,4 +1,52 @@ --- +attributes_empty: + component: + component_id: ui_patterns_test:test-component + props: + attributes_implicit: + source_id: attributes + source: + value: '' + attributes_ui_patterns: + source_id: attributes + source: + value: '' + attributes_class: + source_id: attributes + source: + value: '' + output: + props: + attributes_implicit: + value: '' + entity: {} + +attributes_default: + component: + component_id: ui_patterns_test:test-component + props: + attributes_implicit: + source_id: attributes + source: + value: 'ui_patterns="foo"' + attributes_ui_patterns: + source_id: attributes + source: + value: 'ui_patterns="foo"' + attributes_class: + source_id: attributes + source: + value: 'ui_patterns="foo"' + output: + props: + attributes_implicit: + value: 'ui_patterns="foo"' + attributes_ui_patterns: + value: 'ui_patterns="foo"' + attributes_class: + value: 'ui_patterns="foo"' + entity: {} + field_property_default: component: component_id: ui_patterns_test:test-component diff --git a/tests/modules/ui_patterns_test/components/test-component/test-component.component.yml b/tests/modules/ui_patterns_test/components/test-component/test-component.component.yml index 97cbbc3fdd519feab3409853a26cce89727e791c..5dfd6f874847f8af825a616f892d9379204f8922 100644 --- a/tests/modules/ui_patterns_test/components/test-component/test-component.component.yml +++ b/tests/modules/ui_patterns_test/components/test-component/test-component.component.yml @@ -19,6 +19,27 @@ props: enum: - "2" - "3" + attributes_implicit: + title: "Attributes (implicit typing)" + type: object + patternProperties: + ".+": + anyOf: + - type: + - string + - number + - type: array + items: + anyOf: + - type: number + - type: string + attributes_ui_patterns: + title: "Attributes (explicit typing)" + "$ref": "ui-patterns://attributes" + attributes_class: + title: "Attributes when type is a PHP namespace" + type: 'Drupal\Core\Template\Attribute' + slots: slot: title: "Slot" diff --git a/tests/modules/ui_patterns_test/components/test-component/test-component.twig b/tests/modules/ui_patterns_test/components/test-component/test-component.twig index 8c0d0364144d429ab2f387a014f26b82c45805ec..3e74de2a6dfa8a4fd71e9b8e7094cf93120ac062 100644 --- a/tests/modules/ui_patterns_test/components/test-component/test-component.twig +++ b/tests/modules/ui_patterns_test/components/test-component/test-component.twig @@ -8,6 +8,15 @@ <div class="ui-patterns-props-enum_string"> {{ enum_string }} </div> + <div class="ui-patterns-props-attributes_implicit"> + {{ attributes_implicit }} + </div> + <div class="ui-patterns-props-attributes_ui_patterns"> + {{ attributes_ui_patterns }} + </div> + <div class="ui-patterns-props-attributes_class"> + {{ attributes_class }} + </div> <div class="ui-patterns-slots-slot"> {{ slot }} </div> diff --git a/tests/src/Functional/UiPatternsFunctionalTestBase.php b/tests/src/Functional/UiPatternsFunctionalTestBase.php index af4af9e2b7173cb35d422317e4c6f9d805f59ce0..9c56261a806d7dfd84e9b2733b1030e4d3eb556d 100644 --- a/tests/src/Functional/UiPatternsFunctionalTestBase.php +++ b/tests/src/Functional/UiPatternsFunctionalTestBase.php @@ -8,6 +8,7 @@ use Drupal\Component\Serialization\Yaml; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\ui_patterns\Traits\TestContentCreationTrait; use Drupal\Tests\ui_patterns\Traits\TestDataTrait; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * Base function testing. @@ -57,6 +58,9 @@ abstract class UiPatternsFunctionalTestBase extends BrowserTestBase { if ($this->user) { $this->drupalLogin($this->user); } + else { + throw new AccessDeniedHttpException($this->getTextContent()); + } } /** @@ -95,6 +99,7 @@ abstract class UiPatternsFunctionalTestBase extends BrowserTestBase { * The config fixture. */ public function importConfigFixture(string $config_id, array $config) { + $this->configInitialize = FALSE; $this->initializeConfig(); \Drupal::service('config.storage.sync')->write($config_id, $config); $config_importer = $this->configImporter(); @@ -128,6 +133,7 @@ abstract class UiPatternsFunctionalTestBase extends BrowserTestBase { protected function validateRenderedComponent($test_set) { $output = $test_set['output'] ?? []; $page = $this->getSession()->getPage(); + foreach ($output as $prop_or_slot => $prop_or_slot_item) { foreach ($prop_or_slot_item as $prop_name => $output) { $expected_outputs_here = ($prop_or_slot === "props") ? [$output] : $output; diff --git a/ui_patterns.services.yml b/ui_patterns.services.yml index 16062dcd2435304b78887093ccc9d99a3cfac923..abffbf352b4d9e402649948f7be24826407bb364 100644 --- a/ui_patterns.services.yml +++ b/ui_patterns.services.yml @@ -45,12 +45,12 @@ services: arguments: - "@plugin.manager.ui_patterns_source" - "@plugin.manager.ui_patterns_prop_type" - - "@plugin.manager.ui_patterns_prop_type_adapter" - "@plugin.manager.sdc" ui_patterns.component_element_alter: class: Drupal\ui_patterns\Element\ComponentElementAlter arguments: - "@plugin.manager.sdc" + - "@plugin.manager.ui_patterns_prop_type_adapter" # JSON schema management. ui_patterns.schema_stream_wrapper: