diff --git a/Adapter/PhpcrOdmAdapter.php b/Adapter/PhpcrOdmAdapter.php index 47ca677..2eaf0a9 100644 --- a/Adapter/PhpcrOdmAdapter.php +++ b/Adapter/PhpcrOdmAdapter.php @@ -115,33 +115,57 @@ public function removeAutoRoute(AutoRouteInterface $autoRoute) */ public function createAutoRoute($uri, $contentDocument, $autoRouteTag) { - $path = $this->baseRoutePath; - $document = $parentDocument = $this->dm->find(null, $path); + $basePath = $this->baseRoutePath; + $document = $parentDocument = $this->dm->find(null, $basePath); + if (null === $parentDocument) { throw new \RuntimeException(sprintf('The "route_basepath" configuration points to a non-existant path "%s".', - $path + $basePath )); } $segments = preg_split('#/#', $uri, null, PREG_SPLIT_NO_EMPTY); $headName = array_pop($segments); foreach ($segments as $segment) { - $path .= '/' . $segment; - $document = $this->dm->find(null, $path); + $basePath .= '/' . $segment; + $document = $this->dm->find(null, $basePath); if (null === $document) { $document = new Generic(); - $document->setParent($parentDocument); + $document->setParentDocument($parentDocument); $document->setNodeName($segment); $this->dm->persist($document); } $parentDocument = $document; } + $path = $basePath . '/' . $headName; + $existingDocument = $this->dm->find(null, $path); + + if ($existingDocument) { + if ($existingDocument instanceof Generic) { + return $this->migrateGenericToAutoRoute( + $existingDocument, + $contentDocument, + $autoRouteTag, + AutoRouteInterface::TYPE_PRIMARY + ); + } + + throw new \RuntimeException( + sprintf( + 'Encountered existing PHPCR-ODM document at path "%s" of class "%s", the route tree should ' . + 'contain only instances of AutoRouteInterface.', + $path, + get_class($existingDocument) + ) + ); + } + $headRoute = new $this->autoRouteFqcn(); $headRoute->setContent($contentDocument); $headRoute->setName($headName); - $headRoute->setParent($document); + $headRoute->setParentDocument($document); $headRoute->setAutoRouteTag($autoRouteTag); $headRoute->setType(AutoRouteInterface::TYPE_PRIMARY); @@ -190,13 +214,51 @@ public function getReferringAutoRoutes($contentDocument) */ public function findRouteForUri($uri) { - $path = $this->getPathFromUri($uri); - - return $this->dm->find(null, $path); + return $this->dm->find( + 'Symfony\Cmf\Component\RoutingAuto\Model\AutoRouteInterface', + $this->getPathFromUri($uri) + ); } private function getPathFromUri($uri) { return $this->baseRoutePath . $uri; } + + /** + * Convert the given generic document to an auto route document. + * + * @param Generic $document + * @param object $contentDocument + * @param string $autoRouteTag + * @param string $routeType + * @return AutoRouteInterface + */ + private function migrateGenericToAutoRoute(Generic $document, $contentDocument, $autoRouteTag, $routeType) + { + $autoRouteClassName = $this->autoRouteFqcn; + $mapper = $this->dm->getConfiguration()->getDocumentClassMapper(); + $mapper->writeMetadata($this->dm, $document->getNode(), $autoRouteClassName); + $this->dm->getPhpcrSession()->save(); + // Detach is needed to force Doctrine to re-load the node + $this->dm->detach($document); + $autoRoute = $this->dm->find(null, $document->getId()); + + if (!$autoRoute instanceof $autoRouteClassName) { + throw new \RuntimeException( + sprintf( + 'Failed to migrate existing, non-managed, PHPCR node at "%s" to a managed document implementing ' . + 'the AutoRouteInterface. It is an instance of "%s".', + $document->getId(), + get_class($autoRoute) + ) + ); + } + + $autoRoute->setContent($contentDocument); + $autoRoute->setAutoRouteTag($autoRouteTag); + $autoRoute->setType($routeType); + + return $autoRoute; + } } diff --git a/CHANGELOG.md b/CHANGELOG.md index d4c9e94..fb00294 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ Changelog ========= +1.0.2 +---------- + +* Convert non-managed intermediate nodes into AutoRoute documents #165 + +1.0.0 +----- + +* Enabled new `container` token provider - retrieve URL elements + from container parameters. + 1.0.0-RC1 --------- diff --git a/Tests/Functional/EventListener/AutoRouteListenerTest.php b/Tests/Functional/EventListener/AutoRouteListenerTest.php index 8d5c74b..34ec358 100644 --- a/Tests/Functional/EventListener/AutoRouteListenerTest.php +++ b/Tests/Functional/EventListener/AutoRouteListenerTest.php @@ -521,4 +521,37 @@ public function testConflictResolverDefaultThrowException() $this->getDm()->persist($blog); $this->getDm()->flush(); } + + public function testGenericNodeShouldBeConvertedInAnAutoRouteNode() + { + $blog = new Blog; + $blog->path = '/test/my-post'; + $blog->title = 'My Post'; + $this->getDm()->persist($blog); + $this->getDm()->flush(); + + $this->assertInstanceOf( + 'Doctrine\ODM\PHPCR\Document\Generic', + $this->getDm()->find(null, '/test/auto-route/blog') + ); + $blogRoute = $this->getDm()->find(null, '/test/auto-route/blog/my-post'); + $this->assertInstanceOf('Symfony\Cmf\Component\RoutingAuto\Model\AutoRouteInterface', $blogRoute); + $this->assertSame($blog, $blogRoute->getContent()); + + $page = new Page; + $page->path = '/test/blog'; + $page->title = 'Blog'; + + $this->getDm()->persist($page); + $this->getDm()->flush(); + + $this->assertInstanceOf( + 'Symfony\Cmf\Component\RoutingAuto\Model\AutoRouteInterface', + $this->getDm()->find(null, '/test/auto-route/blog') + ); + $this->assertInstanceOf( + 'Symfony\Cmf\Component\RoutingAuto\Model\AutoRouteInterface', + $this->getDm()->find(null, '/test/auto-route/blog/my-post') + ); + } } diff --git a/Tests/Unit/Adapter/PhpcrOdmAdapterTest.php b/Tests/Unit/Adapter/PhpcrOdmAdapterTest.php index 9a967cd..1e063eb 100644 --- a/Tests/Unit/Adapter/PhpcrOdmAdapterTest.php +++ b/Tests/Unit/Adapter/PhpcrOdmAdapterTest.php @@ -109,6 +109,8 @@ public function testCreateAutoRoute($path, $expectedParentPath, $expectedName, $ if ($parentPathExists) { $this->dm->find(null, $expectedParentPath) ->willReturn($this->parentRoute); + $this->dm->find(null, $expectedParentPath . '/' . $expectedName) + ->willReturn(null); } else { $this->dm->find(null, $expectedParentPath) ->willReturn(null); @@ -119,10 +121,34 @@ public function testCreateAutoRoute($path, $expectedParentPath, $expectedName, $ $this->assertInstanceOf('Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRoute', $res); $this->assertEquals($expectedName, $res->getName()); - $this->assertSame($this->parentRoute, $res->getParent()); + $this->assertSame($this->parentRoute, $res->getParentDocument()); $this->assertSame($this->contentDocument, $res->getContent()); } + /** + * @expectedException \RuntimeException + * @expectedExceptionMessageRegExp /Failed to migrate existing.*? at "\/test\/generic" .*? It is an instance of "stdClass"\./ + */ + public function testCreateAutoRouteThrowsExceptionIfItCannotMigrateExistingGenericDocumentToAutoRoute() + { + $uri = '/generic'; + $genericDocument = $this->prophesize('Doctrine\ODM\PHPCR\Document\Generic'); + $genericDocument->getNode()->willReturn($this->prophesize('PHPCR\NodeInterface')->reveal()); + $genericDocument->getId()->willReturn($this->baseRoutePath . $uri); + $documentClassMapper = $this->prophesize('Doctrine\ODM\PHPCR\DocumentClassMapperInterface'); + $configuration = $this->prophesize('Doctrine\ODM\PHPCR\Configuration'); + $configuration->getDocumentClassMapper()->willReturn($documentClassMapper->reveal()); + $this->dm->getConfiguration()->willReturn($configuration->reveal()); + $this->dm->getPhpcrSession()->willReturn($this->phpcrSession); + $this->dm->detach($genericDocument)->willReturn(null); + $this->dm->find(null, $this->baseRoutePath)->willReturn($this->baseNode); + $this->dm->find(null, $this->baseRoutePath . $uri)->willReturn( + $genericDocument->reveal(), + new \stdClass() + ); + $this->adapter->createAutoRoute($uri, $this->contentDocument, 'it'); + } + /** * @expectedException \RuntimeException * @expectedExceptionMessage configuration points to a non-existant path @@ -155,7 +181,7 @@ public function provideCompareRouteContent() public function testCompareRouteContent($isMatch) { $this->route->getContent()->willReturn($this->contentDocument); - $content = $isMatch ? $this->contentDocument : $this->contentDocument2; + $isMatch ? $this->contentDocument : $this->contentDocument2; $this->adapter->compareAutoRouteContent($this->route->reveal(), $this->contentDocument); } @@ -172,11 +198,11 @@ public function testGetReferringRoutes() public function testFindRouteForUri() { $uri = '/this/is/uri'; - $expectedRoutes = array($this->route->reveal()); + $expectedRoute = $this->route->reveal(); - $this->dm->find(null, $this->baseRoutePath . $uri)->willReturn($expectedRoutes); + $this->dm->find('Symfony\Cmf\Component\RoutingAuto\Model\AutoRouteInterface', $this->baseRoutePath . $uri)->willReturn($expectedRoute); $res = $this->adapter->findRouteForUri($uri); - $this->assertSame($expectedRoutes, $res); + $this->assertSame($expectedRoute, $res); } }