diff --git a/Content/ContentTypeResolver/SnippetSelectionResolver.php b/Content/ContentTypeResolver/SnippetSelectionResolver.php new file mode 100644 index 0000000..c2b3824 --- /dev/null +++ b/Content/ContentTypeResolver/SnippetSelectionResolver.php @@ -0,0 +1,114 @@ +contentMapper = $contentMapper; + $this->structureResolver = $structureResolver; + $this->defaultSnippetManager = $defaultSnippetManager; + } + + public static function getContentType(): string + { + return 'snippet_selection'; + } + + /** + * {@inheritdoc} + */ + public function resolve($data, PropertyInterface $property, string $locale, array $attributes = []): ContentView + { + /** @var StructureBridge $structure */ + $structure = $property->getStructure(); + $webspaceKey = $structure->getWebspaceKey(); + $shadowLocale = $structure->getIsShadow() ? $structure->getShadowBaseLanguage() : null; + + $params = $property->getParams(); + /** @var bool $loadExcerpt */ + $loadExcerpt = isset($params['loadExcerpt']) ? $params['loadExcerpt']->getValue() : false; + /** @var string $defaultArea */ + $defaultArea = isset($params['default']) ? $params['default']->getValue() : null; + + $snippetIds = $data ?? []; + if (empty($snippetIds) && $defaultArea) { + $defaultSnippetId = $this->getDefaultSnippetId($webspaceKey, $defaultArea, $locale); + $snippetIds = $defaultSnippetId ? [$defaultSnippetId] : []; + } + + $snippets = []; + foreach ($snippetIds as $snippetId) { + /** @var SnippetBridge $snippet */ + $snippet = $this->contentMapper->load($snippetId, $webspaceKey, $locale); + + if (!$snippet->getHasTranslation() && null !== $shadowLocale) { + /** @var SnippetBridge $snippet */ + $snippet = $this->contentMapper->load($snippetId, $webspaceKey, $shadowLocale); + } + + $snippet->setIsShadow(null !== $shadowLocale); + $snippet->setShadowBaseLanguage($shadowLocale); + + $snippets[] = $this->structureResolver->resolve($snippet, $locale, $loadExcerpt); + } + + return new ContentView($snippets, $data ?? []); + } + + private function getDefaultSnippetId(string $webspaceKey, string $snippetArea, string $locale): ?string + { + try { + /** @var SnippetDocument|null $snippet */ + $snippet = $this->defaultSnippetManager->load($webspaceKey, $snippetArea, $locale); + } catch (WrongSnippetTypeException $exception) { + return null; + } + + if (!$snippet) { + return null; + } + + return $snippet->getUuid(); + } +} diff --git a/Content/StructureResolver.php b/Content/StructureResolver.php index ad09de6..645d999 100644 --- a/Content/StructureResolver.php +++ b/Content/StructureResolver.php @@ -51,14 +51,20 @@ public function __construct( /** * @param StructureBridge $structure */ - public function resolve(StructureInterface $structure, string $locale): array - { + public function resolve( + StructureInterface $structure, + string $locale, + bool $includeExtension = true + ): array { $data = $this->getStructureData($structure); - $data['extension'] = $this->resolveExtensionData( - $this->getExtensionData($structure), - $locale, - ['webspaceKey' => $structure->getWebspaceKey()] - ); + + if ($includeExtension) { + $data['extension'] = $this->resolveExtensionData( + $this->getExtensionData($structure), + $locale, + ['webspaceKey' => $structure->getWebspaceKey()] + ); + } foreach ($structure->getProperties(true) as $property) { $contentView = $this->contentResolver->resolve( diff --git a/Content/StructureResolverInterface.php b/Content/StructureResolverInterface.php index 6c487c9..38b6de7 100644 --- a/Content/StructureResolverInterface.php +++ b/Content/StructureResolverInterface.php @@ -20,7 +20,11 @@ interface StructureResolverInterface /** * @return mixed[] */ - public function resolve(StructureInterface $structure, string $locale): array; + public function resolve( + StructureInterface $structure, + string $locale, + bool $includeExtension = true + ): array; /** * @param string[] $propertyMap diff --git a/Resources/config/content-type-resolvers.xml b/Resources/config/content-type-resolvers.xml index 2edb108..56402e2 100644 --- a/Resources/config/content-type-resolvers.xml +++ b/Resources/config/content-type-resolvers.xml @@ -24,6 +24,18 @@ + + + + + + + + contentMapper = $this->prophesize(ContentMapperInterface::class); + $this->structureResolver = $this->prophesize(StructureResolverInterface::class); + $this->defaultSnippetManager = $this->prophesize(DefaultSnippetManagerInterface::class); + + $this->snippetSelectionResolver = new SnippetSelectionResolver( + $this->contentMapper->reveal(), + $this->structureResolver->reveal(), + $this->defaultSnippetManager->reveal() + ); + } + + public function testGetContentType(): void + { + self::assertSame('snippet_selection', $this->snippetSelectionResolver::getContentType()); + } + + public function testResolve(): void + { + $structure = $this->prophesize(StructureBridge::class); + $structure->getWebspaceKey()->willReturn('webspace-key'); + $structure->getIsShadow()->willReturn(false); + + $property = $this->prophesize(PropertyInterface::class); + $property->getStructure()->willReturn($structure->reveal()); + $property->getParams()->willReturn([]); + + $snippet1 = $this->prophesize(SnippetBridge::class); + $snippet1->getHasTranslation()->willReturn(true); + $snippet1->setIsShadow(false)->shouldBeCalled(); + $snippet1->setShadowBaseLanguage(null)->shouldBeCalled(); + + $this->contentMapper->load('snippet-1', 'webspace-key', 'en')->willReturn($snippet1->reveal()); + $this->structureResolver->resolve($snippet1->reveal(), 'en', false)->willReturn([ + 'id' => 'snippet-1', + 'template' => 'test', + 'content' => [], + 'view' => [], + ]); + + $snippet2 = $this->prophesize(SnippetBridge::class); + $snippet2->getHasTranslation()->willReturn(false); + $snippet2->setIsShadow(false)->shouldBeCalled(); + $snippet2->setShadowBaseLanguage(null)->shouldBeCalled(); + + $this->contentMapper->load('snippet-2', 'webspace-key', 'en')->willReturn($snippet2->reveal()); + $this->structureResolver->resolve($snippet2->reveal(), 'en', false)->willReturn([ + 'id' => 'snippet-2', + 'template' => 'test', + 'content' => [], + 'view' => [], + ]); + + $result = $this->snippetSelectionResolver->resolve(['snippet-1', 'snippet-2'], $property->reveal(), 'en', []); + $this->assertInstanceOf(ContentView::class, $result); + $this->assertSame( + [ + [ + 'id' => 'snippet-1', + 'template' => 'test', + 'content' => [], + 'view' => [], + ], + [ + 'id' => 'snippet-2', + 'template' => 'test', + 'content' => [], + 'view' => [], + ], + ], + $result->getContent() + ); + + $this->assertSame( + ['snippet-1', 'snippet-2'], + $result->getView() + ); + } + + public function testResolveWithExcerpt(): void + { + $structure = $this->prophesize(StructureBridge::class); + $structure->getWebspaceKey()->willReturn('webspace-key'); + $structure->getIsShadow()->willReturn(false); + + $property = $this->prophesize(PropertyInterface::class); + $property->getStructure()->willReturn($structure->reveal()); + $property->getParams()->willReturn([ + 'loadExcerpt' => new PropertyParameter('loadExcerpt', true), + ]); + + $snippet1 = $this->prophesize(SnippetBridge::class); + $snippet1->getHasTranslation()->willReturn(true); + $snippet1->setIsShadow(false)->shouldBeCalled(); + $snippet1->setShadowBaseLanguage(null)->shouldBeCalled(); + + $this->contentMapper->load('snippet-1', 'webspace-key', 'en')->willReturn($snippet1->reveal()); + $this->structureResolver->resolve($snippet1->reveal(), 'en', true)->willReturn([ + 'id' => 'snippet-1', + 'template' => 'test', + 'content' => [], + 'view' => [], + ]); + + $result = $this->snippetSelectionResolver->resolve(['snippet-1'], $property->reveal(), 'en', []); + $this->assertInstanceOf(ContentView::class, $result); + $this->assertSame( + [ + [ + 'id' => 'snippet-1', + 'template' => 'test', + 'content' => [], + 'view' => [], + ], + ], + $result->getContent() + ); + + $this->assertSame( + ['snippet-1'], + $result->getView() + ); + } + + public function testResolveShadowLocale(): void + { + $structure = $this->prophesize(StructureBridge::class); + $structure->getWebspaceKey()->willReturn('webspace-key'); + $structure->getIsShadow()->willReturn(true); + $structure->getShadowBaseLanguage()->willReturn('de'); + + $property = $this->prophesize(PropertyInterface::class); + $property->getStructure()->willReturn($structure->reveal()); + $property->getParams()->willReturn([]); + + $snippet1 = $this->prophesize(SnippetBridge::class); + $snippet1->getHasTranslation()->willReturn(true); + $snippet1->setIsShadow(true)->shouldBeCalled(); + $snippet1->setShadowBaseLanguage('de')->shouldBeCalled(); + + $this->contentMapper->load('snippet-1', 'webspace-key', 'en')->willReturn($snippet1->reveal()); + $this->structureResolver->resolve($snippet1->reveal(), 'en', false)->willReturn([ + 'id' => 'snippet-1', + 'template' => 'test', + 'content' => [], + 'view' => [], + ]); + + $result = $this->snippetSelectionResolver->resolve(['snippet-1'], $property->reveal(), 'en', []); + $this->assertInstanceOf(ContentView::class, $result); + $this->assertSame( + [ + [ + 'id' => 'snippet-1', + 'template' => 'test', + 'content' => [], + 'view' => [], + ], + ], + $result->getContent() + ); + + $this->assertSame( + ['snippet-1'], + $result->getView() + ); + } + + public function testResolveShadowLocaleNoTranslation(): void + { + $structure = $this->prophesize(StructureBridge::class); + $structure->getWebspaceKey()->willReturn('webspace-key'); + $structure->getIsShadow()->willReturn(true); + $structure->getShadowBaseLanguage()->willReturn('de'); + + $property = $this->prophesize(PropertyInterface::class); + $property->getStructure()->willReturn($structure->reveal()); + $property->getParams()->willReturn([]); + + $snippet1en = $this->prophesize(SnippetBridge::class); + $snippet1en->getHasTranslation()->willReturn(false); + + $snippet1de = $this->prophesize(SnippetBridge::class); + $snippet1de->setIsShadow(true)->shouldBeCalled(); + $snippet1de->setShadowBaseLanguage('de')->shouldBeCalled(); + + $this->contentMapper->load('snippet-1', 'webspace-key', 'en')->willReturn($snippet1en->reveal()); + $this->contentMapper->load('snippet-1', 'webspace-key', 'de')->willReturn($snippet1de->reveal()); + $this->structureResolver->resolve($snippet1de->reveal(), 'en', false)->willReturn([ + 'id' => 'snippet-1', + 'template' => 'test', + 'content' => [], + 'view' => [], + ]); + + $result = $this->snippetSelectionResolver->resolve(['snippet-1'], $property->reveal(), 'en', []); + $this->assertInstanceOf(ContentView::class, $result); + $this->assertSame( + [ + [ + 'id' => 'snippet-1', + 'template' => 'test', + 'content' => [], + 'view' => [], + ], + ], + $result->getContent() + ); + + $this->assertSame( + ['snippet-1'], + $result->getView() + ); + } + + public function testResolveDataIsNull(): void + { + $structure = $this->prophesize(StructureBridge::class); + $structure->getWebspaceKey()->willReturn('webspace-key'); + $structure->getIsShadow()->willReturn(false); + + $property = $this->prophesize(PropertyInterface::class); + $property->getStructure()->willReturn($structure->reveal()); + $property->getParams()->willReturn([]); + + $result = $this->snippetSelectionResolver->resolve(null, $property->reveal(), 'en', []); + $this->assertInstanceOf(ContentView::class, $result); + $this->assertSame( + [], + $result->getContent() + ); + + $this->assertSame( + [], + $result->getView() + ); + } + + public function testResolveDataIsNullWithDefaultArea(): void + { + $structure = $this->prophesize(StructureBridge::class); + $structure->getWebspaceKey()->willReturn('webspace-key'); + $structure->getIsShadow()->willReturn(false); + + $property = $this->prophesize(PropertyInterface::class); + $property->getStructure()->willReturn($structure->reveal()); + $property->getParams()->willReturn([ + 'default' => new PropertyParameter('default', 'test-snippet-area'), + ]); + + $defaultSnippetDocument = $this->prophesize(SnippetDocument::class); + $defaultSnippetDocument->getUuid()->willReturn('default-snippet-1'); + $this->defaultSnippetManager->load('webspace-key', 'test-snippet-area', 'en') + ->willReturn($defaultSnippetDocument->reveal()); + + $defaultSnippet = $this->prophesize(SnippetBridge::class); + $defaultSnippet->getHasTranslation()->willReturn(true); + $defaultSnippet->setIsShadow(false)->shouldBeCalled(); + $defaultSnippet->setShadowBaseLanguage(null)->shouldBeCalled(); + + $this->contentMapper->load('default-snippet-1', 'webspace-key', 'en')->willReturn($defaultSnippet->reveal()); + $this->structureResolver->resolve($defaultSnippet->reveal(), 'en', false)->willReturn([ + 'id' => 'default-snippet-1', + 'template' => 'test', + 'content' => [], + 'view' => [], + ]); + + $result = $this->snippetSelectionResolver->resolve(null, $property->reveal(), 'en', []); + $this->assertInstanceOf(ContentView::class, $result); + $this->assertSame( + [ + [ + 'id' => 'default-snippet-1', + 'template' => 'test', + 'content' => [], + 'view' => [], + ], + ], + $result->getContent() + ); + + $this->assertSame( + [], + $result->getView() + ); + } +}