diff --git a/Content/Application/ContentDataMapper/DataMapper/RoutableDataMapper.php b/Content/Application/ContentDataMapper/DataMapper/RoutableDataMapper.php index 2b8f262a..fc656d20 100644 --- a/Content/Application/ContentDataMapper/DataMapper/RoutableDataMapper.php +++ b/Content/Application/ContentDataMapper/DataMapper/RoutableDataMapper.php @@ -16,7 +16,9 @@ use Sulu\Bundle\ContentBundle\Content\Domain\Model\DimensionContentInterface; use Sulu\Bundle\ContentBundle\Content\Domain\Model\RoutableInterface; use Sulu\Bundle\ContentBundle\Content\Domain\Model\TemplateInterface; +use Sulu\Bundle\RouteBundle\Entity\Route; use Sulu\Bundle\RouteBundle\Generator\RouteGeneratorInterface; +use Sulu\Bundle\RouteBundle\Manager\ConflictResolverInterface; use Sulu\Bundle\RouteBundle\Manager\RouteManagerInterface; use Sulu\Component\Content\Metadata\Factory\StructureMetadataFactoryInterface; use Sulu\Component\Content\Metadata\PropertyMetadata; @@ -40,9 +42,9 @@ class RoutableDataMapper implements DataMapperInterface private $routeManager; /** - * @var array + * @var ConflictResolverInterface */ - private $structureDefaultTypes; + private $conflictResolver; /** * @var array> @@ -50,20 +52,19 @@ class RoutableDataMapper implements DataMapperInterface private $routeMappings; /** - * @param array $structureDefaultTypes * @param array> $routeMappings */ public function __construct( StructureMetadataFactoryInterface $factory, RouteGeneratorInterface $routeGenerator, RouteManagerInterface $routeManager, - array $structureDefaultTypes, + ConflictResolverInterface $conflictResolver, array $routeMappings ) { $this->factory = $factory; $this->routeGenerator = $routeGenerator; $this->routeManager = $routeManager; - $this->structureDefaultTypes = $structureDefaultTypes; + $this->conflictResolver = $conflictResolver; $this->routeMappings = $routeMappings; } @@ -80,21 +81,13 @@ public function map( throw new \RuntimeException('LocalizedDimensionContent needs to extend the TemplateInterface.'); } - if (DimensionContentInterface::STAGE_LIVE !== $localizedDimensionContent->getStage()) { - // return; - } - $type = $localizedDimensionContent::getTemplateType(); /** @var string|null $template */ - $template = $data['template'] ?? null; - - if (null === $template) { - $template = $this->structureDefaultTypes[$type] ?? null; - } + $template = $localizedDimensionContent->getTemplateKey() ?? null; if (null === $template) { - throw new \RuntimeException('Expected "template" to be set in the data array.'); + throw new \RuntimeException('LocalizedDimensionContent should return the a template.'); } $metadata = $this->factory->getStructureMetadata($type, $template); @@ -171,10 +164,19 @@ public function map( (string) $localizedDimensionContent->getResourceId(), $locale, $routePath, - true + false ); $routePath = $route->getPath(); + } else { + $route = new Route(); + $route->setPath($routePath); + $route->setLocale($locale); + $route->setEntityClass($entityClass); + $route->setEntityId((string) $localizedDimensionContent->getResourceId()); + + $routePath = $this->conflictResolver->resolve($route) + ->getPath(); } $oldData = $localizedDimensionContent->getTemplateData(); diff --git a/Resources/config/data-mapper.xml b/Resources/config/data-mapper.xml index 3d68c42d..d5362cdd 100644 --- a/Resources/config/data-mapper.xml +++ b/Resources/config/data-mapper.xml @@ -36,7 +36,7 @@ - %sulu.content.structure.default_types% + %sulu_route.mappings% diff --git a/Tests/Unit/Content/Application/ContentDataMapper/DataMapper/RoutableDataMapperTest.php b/Tests/Unit/Content/Application/ContentDataMapper/DataMapper/RoutableDataMapperTest.php index 7a8afabe..1d784389 100644 --- a/Tests/Unit/Content/Application/ContentDataMapper/DataMapper/RoutableDataMapperTest.php +++ b/Tests/Unit/Content/Application/ContentDataMapper/DataMapper/RoutableDataMapperTest.php @@ -24,6 +24,7 @@ use Sulu\Bundle\ContentBundle\Tests\Traits\SetGetPrivatePropertyTrait; use Sulu\Bundle\RouteBundle\Entity\Route; use Sulu\Bundle\RouteBundle\Generator\RouteGeneratorInterface; +use Sulu\Bundle\RouteBundle\Manager\ConflictResolverInterface; use Sulu\Bundle\RouteBundle\Manager\RouteManagerInterface; use Sulu\Component\Content\Metadata\Factory\StructureMetadataFactoryInterface; use Sulu\Component\Content\Metadata\PropertyMetadata; @@ -48,19 +49,23 @@ class RoutableDataMapperTest extends TestCase */ private $routeManager; + /** + * @var ObjectProphecy|ConflictResolverInterface + */ + private $conflictResolver; + protected function setUp(): void { $this->structureMetadataFactory = $this->prophesize(StructureMetadataFactoryInterface::class); $this->routeGenerator = $this->prophesize(RouteGeneratorInterface::class); $this->routeManager = $this->prophesize(RouteManagerInterface::class); + $this->conflictResolver = $this->prophesize(ConflictResolverInterface::class); } /** - * @param array $structureDefaultTypes * @param array> $resourceKeyMappings */ protected function createRouteDataMapperInstance( - array $structureDefaultTypes = [], ?array $resourceKeyMappings = null ): RoutableDataMapper { if (!\is_array($resourceKeyMappings)) { @@ -80,7 +85,7 @@ protected function createRouteDataMapperInstance( $this->structureMetadataFactory->reveal(), $this->routeGenerator->reveal(), $this->routeManager->reveal(), - $structureDefaultTypes, + $this->conflictResolver->reveal(), $resourceKeyMappings ); } @@ -94,8 +99,8 @@ public function testMapNoRoutableInterface(): void $this->structureMetadataFactory->getStructureMetadata(Argument::cetera())->shouldNotBeCalled(); $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent->reveal(), $localizedDimensionContent->reveal(), $data); @@ -113,6 +118,11 @@ public function testMapNoTemplateInterface(): void $localizedDimensionContent = $this->prophesize(DimensionContentInterface::class); $localizedDimensionContent->willImplement(RoutableInterface::class); + $this->structureMetadataFactory->getStructureMetadata(Argument::cetera())->shouldNotBeCalled(); + $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); + $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent->reveal(), $localizedDimensionContent->reveal(), $data); } @@ -120,6 +130,7 @@ public function testMapNoTemplateInterface(): void public function testMapNoTemplateGiven(): void { $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('LocalizedDimensionContent should return the a template.'); $data = []; @@ -131,10 +142,10 @@ public function testMapNoTemplateGiven(): void $this->structureMetadataFactory->getStructureMetadata(Argument::cetera())->shouldNotBeCalled(); $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); - $mapper = $this->createRouteDataMapperInstance([], []); + $mapper = $this->createRouteDataMapperInstance([]); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); @@ -143,22 +154,21 @@ public function testMapNoTemplateGiven(): void public function testMapNoMetadata(): void { - $data = [ - 'template' => 'default', - ]; + $data = []; $example = new Example(); static::setPrivateProperty($example, 'id', 1); $unlocalizedDimensionContent = new ExampleDimensionContent($example); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setLocale('en'); $this->structureMetadataFactory->getStructureMetadata('example', 'default') ->shouldBeCalled() ->willReturn(null); $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); @@ -168,14 +178,13 @@ public function testMapNoMetadata(): void public function testMapNoRouteProperty(): void { - $data = [ - 'template' => 'default', - ]; + $data = []; $example = new Example(); static::setPrivateProperty($example, 'id', 1); $unlocalizedDimensionContent = new ExampleDimensionContent($example); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setLocale('en'); $this->structureMetadataFactory->getStructureMetadata('example', 'default') @@ -183,8 +192,8 @@ public function testMapNoRouteProperty(): void ->willReturn($this->createTextLineStructureMetadata()); $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); @@ -197,22 +206,21 @@ public function testMapNoLocale(): void $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('Expected a LocalizedDimensionContent with a locale.'); - $data = [ - 'template' => 'default', - ]; + $data = []; $example = new Example(); static::setPrivateProperty($example, 'id', 1); $unlocalizedDimensionContent = new ExampleDimensionContent($example); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $this->structureMetadataFactory->getStructureMetadata('example', 'default') ->shouldBeCalled() ->willReturn($this->createRouteStructureMetadata()); $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); @@ -228,14 +236,13 @@ public function testMapNoRoutePropertyValue(): void ); /** @phpstan-ignore-next-line */ - $data = [ - 'template' => 'default', - ]; + $data = []; $example = new Example(); static::setPrivateProperty($example, 'id', 1); $unlocalizedDimensionContent = new ExampleDimensionContent($example); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setLocale('en'); $this->structureMetadataFactory->getStructureMetadata('example', 'default') @@ -243,8 +250,8 @@ public function testMapNoRoutePropertyValue(): void ->willReturn($this->createRouteStructureMetadata()); $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); @@ -258,7 +265,6 @@ public function testMapNoRouteMapping(): void $this->expectExceptionMessage('No route mapping found for "examples".'); $data = [ - 'template' => 'default', 'url' => '/test', ]; @@ -266,6 +272,7 @@ public function testMapNoRouteMapping(): void static::setPrivateProperty($example, 'id', 1); $unlocalizedDimensionContent = new ExampleDimensionContent($example); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setLocale('en'); $this->structureMetadataFactory->getStructureMetadata('example', 'default') @@ -273,10 +280,10 @@ public function testMapNoRouteMapping(): void ->willReturn($this->createRouteStructureMetadata()); $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); - $mapper = $this->createRouteDataMapperInstance([], []); + $mapper = $this->createRouteDataMapperInstance([]); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); $this->assertSame([], $localizedDimensionContent->getTemplateData()); @@ -288,7 +295,6 @@ public function testMapNoResourceId(): void $this->expectExceptionMessage('Expected a LocalizedDimensionContent with a resourceId.'); $data = [ - 'template' => 'default', 'url' => '/test', ]; @@ -296,6 +302,7 @@ public function testMapNoResourceId(): void $unlocalizedDimensionContent = new ExampleDimensionContent($example); $unlocalizedDimensionContent->setStage('live'); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setStage('live'); $localizedDimensionContent->setLocale('en'); @@ -304,8 +311,8 @@ public function testMapNoResourceId(): void ->willReturn($this->createRouteStructureMetadata()); $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); @@ -316,7 +323,6 @@ public function testMapNoResourceId(): void public function testMapRouteProperty(): void { $data = [ - 'template' => 'default', 'url' => '/test', ]; @@ -328,6 +334,7 @@ public function testMapRouteProperty(): void $unlocalizedDimensionContent = new ExampleDimensionContent($example); $unlocalizedDimensionContent->setStage('live'); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setStage('live'); $localizedDimensionContent->setLocale('en'); @@ -340,13 +347,13 @@ public function testMapRouteProperty(): void '1', 'en', '/test', - true + false ) ->shouldBeCalled() ->willReturn($route); - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); @@ -359,38 +366,40 @@ public function testMapRouteProperty(): void public function testMapRouteDraftDimension(): void { $data = [ - 'template' => 'default', 'url' => '/test', ]; + $conflictRoute = new Route(); + $conflictRoute->setPath('/test-1'); + $example = new Example(); $unlocalizedDimensionContent = new ExampleDimensionContent($example); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setLocale('en'); $this->structureMetadataFactory->getStructureMetadata('example', 'default') ->shouldBeCalled() ->willReturn($this->createRouteStructureMetadata()); - $this->routeManager->createOrUpdateByAttributes(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera()) + ->shouldBeCalled() + ->willReturn($conflictRoute); $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); $this->assertSame([ - 'url' => '/test', + 'url' => '/test-1', ], $localizedDimensionContent->getTemplateData()); } public function testMapNoNewAndOldUrl(): void { - $data = [ - 'template' => 'default', - ]; + $data = []; $route = new Route(); $route->setPath('/test'); @@ -400,21 +409,23 @@ public function testMapNoNewAndOldUrl(): void $unlocalizedDimensionContent = new ExampleDimensionContent($example); $unlocalizedDimensionContent->setStage('live'); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setStage('live'); $localizedDimensionContent->setLocale('en'); $this->structureMetadataFactory->getStructureMetadata('example', 'default') ->shouldBeCalled() ->willReturn($this->createRouteStructureMetadata()); - $this->routeGenerator->generate(Argument::cetera())->willReturn('/test'); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); + $this->routeManager->createOrUpdateByAttributes( Example::class, '1', 'en', '/test', - true + false ) ->shouldBeCalled() ->willReturn($route); @@ -429,9 +440,7 @@ public function testMapNoNewAndOldUrl(): void public function testMapWithNoUrlButOldUrl(): void { - $data = [ - 'template' => 'default', - ]; + $data = []; $route = new Route(); $route->setPath('/test-1'); @@ -441,6 +450,7 @@ public function testMapWithNoUrlButOldUrl(): void $unlocalizedDimensionContent = new ExampleDimensionContent($example); $unlocalizedDimensionContent->setStage('live'); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setStage('live'); $localizedDimensionContent->setLocale('en'); $localizedDimensionContent->setTemplateData(['url' => '/example']); @@ -449,11 +459,9 @@ public function testMapWithNoUrlButOldUrl(): void ->shouldBeCalled() ->willReturn($this->createRouteStructureMetadata()); - $this->routeManager->createOrUpdateByAttributes(Argument::cetera()) - ->shouldNotBeCalled(); - - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); + $this->routeManager->createOrUpdateByAttributes(Argument::cetera())->shouldNotBeCalled(); + $this->routeGenerator->generate(Argument::cetera())->shouldNotBeCalled(); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); @@ -466,7 +474,6 @@ public function testMapWithNoUrlButOldUrl(): void public function testMapGenerate(): void { $data = [ - 'template' => 'default', 'url' => null, ]; @@ -478,6 +485,7 @@ public function testMapGenerate(): void $unlocalizedDimensionContent = new ExampleDimensionContent($example); $unlocalizedDimensionContent->setStage('live'); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setStage('live'); $localizedDimensionContent->setLocale('en'); $localizedDimensionContent->setTemplateData(['title' => 'Test', 'url' => null]); @@ -499,12 +507,14 @@ public function testMapGenerate(): void '123', 'en', '/custom/testEntity-123', - true + false ) ->shouldBeCalled() ->willReturn($route); - $mapper = $this->createRouteDataMapperInstance([], [ + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); + + $mapper = $this->createRouteDataMapperInstance([ 'examples' => [ 'generator' => 'schema', 'options' => [ @@ -528,7 +538,6 @@ public function testMapOnlySlash(): void $this->expectExceptionMessage('Not allowed url "/" given or generated.'); $data = [ - 'template' => 'default', 'url' => null, ]; @@ -539,15 +548,17 @@ public function testMapOnlySlash(): void static::setPrivateProperty($example, 'id', 123); $unlocalizedDimensionContent = new ExampleDimensionContent($example); $localizedDimensionContent = new ExampleDimensionContent($example); + $localizedDimensionContent->setTemplateKey('default'); $localizedDimensionContent->setLocale('en'); $localizedDimensionContent->setTemplateData(['title' => 'Test', 'url' => null]); $this->structureMetadataFactory->getStructureMetadata('example', 'default') ->shouldBeCalled() ->willReturn($this->createRouteStructureMetadata()); - $this->routeGenerator->generate(Argument::cetera())->willReturn('/'); + $this->conflictResolver->resolve(Argument::cetera())->shouldNotBeCalled(); + $mapper = $this->createRouteDataMapperInstance(); $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); @@ -557,50 +568,6 @@ public function testMapOnlySlash(): void ], $localizedDimensionContent->getTemplateData()); } - public function testMapNoTemplateWithDefaultTemplate(): void - { - $data = [ - 'url' => '/test', - ]; - - $route = new Route(); - $route->setPath('/test-1'); - - $example = new Example(); - static::setPrivateProperty($example, 'id', 1); - $unlocalizedDimensionContent = new ExampleDimensionContent($example); - $unlocalizedDimensionContent->setStage('live'); - $localizedDimensionContent = new ExampleDimensionContent($example); - $localizedDimensionContent->setStage('live'); - $localizedDimensionContent->setLocale('en'); - - $this->structureMetadataFactory->getStructureMetadata('example', 'new-default') - ->shouldBeCalled() - ->willReturn($this->createRouteStructureMetadata()); - - $this->routeManager->createOrUpdateByAttributes( - Example::class, - '1', - 'en', - '/test', - true - ) - ->shouldBeCalled() - ->willReturn($route); - - $this->routeGenerator->generate(Argument::cetera()) - ->shouldNotBeCalled(); - - $mapper = $this->createRouteDataMapperInstance([ - 'example' => 'new-default', - ]); - $mapper->map($unlocalizedDimensionContent, $localizedDimensionContent, $data); - - $this->assertSame([ - 'url' => '/test-1', - ], $localizedDimensionContent->getTemplateData()); - } - private function createRouteStructureMetadata(): StructureMetadata { $property = $this->prophesize(PropertyMetadata::class);