From 40215f274fb9becb6b7940ef30843dbbf497093a Mon Sep 17 00:00:00 2001 From: Luca Rath-Heel Date: Wed, 7 Apr 2021 14:49:35 +0200 Subject: [PATCH] Add teaser selection resolver (#83) --- .../TeaserSelectionResolver.php | 70 ++++++ Content/Serializer/TeaserSerializer.php | 103 +++++++++ .../Serializer/TeaserSerializerInterface.php | 25 ++ Resources/config/content-type-resolvers.xml | 11 + Resources/config/serializers.xml | 11 + .../TeaserSelectionResolverTest.php | 204 +++++++++++++++++ .../Serializer/TeaserSerializerTest.php | 216 ++++++++++++++++++ 7 files changed, 640 insertions(+) create mode 100644 Content/ContentTypeResolver/TeaserSelectionResolver.php create mode 100644 Content/Serializer/TeaserSerializer.php create mode 100644 Content/Serializer/TeaserSerializerInterface.php create mode 100644 Tests/Unit/Content/ContentTypeResolver/TeaserSelectionResolverTest.php create mode 100644 Tests/Unit/Content/Serializer/TeaserSerializerTest.php diff --git a/Content/ContentTypeResolver/TeaserSelectionResolver.php b/Content/ContentTypeResolver/TeaserSelectionResolver.php new file mode 100644 index 0000000..6c57d73 --- /dev/null +++ b/Content/ContentTypeResolver/TeaserSelectionResolver.php @@ -0,0 +1,70 @@ +teaserManager = $teaserManager; + $this->teaserSerializer = $teaserSerializer; + } + + public function resolve($data, PropertyInterface $property, string $locale, array $attributes = []): ContentView + { + $value = array_merge( + [ + 'presentAs' => null, + 'items' => [], + ], + \is_array($data) ? $data : [] + ); + $items = $value['items'] ?? []; + + if (!\is_array($items) || 0 === \count($items)) { + return new ContentView([], $value); + } + + $teasers = $this->teaserManager->find($items, $locale); + $teasers = array_map( + function (Teaser $teaser) use ($locale) { + return $this->teaserSerializer->serialize($teaser, $locale); + }, + $teasers + ); + + return new ContentView($teasers, $value); + } +} diff --git a/Content/Serializer/TeaserSerializer.php b/Content/Serializer/TeaserSerializer.php new file mode 100644 index 0000000..c518a70 --- /dev/null +++ b/Content/Serializer/TeaserSerializer.php @@ -0,0 +1,103 @@ +arraySerializer = $arraySerializer; + $this->mediaSerializer = $mediaSerializer; + $this->mediaManager = $mediaManager; + $this->referenceStorePool = $referenceStorePool; + } + + /** + * @return mixed[] + */ + public function serialize(Teaser $teaser, string $locale, ?SerializationContext $context = null): array + { + $teaserData = $this->arraySerializer->serialize($teaser, $context); + unset($teaserData['mediaId']); + + $mediaId = $teaser->getMediaId(); + $mediaData = null; + if ($mediaId) { + $media = $this->mediaManager->getEntityById($mediaId); + $mediaData = $this->mediaSerializer->serialize($media, $locale); + } + + $teaserData['media'] = $mediaData; + + $this->addToReferenceStore($teaser->getId(), $teaser->getType()); + + return $teaserData; + } + + /** + * @param int|string $id + */ + private function addToReferenceStore($id, string $alias): void + { + if ('pages' === $alias) { + // unfortunately the reference store for pages was not adjusted and still uses content as alias + $alias = 'content'; + } + + if ('articles' === $alias) { + $alias = 'article'; + } + + try { + $referenceStore = $this->referenceStorePool->getStore($alias); + } catch (ReferenceStoreNotExistsException $e) { + // @ignoreException do nothing when reference store was not found + + return; + } + + $referenceStore->add($id); + } +} diff --git a/Content/Serializer/TeaserSerializerInterface.php b/Content/Serializer/TeaserSerializerInterface.php new file mode 100644 index 0000000..a382a70 --- /dev/null +++ b/Content/Serializer/TeaserSerializerInterface.php @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + diff --git a/Tests/Unit/Content/ContentTypeResolver/TeaserSelectionResolverTest.php b/Tests/Unit/Content/ContentTypeResolver/TeaserSelectionResolverTest.php new file mode 100644 index 0000000..052edb9 --- /dev/null +++ b/Tests/Unit/Content/ContentTypeResolver/TeaserSelectionResolverTest.php @@ -0,0 +1,204 @@ +teaserManager = $this->prophesize(TeaserManagerInterface::class); + $this->teaserSerializer = $this->prophesize(TeaserSerializerInterface::class); + + $this->teaserSelectionResolver = new TeaserSelectionResolver( + $this->teaserManager->reveal(), + $this->teaserSerializer->reveal() + ); + } + + public function testGetContentType(): void + { + self::assertSame('teaser_selection', $this->teaserSelectionResolver::getContentType()); + } + + public function testResolve(): void + { + $locale = 'en'; + $items = [ + [ + 'id' => '74a36ca1-4805-48a0-b37d-3ffb3a6be9b1', + 'type' => 'pages', + ], + [ + 'id' => '5524447a-1afd-4d08-bb25-d34f46e3621c', + 'type' => 'articles', + ], + [ + 'id' => 'bb03b2f1-135f-4fcf-b27a-b2cf5f36be66', + 'type' => 'other', + ], + ]; + $value = [ + 'presentAs' => 'two-columns', + 'items' => $items, + ]; + + /** @var PropertyInterface|ObjectProphecy $property */ + $property = $this->prophesize(PropertyInterface::class); + + $pageTeaser = $this->prophesize(Teaser::class); + $articleTeaser = $this->prophesize(Teaser::class); + $otherTeaser = $this->prophesize(Teaser::class); + + $this->teaserManager->find($items, $locale)->willReturn([ + $pageTeaser->reveal(), + $articleTeaser->reveal(), + $otherTeaser->reveal(), + ]); + + $this->teaserSerializer->serialize($pageTeaser->reveal(), $locale)->willReturn([ + 'id' => '74a36ca1-4805-48a0-b37d-3ffb3a6be9b1', + 'type' => 'pages', + 'locale' => 'en', + 'title' => 'My page', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'url' => '/my-page', + 'attributes' => [ + 'structureType' => 'default', + 'webspaceKey' => 'example', + ], + 'media' => [ + 'id' => 1, + 'formatUri' => '/media/1/{format}/media-1.jpg?=v1-0', + ], + ]); + + $this->teaserSerializer->serialize($articleTeaser->reveal(), $locale)->willReturn([ + 'id' => '5524447a-1afd-4d08-bb25-d34f46e3621c', + 'type' => 'articles', + 'locale' => 'en', + 'title' => 'My article', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'url' => '/my-article', + 'attributes' => [ + 'structureType' => 'default', + 'webspaceKey' => 'example', + ], + 'media' => null, + ]); + + $this->teaserSerializer->serialize($otherTeaser->reveal(), $locale)->willReturn([ + 'id' => 'bb03b2f1-135f-4fcf-b27a-b2cf5f36be66', + 'type' => 'other', + 'locale' => 'en', + 'title' => 'My thing', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'url' => '/my-thing', + 'media' => null, + ]); + + $result = $this->teaserSelectionResolver->resolve($value, $property->reveal(), $locale); + + self::assertSame([ + [ + 'id' => '74a36ca1-4805-48a0-b37d-3ffb3a6be9b1', + 'type' => 'pages', + 'locale' => 'en', + 'title' => 'My page', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'url' => '/my-page', + 'attributes' => [ + 'structureType' => 'default', + 'webspaceKey' => 'example', + ], + 'media' => [ + 'id' => 1, + 'formatUri' => '/media/1/{format}/media-1.jpg?=v1-0', + ], + ], + [ + 'id' => '5524447a-1afd-4d08-bb25-d34f46e3621c', + 'type' => 'articles', + 'locale' => 'en', + 'title' => 'My article', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'url' => '/my-article', + 'attributes' => [ + 'structureType' => 'default', + 'webspaceKey' => 'example', + ], + 'media' => null, + ], + [ + 'id' => 'bb03b2f1-135f-4fcf-b27a-b2cf5f36be66', + 'type' => 'other', + 'locale' => 'en', + 'title' => 'My thing', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'url' => '/my-thing', + 'media' => null, + ], + ], $result->getContent()); + self::assertSame($value, $result->getView()); + } + + public function testResolveNullValue(): void + { + $locale = 'en'; + $value = null; + + /** @var PropertyInterface|ObjectProphecy $property */ + $property = $this->prophesize(PropertyInterface::class); + + $this->teaserManager->find(Argument::any())->shouldNotBeCalled(); + $this->teaserSerializer->serialize(Argument::any())->shouldNotBeCalled(); + + $result = $this->teaserSelectionResolver->resolve($value, $property->reveal(), $locale); + + self::assertSame([], $result->getContent()); + self::assertSame([ + 'presentAs' => null, + 'items' => [], + ], $result->getView()); + } +} diff --git a/Tests/Unit/Content/Serializer/TeaserSerializerTest.php b/Tests/Unit/Content/Serializer/TeaserSerializerTest.php new file mode 100644 index 0000000..7e33208 --- /dev/null +++ b/Tests/Unit/Content/Serializer/TeaserSerializerTest.php @@ -0,0 +1,216 @@ +arraySerializer = $this->prophesize(ArraySerializerInterface::class); + $this->mediaSerializer = $this->prophesize(MediaSerializerInterface::class); + $this->mediaManager = $this->prophesize(MediaManagerInterface::class); + $this->referenceStorePool = $this->prophesize(ReferenceStorePoolInterface::class); + + $this->teaserSerializer = new TeaserSerializer( + $this->arraySerializer->reveal(), + $this->mediaSerializer->reveal(), + $this->mediaManager->reveal(), + $this->referenceStorePool->reveal() + ); + } + + public function testSerialize(): void + { + $locale = 'en'; + + $teaser = $this->prophesize(Teaser::class); + $teaser->getId()->willReturn('74a36ca1-4805-48a0-b37d-3ffb3a6be9b1'); + $teaser->getType()->willReturn('pages'); + $teaser->getMediaId()->willReturn(1); + + $media = $this->prophesize(MediaInterface::class); + $this->mediaManager->getEntityById(1)->willReturn($media->reveal()); + + $this->arraySerializer->serialize($teaser, null)->willReturn([ + 'id' => '74a36ca1-4805-48a0-b37d-3ffb3a6be9b1', + 'type' => 'pages', + 'locale' => 'en', + 'title' => 'My page', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'mediaId' => 1, + 'url' => '/my-page', + 'attributes' => [ + 'structureType' => 'default', + 'webspaceKey' => 'example', + ], + ]); + + $this->mediaSerializer->serialize($media, $locale)->willReturn([ + 'id' => 1, + 'formatUri' => '/media/1/{format}/media-1.jpg?=v1-0', + ]); + + $referenceStore = $this->prophesize(ReferenceStoreInterface::class); + $this->referenceStorePool->getStore('content')->willReturn($referenceStore->reveal()); + $referenceStore->add('74a36ca1-4805-48a0-b37d-3ffb3a6be9b1')->shouldBeCalled(); + + $result = $this->teaserSerializer->serialize($teaser->reveal(), $locale); + + $this->assertSame([ + 'id' => '74a36ca1-4805-48a0-b37d-3ffb3a6be9b1', + 'type' => 'pages', + 'locale' => 'en', + 'title' => 'My page', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'url' => '/my-page', + 'attributes' => [ + 'structureType' => 'default', + 'webspaceKey' => 'example', + ], + 'media' => [ + 'id' => 1, + 'formatUri' => '/media/1/{format}/media-1.jpg?=v1-0', + ], + ], $result); + } + + public function testSerializeArticleTeaserWithoutMedia(): void + { + $locale = 'en'; + + $teaser = $this->prophesize(Teaser::class); + $teaser->getId()->willReturn('5524447a-1afd-4d08-bb25-d34f46e3621c'); + $teaser->getType()->willReturn('articles'); + $teaser->getMediaId()->willReturn(null); + + $this->mediaManager->getEntityById(Argument::any())->shouldNotBeCalled(); + + $this->arraySerializer->serialize($teaser, null)->willReturn([ + 'id' => '5524447a-1afd-4d08-bb25-d34f46e3621c', + 'type' => 'articles', + 'locale' => 'en', + 'title' => 'My article', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'mediaId' => null, + 'url' => '/my-article', + 'attributes' => [ + 'structureType' => 'default', + 'webspaceKey' => 'example', + ], + ]); + + $this->mediaSerializer->serialize(Argument::any())->shouldNotBeCalled(); + + $referenceStore = $this->prophesize(ReferenceStoreInterface::class); + $this->referenceStorePool->getStore('article')->willReturn($referenceStore->reveal()); + $referenceStore->add('5524447a-1afd-4d08-bb25-d34f46e3621c')->shouldBeCalled(); + + $result = $this->teaserSerializer->serialize($teaser->reveal(), $locale); + + $this->assertSame([ + 'id' => '5524447a-1afd-4d08-bb25-d34f46e3621c', + 'type' => 'articles', + 'locale' => 'en', + 'title' => 'My article', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'url' => '/my-article', + 'attributes' => [ + 'structureType' => 'default', + 'webspaceKey' => 'example', + ], + 'media' => null, + ], $result); + } + + public function testSerializeOtherTeaserWithContext(): void + { + $locale = 'en'; + $context = $this->prophesize(SerializationContext::class); + + $teaser = $this->prophesize(Teaser::class); + $teaser->getId()->willReturn('bb03b2f1-135f-4fcf-b27a-b2cf5f36be66'); + $teaser->getType()->willReturn('other'); + $teaser->getMediaId()->willReturn(null); + + $this->arraySerializer->serialize($teaser, $context)->willReturn([ + 'id' => 'bb03b2f1-135f-4fcf-b27a-b2cf5f36be66', + 'type' => 'other', + 'locale' => 'en', + 'title' => 'My thing', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'mediaId' => null, + 'url' => '/my-thing', + ]); + + $this->referenceStorePool->getStore('other')->willThrow(ReferenceStoreNotExistsException::class); + + $result = $this->teaserSerializer->serialize($teaser->reveal(), $locale, $context->reveal()); + + $this->assertSame([ + 'id' => 'bb03b2f1-135f-4fcf-b27a-b2cf5f36be66', + 'type' => 'other', + 'locale' => 'en', + 'title' => 'My thing', + 'description' => '

hello world.

', + 'moreText' => 'foo', + 'url' => '/my-thing', + 'media' => null, + ], $result); + } +}