diff --git a/core/modules/layout_builder/layout_builder.services.yml b/core/modules/layout_builder/layout_builder.services.yml index 56b4bf88bd..7edd0836f4 100644 --- a/core/modules/layout_builder/layout_builder.services.yml +++ b/core/modules/layout_builder/layout_builder.services.yml @@ -46,3 +46,14 @@ services: inline_block.usage: class: Drupal\layout_builder\InlineBlockUsage arguments: ['@database'] + layout_builder.normalizer.section_data: + class: Drupal\layout_builder\Normalizer\SectionDataNormalizer + tags: + # Priority must be higher than serializer.normalizer.typed_data. + - { name: normalizer, priority: 1 } + layout_builder.normalizer.layout_section_item: + class: Drupal\layout_builder\Normalizer\LayoutSectionItemNormalizer + public: false + tags: + # Priority must be higher than serializer.normalizer.entity_reference_field_item. + - { name: normalizer, priority: 9 } diff --git a/core/modules/layout_builder/src/Normalizer/LayoutSectionItemNormalizer.php b/core/modules/layout_builder/src/Normalizer/LayoutSectionItemNormalizer.php new file mode 100644 index 0000000000..90e18691b6 --- /dev/null +++ b/core/modules/layout_builder/src/Normalizer/LayoutSectionItemNormalizer.php @@ -0,0 +1,32 @@ +<?php + +namespace Drupal\layout_builder\Normalizer; + +use Drupal\layout_builder\Plugin\DataType\SectionData; +use Drupal\layout_builder\Plugin\Field\FieldType\LayoutSectionItem; +use Drupal\serialization\Normalizer\FieldItemNormalizer; + +/** + * Normalizes section lists. + * + * @todo Remove in https://www.drupal.org/node/issues/2957385 + * + * @internal + */ +class LayoutSectionItemNormalizer extends FieldItemNormalizer { + + /** + * {@inheritdoc} + */ + protected $supportedInterfaceOrClass = LayoutSectionItem::class; + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = NULL, array $context = []) { + /** @var \Drupal\layout_builder\Plugin\DataType\SectionData $section_data */ + $section_data = $this->serializer->denormalize($data['section'], SectionData::class, $format, $context);; + return parent::denormalize($section_data->getValue(), $class, $format, $context); + } + +} diff --git a/core/modules/layout_builder/src/Normalizer/SectionDataNormalizer.php b/core/modules/layout_builder/src/Normalizer/SectionDataNormalizer.php new file mode 100644 index 0000000000..25944a2ae6 --- /dev/null +++ b/core/modules/layout_builder/src/Normalizer/SectionDataNormalizer.php @@ -0,0 +1,45 @@ +<?php + +namespace Drupal\layout_builder\Normalizer; + +use Drupal\layout_builder\Plugin\DataType\SectionData; +use Drupal\layout_builder\Section; +use Drupal\serialization\Normalizer\TypedDataNormalizer; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; + +/** + * Normalizes section data. + */ +class SectionDataNormalizer extends TypedDataNormalizer implements DenormalizerInterface { + + /** + * {@inheritdoc} + */ + protected $supportedInterfaceOrClass = SectionData::class; + + /** + * {@inheritdoc} + */ + public function normalize($object, $format = NULL, array $context = []) { + return $object->getValue()->toArray(); + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = NULL, array $context = []) { + if (!isset($context['target_instance'])) { + throw new InvalidArgumentException('$context[\'target_instance\'] must be set to denormalize with the SectionDataNormalizer'); + } + + /** @var \Drupal\Core\Field\FieldItemInterface $field_item */ + $target_instance = $context['target_instance']; + + $object = SectionData::createInstance($target_instance->getDataDefinition()); + $section = Section::fromArray($data); + $object->setValue($section); + return $object; + } + +} diff --git a/core/modules/layout_builder/src/Plugin/DataType/SectionData.php b/core/modules/layout_builder/src/Plugin/DataType/SectionData.php index 353c53fe7c..79f8f161d7 100644 --- a/core/modules/layout_builder/src/Plugin/DataType/SectionData.php +++ b/core/modules/layout_builder/src/Plugin/DataType/SectionData.php @@ -27,6 +27,9 @@ class SectionData extends TypedData { * {@inheritdoc} */ public function setValue($value, $notify = TRUE) { + if ($value && is_array($value)) { + $value = Section::fromArray($value); + } if ($value && !$value instanceof Section) { throw new \InvalidArgumentException(sprintf('Value assigned to "%s" is not a valid section', $this->getName())); } diff --git a/core/modules/layout_builder/tests/src/Unit/SectionDataNormalizerTest.php b/core/modules/layout_builder/tests/src/Unit/SectionDataNormalizerTest.php new file mode 100644 index 0000000000..17e07e2d3e --- /dev/null +++ b/core/modules/layout_builder/tests/src/Unit/SectionDataNormalizerTest.php @@ -0,0 +1,86 @@ +<?php + +namespace Drupal\Tests\layout_builder\Unit; + +use Drupal\Core\Field\FieldItemInterface; +use Drupal\Core\TypedData\DataDefinitionInterface; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Drupal\layout_builder\Normalizer\SectionDataNormalizer; +use Drupal\layout_builder\Plugin\DataType\SectionData; +use Drupal\layout_builder\Section; +use Drupal\Tests\UnitTestCase; + +/** + * @coversDefaultClass \Drupal\layout_builder\Normalizer\SectionDataNormalizer + * @group layout_builder + */ +class SectionDataNormalizerTest extends UnitTestCase { + + /** + * The normalizer. + * + * @var \Drupal\layout_builder\Normalizer\SectionDataNormalizer + */ + protected $normalizer; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $this->normalizer = new SectionDataNormalizer(); + } + + /** + * @covers ::supportsNormalization + */ + public function testSupportsNormalization() { + $section_data = $this->prophesize(SectionData::class); + $this->assertTrue($this->normalizer->supportsNormalization($section_data->reveal())); + } + + /** + * @covers ::supportsDenormalization + */ + public function testSupportsDenormalization() { + $this->assertTrue($this->normalizer->supportsDenormalization([], SectionData::class)); + } + + /** + * Tests the normalize function. + * + * @covers ::normalize + */ + public function testNormalize() { + $data = ['foo']; + $section_data = $this->prophesize(SectionData::class); + $section = $this->prophesize(Section::class); + $section->toArray() + ->willReturn($data); + $section_data->getValue() + ->willReturn($section); + $this->assertArrayEquals($data, $this->normalizer->normalize($section_data->reveal())); + } + + /** + * Tests the denormalize function. + * + * @covers ::denormalize + */ + public function testDenormalize() { + $data = ['foo']; + $target_instance = $this->prophesize(FieldItemInterface::class); + $target_instance->getDataDefinition() + ->willReturn($this->prophesize(DataDefinitionInterface::class)); + $context = [ + 'target_instance' => [ + $target_instance, + ], + ]; + $this->setExpectedException(InvalidArgumentException::class); + $this->normalizer->denormalize($data, SectionData::class); + $section_data = $this->normalizer->denormalize($data, SectionData::class, $context); + $this->assertArrayEquals($data, $section_data->getValue()->toArray()); + } + +}