diff --git a/Command/MovePageTreeCommand.php b/Command/MovePageTreeCommand.php new file mode 100644 index 000000000..e42f4df8c --- /dev/null +++ b/Command/MovePageTreeCommand.php @@ -0,0 +1,58 @@ +setName('sulu:article:page-tree:move') + ->addArgument('source-segment', InputArgument::REQUIRED) + ->addArgument('destination-segment', InputArgument::REQUIRED) + ->addArgument('webspace-key', InputArgument::REQUIRED) + ->addArgument('locale', InputArgument::REQUIRED); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $source = $input->getArgument('source-segment'); + $destination = $input->getArgument('destination-segment'); + $webspaceKey = $input->getArgument('webspace-key'); + $locale = $input->getArgument('locale'); + + $mover = $this->getContainer()->get('sulu_article.page_tree_route.mover'); + $strategyPool = $this->getContainer()->get('sulu.content.resource_locator.strategy_pool'); + $documentManager = $this->getContainer()->get('sulu_document_manager.document_manager'); + $strategy = $strategyPool->getStrategyByWebspaceKey($webspaceKey); + + $destinationUuid = $strategy->loadByResourceLocator($destination, $webspaceKey, $locale); + $document = $documentManager->find($destinationUuid, $locale); + + $mover->move($source, $document); + + $documentManager->flush(); + } +} diff --git a/DependencyInjection/SuluArticleExtension.php b/DependencyInjection/SuluArticleExtension.php index 80ab70bcd..b4e048e4c 100644 --- a/DependencyInjection/SuluArticleExtension.php +++ b/DependencyInjection/SuluArticleExtension.php @@ -163,6 +163,7 @@ public function load(array $configs, ContainerBuilder $container) 'sulu_article.page_tree_route.updater.' . $config['content_types']['page_tree_route']['page_route_cascade'] ); + $loader->load('page_tree_move.xml'); if ($config['content_types']['page_tree_route']['page_route_cascade'] !== 'off') { $loader->load('page_tree_update.xml'); } diff --git a/PageTree/PageTreeMoverInterface.php b/PageTree/PageTreeMoverInterface.php new file mode 100644 index 000000000..814af1ace --- /dev/null +++ b/PageTree/PageTreeMoverInterface.php @@ -0,0 +1,26 @@ +findLinkedArticles($document->getUuid(), $document->getLocale()); + $articles = $this->findLinkedArticles('page', $document->getUuid(), $document->getLocale()); foreach ($articles as $article) { - $this->updateArticle($article, $document->getResourceSegment(), $document->getLocale()); + $this->updateArticle($article, $document); + } + } + + /** + * {@inheritdoc} + */ + public function move($source, BasePageDocument $document) + { + $articles = $this->findLinkedArticles('page-path', $source, $document->getLocale()); + foreach ($articles as $article) { + $this->updateArticle($article, $document); } } /** * Find articles linked to the given page. * - * @param string $uuid + * @param string $field + * @param string $value * @param string $locale * * @return ArticleInterface[] */ - private function findLinkedArticles($uuid, $locale) + private function findLinkedArticles($field, $value, $locale) { $where = []; foreach ($this->metadataFactory->getStructures('article') as $metadata) { @@ -98,11 +110,12 @@ private function findLinkedArticles($uuid, $locale) } $where[] = sprintf( - '([%s] = "%s" AND [%s-page] = "%s")', + '([%s] = "%s" AND [%s-%s] = "%s")', $this->propertyEncoder->localizedSystemName('template', $locale), $metadata->getName(), $this->propertyEncoder->localizedContentName($property->getName(), $locale), - $uuid + $field, + $value ); } @@ -125,15 +138,18 @@ private function findLinkedArticles($uuid, $locale) * Update route of given article. * * @param ArticleDocument $article - * @param string $resourceSegment - * @param string $locale + * @param BasePageDocument $document */ - private function updateArticle(ArticleDocument $article, $resourceSegment, $locale) + private function updateArticle(ArticleDocument $article, BasePageDocument $document) { + $locale = $document->getLocale(); + $resourceSegment = $document->getResourceSegment(); + $property = $this->getRoutePathPropertyNameByStructureType($article->getStructureType()); $propertyName = $this->propertyEncoder->localizedContentName($property->getName(), $locale); $node = $this->documentInspector->getNode($article); + $node->setProperty($propertyName . '-page', $document->getUuid()); $node->setProperty($propertyName . '-page-path', $resourceSegment); $suffix = $node->getPropertyValueWithDefault($propertyName . '-suffix', null); diff --git a/Resources/config/page_tree_move.xml b/Resources/config/page_tree_move.xml new file mode 100644 index 000000000..8390fc1d9 --- /dev/null +++ b/Resources/config/page_tree_move.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/Resources/config/page_tree_update.xml b/Resources/config/page_tree_update.xml index 3c417f08a..7971005ee 100644 --- a/Resources/config/page_tree_update.xml +++ b/Resources/config/page_tree_update.xml @@ -16,7 +16,7 @@ + class="Sulu\Bundle\ArticleBundle\PageTree\PageTreeRepository"> diff --git a/Tests/Functional/PageTree/PageTreeRepositoryTest.php b/Tests/Functional/PageTree/PageTreeRepositoryTest.php new file mode 100644 index 000000000..f27c86c99 --- /dev/null +++ b/Tests/Functional/PageTree/PageTreeRepositoryTest.php @@ -0,0 +1,188 @@ +initPhpcr(); + $this->purgeDatabase(); + + $this->documentManager = $this->getContainer()->get('sulu_document_manager.document_manager'); + $this->pageTreeRepository = new PageTreeRepository( + $this->documentManager, + $this->getContainer()->get('sulu_content.structure.factory'), + $this->getContainer()->get('sulu_document_manager.property_encoder'), + $this->getContainer()->get('sulu_document_manager.document_inspector') + ); + } + + public function testUpdate() + { + $pages = [ + $this->createPage('Test 1', '/test-1'), + $this->createPage('Test 2', '/test-2'), + ]; + + $articles = [ + $this->createArticle($this->getPathData($pages[0], 'article-1')), + $this->createArticle($this->getPathData($pages[0], 'article-2')), + $this->createArticle($this->getPathData($pages[1], 'article-3')), + ]; + $this->documentManager->flush(); + + $pages[0]->setResourceSegment('/test-3'); + $this->documentManager->persist($pages[0], $this->locale); + $this->documentManager->publish($pages[0], $this->locale); + $this->documentManager->flush(); + $this->documentManager->clear(); + + $this->pageTreeRepository->update($pages[0]); + $this->documentManager->flush(); + $this->documentManager->clear(); + + $result = [ + $this->documentManager->find($articles[0]['id'], $this->locale), + $this->documentManager->find($articles[1]['id'], $this->locale), + $this->documentManager->find($articles[2]['id'], $this->locale), + ]; + + $this->assertEquals('/test-3/article-1', $result[0]->getRoutePath()); + $this->assertEquals('/test-3/article-2', $result[1]->getRoutePath()); + $this->assertEquals('/test-2/article-3', $result[2]->getRoutePath()); + } + + public function testMove() + { + $pages = [ + $this->createPage('Test 1', '/test-1'), + $this->createPage('Test 2', '/test-2'), + $this->createPage('Test 3', '/test-3'), + ]; + + $articles = [ + $this->createArticle($this->getPathData($pages[0], 'article-1')), + $this->createArticle($this->getPathData($pages[0], 'article-2')), + $this->createArticle($this->getPathData($pages[1], 'article-3')), + ]; + + $this->documentManager->flush(); + $this->documentManager->clear(); + + $this->pageTreeRepository->move('/test-1', $pages[2]); + $this->documentManager->flush(); + $this->documentManager->clear(); + + $result = [ + $this->documentManager->find($articles[0]['id'], $this->locale), + $this->documentManager->find($articles[1]['id'], $this->locale), + $this->documentManager->find($articles[2]['id'], $this->locale), + ]; + + $this->assertEquals('/test-3/article-1', $result[0]->getRoutePath()); + $this->assertEquals('/test-3/article-2', $result[1]->getRoutePath()); + $this->assertEquals('/test-2/article-3', $result[2]->getRoutePath()); + } + + private function getPathData(PageDocument $page, $suffix) + { + return [ + 'page' => [ + 'uuid' => $page->getUuid(), + 'path' => $page->getResourceSegment(), + ], + 'suffix' => $suffix, + 'path' => $page->getResourceSegment() . '/' . $suffix, + ]; + } + + /** + * Create a new article. + * + * @param array $routePathData + * @param string $title + * + * @return array + */ + private function createArticle(array $routePathData, $title = 'Test Article') + { + $client = $this->createAuthenticatedClient(); + $client->request( + 'POST', + '/api/articles?locale=' . $this->locale . '&action=publish', + [ + 'title' => $title, + 'template' => 'page_tree_route', + 'routePath' => $routePathData, + 'authored' => '2016-01-01', + ] + ); + + return json_decode($client->getResponse()->getContent(), true); + } + + /** + * Create a new page. + * + * @param string $title + * @param string $resourceSegment + * + * @return PageDocument + */ + private function createPage($title = 'Test Page', $resourceSegment = '/test-page') + { + $sessionManager = $this->getContainer()->get('sulu.phpcr.session'); + $page = $this->documentManager->create('page'); + + $uuidReflection = new \ReflectionProperty(PageDocument::class, 'uuid'); + $uuidReflection->setAccessible(true); + $uuidReflection->setValue($page, Uuid::uuid4()->toString()); + + $page->setTitle($title); + $page->setStructureType('default'); + $page->setParent($this->documentManager->find($sessionManager->getContentPath('sulu_io'))); + $page->setResourceSegment($resourceSegment); + + $this->documentManager->persist($page, $this->locale); + $this->documentManager->publish($page, $this->locale); + $this->documentManager->flush(); + + return $page; + } +}