From 7a220deec823cc36d28012f8b9b34835608e4738 Mon Sep 17 00:00:00 2001 From: bwaidelich Date: Sun, 12 Nov 2023 11:52:22 +0100 Subject: [PATCH 1/3] WIP: FEATURE: Site configuration presets Resolves: #4582 --- Neos.Neos/Classes/Domain/Model/Site.php | 24 +++++++++++++-- Neos.Neos/Configuration/Settings.Sites.yaml | 18 +++++++++++ Neos.Neos/Configuration/Settings.yaml | 16 ---------- .../Migrations/Code/Version20230801154834.php | 4 +-- .../Features/FrontendRouting/Basic.feature | 5 ++-- .../FrontendRouting/Dimensions.feature | 30 +++++++++++-------- .../FrontendRouting/DisableNodes.feature | 5 ++-- .../FrontendRouting/MultiSiteLinking.feature | 11 +++++-- .../FrontendRouting/RouteCache.feature | 5 ++-- .../FrontendRouting/Shortcuts.feature | 5 ++-- .../TetheredSiteChildDocuments.feature | 5 ++-- .../Features/Fusion/ContentCase.feature | 5 ++-- .../Features/Fusion/ContentCollection.feature | 5 ++-- .../Features/Fusion/ConvertUris.feature | 5 ++-- .../Behavior/Features/Fusion/Menu.feature | 5 ++-- 15 files changed, 95 insertions(+), 53 deletions(-) create mode 100755 Neos.Neos/Configuration/Settings.Sites.yaml diff --git a/Neos.Neos/Classes/Domain/Model/Site.php b/Neos.Neos/Classes/Domain/Model/Site.php index 1d15d90a342..7ca8eca6efd 100644 --- a/Neos.Neos/Classes/Domain/Model/Site.php +++ b/Neos.Neos/Classes/Domain/Model/Site.php @@ -17,8 +17,10 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Neos\ContentRepositoryRegistry\Exception\InvalidConfigurationException; use Neos\Flow\Annotations as Flow; use Neos\Media\Domain\Model\AssetCollection; +use Neos\Utility\Arrays; /** * Domain model of a site @@ -35,12 +37,19 @@ class Site public const STATE_OFFLINE = 2; /** - * @Flow\InjectConfiguration(path="sites") * @var array * @phpstan-var array> */ + #[Flow\InjectConfiguration(path: 'sites')] protected $sitesConfiguration = []; + /** + * @var array + * @phpstan-var array> + */ + #[Flow\InjectConfiguration(path: 'sitePresets')] + protected $sitePresetsConfiguration = []; + /** * Name of the site * @@ -372,7 +381,16 @@ public function emitSiteChanged() public function getConfiguration(): SiteConfiguration { - // we DO NOT want recursive merge here - return SiteConfiguration::fromArray($this->sitesConfiguration[$this->nodeName] ?? $this->sitesConfiguration['*']); + $siteSettingsPath = array_key_exists($this->nodeName, $this->sitesConfiguration) ? $this->nodeName : '*'; + $siteSettings = $this->sitesConfiguration[$siteSettingsPath]; + if (isset($siteSettings['preset'])) { + is_string($siteSettings['preset']) || throw new \RuntimeException(sprintf('Invalid "preset" configuration for "Neos.Neos.sites.%s". Expected string, got: %s', $siteSettingsPath, get_debug_type($siteSettings['preset'])), 1699785648); + if (!isset($this->sitePresetsConfiguration[$siteSettings['preset']]) || !is_array($this->sitePresetsConfiguration[$siteSettings['preset']])) { + throw new \RuntimeException(sprintf('Site settings "Neos.Neos.sites.%s" refer to a preset "%s", but no corresponding preset is configured', $siteSettingsPath, $siteSettings['preset']), 1699785736); + } + $siteSettings = Arrays::arrayMergeRecursiveOverrule($this->sitePresetsConfiguration[$siteSettings['preset']], $siteSettings); + unset($siteSettings['preset']); + } + return SiteConfiguration::fromArray($siteSettings); } } diff --git a/Neos.Neos/Configuration/Settings.Sites.yaml b/Neos.Neos/Configuration/Settings.Sites.yaml new file mode 100755 index 00000000000..3c62589e72e --- /dev/null +++ b/Neos.Neos/Configuration/Settings.Sites.yaml @@ -0,0 +1,18 @@ +# # +# Site specific settings # +# # +# This file contains settings specific to Neos Sites # + +Neos: + + Neos: + sitePresets: + 'default': + uriPathSuffix: '.html' + contentRepository: default + contentDimensions: + resolver: + factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\AutoUriPathResolverFactory + sites: + '*': + preset: 'default' diff --git a/Neos.Neos/Configuration/Settings.yaml b/Neos.Neos/Configuration/Settings.yaml index 4f45714082b..6580ceda555 100755 --- a/Neos.Neos/Configuration/Settings.yaml +++ b/Neos.Neos/Configuration/Settings.yaml @@ -11,9 +11,6 @@ Neos: Neos: - contentDimensions: - resolution: - uriPathSegmentDelimiter: '_' fusion: # if set to true, Fusion is cached on a per-site basis. @@ -54,19 +51,6 @@ Neos: More information and contribution opportunities at https://www.neos.io --> - routing: - # Setting this to true allows to use an empty uriSegment for default dimensions. - # The only limitation is that all segments must be unique across all dimenions. - supportEmptySegmentForDimensions: true - - sites: - '*': - uriPathSuffix: '.html' - contentRepository: default - contentDimensions: - resolver: - factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\AutoUriPathResolverFactory - nodeTypes: groups: general: diff --git a/Neos.Neos/Migrations/Code/Version20230801154834.php b/Neos.Neos/Migrations/Code/Version20230801154834.php index 68118a7648c..f31c5610840 100644 --- a/Neos.Neos/Migrations/Code/Version20230801154834.php +++ b/Neos.Neos/Migrations/Code/Version20230801154834.php @@ -4,7 +4,7 @@ /** - * Replace defaultUriSuffix configuration with uriPathSuffix in default site configuration + * Replace defaultUriSuffix configuration with uriPathSuffix in default site preset configuration */ class Version20230801154834 extends AbstractMigration { @@ -16,6 +16,6 @@ public function getIdentifier(): string public function up(): void { - $this->moveSettingsPaths(['Neos', 'Flow', 'mvc', 'routes', 'Neos.Neos', 'variables', 'defaultUriSuffix'], ['Neos', 'Neos', 'sites', '*', 'uriPathSuffix']); + $this->moveSettingsPaths(['Neos', 'Flow', 'mvc', 'routes', 'Neos.Neos', 'variables', 'defaultUriSuffix'], ['Neos', 'Neos', 'sitePresets', 'default', 'uriPathSuffix']); } } diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Basic.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Basic.feature index da5635f69db..a2c65cacb27 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Basic.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Basic.feature @@ -59,8 +59,9 @@ Feature: Basic routing functionality (match & resolve document nodes in one dime Neos: Neos: sites: - '*': - contentRepository: default + 'node1': + preset: 'default' + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Dimensions.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Dimensions.feature index c6a9da1b7bf..a0ff8031f22 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Dimensions.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Dimensions.feature @@ -74,8 +74,9 @@ Feature: Routing functionality with multiple content dimensions Neos: Neos: sites: - '*': - contentRepository: default + 'node1': + preset: default + uriPathSuffix: '' contentDimensions: defaultDimensionSpacePoint: market: DE @@ -114,8 +115,9 @@ Feature: Routing functionality with multiple content dimensions Neos: Neos: sites: - '*': - contentRepository: default + 'node1': + preset: default + uriPathSuffix: '' contentDimensions: defaultDimensionSpacePoint: market: DE @@ -173,8 +175,9 @@ Feature: Routing functionality with multiple content dimensions Neos: Neos: sites: - '*': - contentRepository: default + 'node1': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\UriPathResolverFactory @@ -242,8 +245,9 @@ Feature: Routing functionality with multiple content dimensions Neos: Neos: sites: - '*': - contentRepository: default + 'node1': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\UriPathResolverFactory @@ -309,8 +313,9 @@ Feature: Routing functionality with multiple content dimensions Neos: Neos: sites: - '*': - contentRepository: default + 'node1': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\UriPathResolverFactory @@ -373,8 +378,9 @@ Feature: Routing functionality with multiple content dimensions Neos: Neos: sites: - '*': - contentRepository: default + 'node1': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\UriPathResolverFactory diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/DisableNodes.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/DisableNodes.feature index 8912929e8f3..67900f786df 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/DisableNodes.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/DisableNodes.feature @@ -60,8 +60,9 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes Neos: Neos: sites: - '*': - contentRepository: default + 'node1': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/MultiSiteLinking.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/MultiSiteLinking.feature index 33b0b36b404..e221ad3e615 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/MultiSiteLinking.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/MultiSiteLinking.feature @@ -66,8 +66,15 @@ Feature: Linking between multiple websites Neos: Neos: sites: - '*': - contentRepository: default + 'site-1': + preset: default + uriPathSuffix: '' + contentDimensions: + resolver: + factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory + 'site-2': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/RouteCache.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/RouteCache.feature index 4a5df7fc03d..9d905eb6e89 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/RouteCache.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/RouteCache.feature @@ -58,8 +58,9 @@ Feature: Route cache invalidation Neos: Neos: sites: - '*': - contentRepository: default + 'node1': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Shortcuts.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Shortcuts.feature index 3bba3d61557..e05f925bf78 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Shortcuts.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Shortcuts.feature @@ -88,8 +88,9 @@ Feature: Routing behavior of shortcut nodes Neos: Neos: sites: - '*': - contentRepository: default + 'node1': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/TetheredSiteChildDocuments.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/TetheredSiteChildDocuments.feature index 5b644025b96..1c8045f71e3 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/TetheredSiteChildDocuments.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/TetheredSiteChildDocuments.feature @@ -47,8 +47,9 @@ Feature: Tests for site node child documents. These are special in that they hav Neos: Neos: sites: - '*': - contentRepository: default + 'site': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCase.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCase.feature index 3c18ebada65..cd07163192b 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCase.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCase.feature @@ -50,8 +50,9 @@ Feature: Tests for the "Neos.Neos:ContentCase" Fusion prototype Neos: Neos: sites: - '*': - contentRepository: default + 'a': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature index c834e9cb06e..2682199fdf5 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature @@ -57,8 +57,9 @@ Feature: Tests for the "Neos.Neos:ContentCollection" Fusion prototype Neos: Neos: sites: - '*': - contentRepository: default + 'a': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/ConvertUris.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/ConvertUris.feature index f9b0575cabe..8b25a1f88eb 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/ConvertUris.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/ConvertUris.feature @@ -47,8 +47,9 @@ Feature: Tests for the "Neos.Neos:ConvertUris" Fusion prototype Neos: Neos: sites: - '*': - contentRepository: default + 'a': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/Menu.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/Menu.feature index 9d94f027ac5..c552bdea7c5 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/Menu.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/Menu.feature @@ -72,8 +72,9 @@ Feature: Tests for the "Neos.Neos:Menu" and related Fusion prototypes Neos: Neos: sites: - '*': - contentRepository: default + 'a': + preset: default + uriPathSuffix: '' contentDimensions: resolver: factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory From 53a0d132722c51ef600e97bfc256b408856640d8 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Sat, 13 Jan 2024 18:14:46 +0100 Subject: [PATCH 2/3] TASK make phpstan happy --- Neos.Neos/Classes/Domain/Model/Site.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Neos.Neos/Classes/Domain/Model/Site.php b/Neos.Neos/Classes/Domain/Model/Site.php index 7ca8eca6efd..b1d1fac85fd 100644 --- a/Neos.Neos/Classes/Domain/Model/Site.php +++ b/Neos.Neos/Classes/Domain/Model/Site.php @@ -17,7 +17,6 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -use Neos\ContentRepositoryRegistry\Exception\InvalidConfigurationException; use Neos\Flow\Annotations as Flow; use Neos\Media\Domain\Model\AssetCollection; use Neos\Utility\Arrays; @@ -45,7 +44,7 @@ class Site /** * @var array - * @phpstan-var array> + * @phpstan-var array */ #[Flow\InjectConfiguration(path: 'sitePresets')] protected $sitePresetsConfiguration = []; From 1909e8cb738ef24b1dfe961e59fa96391d06fb2e Mon Sep 17 00:00:00 2001 From: Bastian Waidelich Date: Sat, 27 Apr 2024 18:04:27 +0200 Subject: [PATCH 3/3] Tweak `Site::getConfiguration()` and add tests --- Neos.Neos/Classes/Domain/Model/Site.php | 13 ++++- .../Tests/Unit/Domain/Model/SiteTest.php | 48 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/Neos.Neos/Classes/Domain/Model/Site.php b/Neos.Neos/Classes/Domain/Model/Site.php index b1d1fac85fd..15c278beaa9 100644 --- a/Neos.Neos/Classes/Domain/Model/Site.php +++ b/Neos.Neos/Classes/Domain/Model/Site.php @@ -380,10 +380,19 @@ public function emitSiteChanged() public function getConfiguration(): SiteConfiguration { - $siteSettingsPath = array_key_exists($this->nodeName, $this->sitesConfiguration) ? $this->nodeName : '*'; + if (array_key_exists($this->nodeName, $this->sitesConfiguration)) { + $siteSettingsPath = $this->nodeName; + } else { + if (!array_key_exists('*', $this->sitesConfiguration)) { + throw new \RuntimeException(sprintf('Missing configuration for "Neos.Neos.sites.%s" or fallback "Neos.Neos.sites.*"', $this->nodeName), 1714230658); + } + $siteSettingsPath = '*'; + } $siteSettings = $this->sitesConfiguration[$siteSettingsPath]; if (isset($siteSettings['preset'])) { - is_string($siteSettings['preset']) || throw new \RuntimeException(sprintf('Invalid "preset" configuration for "Neos.Neos.sites.%s". Expected string, got: %s', $siteSettingsPath, get_debug_type($siteSettings['preset'])), 1699785648); + if (!is_string($siteSettings['preset'])) { + throw new \RuntimeException(sprintf('Invalid "preset" configuration for "Neos.Neos.sites.%s". Expected string, got: %s', $siteSettingsPath, get_debug_type($siteSettings['preset'])), 1699785648); + } if (!isset($this->sitePresetsConfiguration[$siteSettings['preset']]) || !is_array($this->sitePresetsConfiguration[$siteSettings['preset']])) { throw new \RuntimeException(sprintf('Site settings "Neos.Neos.sites.%s" refer to a preset "%s", but no corresponding preset is configured', $siteSettingsPath, $siteSettings['preset']), 1699785736); } diff --git a/Neos.Neos/Tests/Unit/Domain/Model/SiteTest.php b/Neos.Neos/Tests/Unit/Domain/Model/SiteTest.php index b7054ba7a3e..70de94487e1 100644 --- a/Neos.Neos/Tests/Unit/Domain/Model/SiteTest.php +++ b/Neos.Neos/Tests/Unit/Domain/Model/SiteTest.php @@ -12,6 +12,7 @@ */ use Neos\Flow\Tests\UnitTestCase; use Neos\Neos\Domain\Model\Site; +use Neos\Utility\ObjectAccess; /** * Testcase for the "Site" domain model @@ -57,4 +58,51 @@ public function theSiteResourcesPackageKeyCanBeSetAndRetrieved() $site->setSiteResourcesPackageKey('Foo'); self::assertSame('Foo', $site->getSiteResourcesPackageKey()); } + + public static function getConfigurationFailingDataProvider(): iterable + { + yield 'no matching nor default site config' => ['nodeTypeName' => 'siteNodeName', 'sitesConfiguration' => [], 'sitePresetConfiguration' => [], 'expectedExceptionMessage' => 'Missing configuration for "Neos.Neos.sites.siteNodeName" or fallback "Neos.Neos.sites.*"']; + yield 'referring non-string preset' => ['nodeTypeName' => 'siteNodeName', 'sitesConfiguration' => ['siteNodeName' => ['preset' => false]], 'sitePresetConfiguration' => [], 'expectedExceptionMessage' => 'Invalid "preset" configuration for "Neos.Neos.sites.siteNodeName". Expected string, got: bool']; + yield 'referring non-existing preset' => ['nodeTypeName' => 'siteNodeName', 'sitesConfiguration' => ['siteNodeName' => ['preset' => 'nonExistingPreset']], 'sitePresetConfiguration' => [], 'expectedExceptionMessage' => 'Site settings "Neos.Neos.sites.siteNodeName" refer to a preset "nonExistingPreset"']; + yield 'missing content repository identifier' => ['nodeTypeName' => 'siteNodeName', 'sitesConfiguration' => ['siteNodeName' => []], 'sitePresetConfiguration' => [], 'expectedExceptionMessage' => 'There is no content repository identifier configured in Sites configuration in Settings.yaml: Neos.Neos.sites.*.contentRepository']; + yield 'missing content dimension resolver factory' => ['nodeTypeName' => 'siteNodeName', 'sitesConfiguration' => ['siteNodeName' => ['contentRepository' => 'default']], 'sitePresetConfiguration' => [], 'expectedExceptionMessage' => 'No Dimension Resolver Factory configured at Neos.Neos.sites.*.contentDimensions.resolver.factoryClassName']; + } + + /** + * @test + * @dataProvider getConfigurationFailingDataProvider + */ + public function getConfigurationFailingTests(string $nodeTypeName, array $sitesConfiguration, array $sitePresetsConfiguration, string $expectedExceptionMessage): void + { + $site = new Site($nodeTypeName); + ObjectAccess::setProperty($site, 'sitesConfiguration', $sitesConfiguration, true); + ObjectAccess::setProperty($site, 'sitePresetsConfiguration', $sitePresetsConfiguration, true); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage($expectedExceptionMessage); + $site->getConfiguration(); + } + + public static function getConfigurationSucceedingDataProvider(): iterable + { + yield 'minimal configuration' => ['nodeTypeName' => 'siteNodeName', 'sitesConfiguration' => ['siteNodeName' => ['contentRepository' => 'default', 'contentDimensions' => ['resolver' => ['factoryClassName' => 'Foo']]]], 'sitePresetConfiguration' => [], 'expectedConfiguration' => ['contentRepositoryId' => 'default', 'contentDimensionResolverFactoryClassName' => 'Foo', 'contentDimensionResolverOptions' => [], 'defaultDimensionSpacePoint' => [], 'uriPathSuffix' => '']]; + yield 'full configuration' => ['nodeTypeName' => 'siteNodeName', 'sitesConfiguration' => ['siteNodeName' => ['contentRepository' => 'custom_repo', 'contentDimensions' => ['resolver' => ['factoryClassName' => 'Bar', 'options' => ['some' => 'options']], 'defaultDimensionSpacePoint' => ['language' => 'de']], 'uriPathSuffix' => 'some-suffix']], 'sitePresetConfiguration' => [], 'expectedConfiguration' => ['contentRepositoryId' => 'custom_repo', 'contentDimensionResolverFactoryClassName' => 'Bar', 'contentDimensionResolverOptions' => ['some' => 'options'], 'defaultDimensionSpacePoint' => ['language' => 'de'], 'uriPathSuffix' => 'some-suffix']]; + yield 'full configuration from fallback' => ['nodeTypeName' => 'siteNodeName', 'sitesConfiguration' => ['*' => ['contentRepository' => 'custom_repo', 'contentDimensions' => ['resolver' => ['factoryClassName' => 'Bar', 'options' => ['some' => 'options']], 'defaultDimensionSpacePoint' => ['language' => 'de']], 'uriPathSuffix' => 'some-suffix']], 'sitePresetConfiguration' => [], 'expectedConfiguration' => ['contentRepositoryId' => 'custom_repo', 'contentDimensionResolverFactoryClassName' => 'Bar', 'contentDimensionResolverOptions' => ['some' => 'options'], 'defaultDimensionSpacePoint' => ['language' => 'de'], 'uriPathSuffix' => 'some-suffix']]; + yield 'full configuration merged with preset' => ['nodeTypeName' => 'siteNodeName', 'sitesConfiguration' => ['siteNodeName' => ['preset' => 'somePreset', 'contentDimensions' => ['defaultDimensionSpacePoint' => ['country' => 'DE']], 'uriPathSuffix' => 'some-overridden-suffix']], 'sitePresetConfiguration' => ['somePreset' => ['contentRepository' => 'custom_repo', 'contentDimensions' => ['resolver' => ['factoryClassName' => 'Bar', 'options' => ['some' => 'options']], 'defaultDimensionSpacePoint' => ['language' => 'de']], 'uriPathSuffix' => 'some-default-suffix']], 'expectedConfiguration' => ['contentRepositoryId' => 'custom_repo', 'contentDimensionResolverFactoryClassName' => 'Bar', 'contentDimensionResolverOptions' => ['some' => 'options'], 'defaultDimensionSpacePoint' => ['language' => 'de', 'country' => 'DE'], 'uriPathSuffix' => 'some-overridden-suffix']]; + yield 'full configuration from fallback merged with preset' => ['nodeTypeName' => 'siteNodeName', 'sitesConfiguration' => ['*' => ['preset' => 'somePreset', 'contentDimensions' => ['defaultDimensionSpacePoint' => ['country' => 'DE']], 'uriPathSuffix' => 'some-overridden-suffix']], 'sitePresetConfiguration' => ['somePreset' => ['contentRepository' => 'custom_repo', 'contentDimensions' => ['resolver' => ['factoryClassName' => 'Bar', 'options' => ['some' => 'options']], 'defaultDimensionSpacePoint' => ['language' => 'de']], 'uriPathSuffix' => 'some-default-suffix']], 'expectedConfiguration' => ['contentRepositoryId' => 'custom_repo', 'contentDimensionResolverFactoryClassName' => 'Bar', 'contentDimensionResolverOptions' => ['some' => 'options'], 'defaultDimensionSpacePoint' => ['language' => 'de', 'country' => 'DE'], 'uriPathSuffix' => 'some-overridden-suffix']]; + } + + /** + * @test + * @dataProvider getConfigurationSucceedingDataProvider + */ + public function getConfigurationSucceedingTests(string $nodeTypeName, array $sitesConfiguration, array $sitePresetsConfiguration, array $expectedConfiguration): void + { + $site = new Site($nodeTypeName); + ObjectAccess::setProperty($site, 'sitesConfiguration', $sitesConfiguration, true); + ObjectAccess::setProperty($site, 'sitePresetsConfiguration', $sitePresetsConfiguration, true); + + $configuration = $site->getConfiguration(); + self::assertSame($expectedConfiguration, json_decode(json_encode($configuration), true)); + } }