diff --git a/app/References/ReferenceUpdater.php b/app/References/ReferenceUpdater.php index d90591ab6..2f7b70a87 100644 --- a/app/References/ReferenceUpdater.php +++ b/app/References/ReferenceUpdater.php @@ -2,6 +2,7 @@ namespace BookStack\References; +use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Entity; use BookStack\Entities\Models\Page; use BookStack\Entities\Repos\RevisionRepo; @@ -21,7 +22,7 @@ class ReferenceUpdater public function updateEntityPageReferences(Entity $entity, string $oldLink) { - $references = $this->referenceFetcher->getPageReferencesToEntity($entity); + $references = $this->getReferencesToUpdate($entity); $newLink = $entity->getUrl(); /** @var Reference $reference */ @@ -32,6 +33,33 @@ class ReferenceUpdater } } + /** + * @return Reference[] + */ + protected function getReferencesToUpdate(Entity $entity): array + { + /** @var Reference[] $references */ + $references = $this->referenceFetcher->getPageReferencesToEntity($entity)->values()->all(); + + if ($entity instanceof Book) { + $pages = $entity->pages()->get(['id']); + $chapters = $entity->chapters()->get(['id']); + $children = $pages->concat($chapters); + foreach ($children as $bookChild) { + $childRefs = $this->referenceFetcher->getPageReferencesToEntity($bookChild)->values()->all(); + array_push($references, ...$childRefs); + } + } + + $deduped = []; + foreach ($references as $reference) { + $key = $reference->from_id . ':' . $reference->from_type; + $deduped[$key] = $reference; + } + + return array_values($deduped); + } + protected function updateReferencesWithinPage(Page $page, string $oldLink, string $newLink) { $page = (clone $page)->refresh(); diff --git a/tests/References/ReferencesTest.php b/tests/References/ReferencesTest.php index a067aadfa..3fd68d647 100644 --- a/tests/References/ReferencesTest.php +++ b/tests/References/ReferencesTest.php @@ -3,6 +3,7 @@ namespace Tests\References; use BookStack\Entities\Models\Book; +use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Page; use BookStack\Entities\Repos\PageRepo; use BookStack\Entities\Tools\TrashCan; @@ -145,6 +146,56 @@ class ReferencesTest extends TestCase } } + public function test_pages_linking_to_other_page_updated_on_parent_book_url_change() + { + /** @var Page $bookPage */ + /** @var Page $otherPage */ + /** @var Book $book */ + $bookPage = Page::query()->first(); + $otherPage = Page::query()->where('id', '!=', $bookPage->id)->first(); + $book = $bookPage->book; + + $otherPage->html = 'Link'; + $otherPage->save(); + $this->createReference($otherPage, $bookPage); + + $this->asEditor()->put($book->getUrl(), [ + 'name' => 'my updated book slugaroo', + ]); + + $otherPage->refresh(); + $this->assertStringContainsString('href="http://localhost/books/my-updated-book-slugaroo/page/' . $bookPage->slug . '"', $otherPage->html); + $this->assertDatabaseHas('page_revisions', [ + 'page_id' => $otherPage->id, + 'summary' => 'System auto-update of internal links', + ]); + } + + public function test_pages_linking_to_chapter_updated_on_parent_book_url_change() + { + /** @var Chapter $bookChapter */ + /** @var Page $otherPage */ + /** @var Book $book */ + $bookChapter = Chapter::query()->first(); + $otherPage = Page::query()->first(); + $book = $bookChapter->book; + + $otherPage->html = 'Link'; + $otherPage->save(); + $this->createReference($otherPage, $bookChapter); + + $this->asEditor()->put($book->getUrl(), [ + 'name' => 'my updated book slugaroo', + ]); + + $otherPage->refresh(); + $this->assertStringContainsString('href="http://localhost/books/my-updated-book-slugaroo/chapter/' . $bookChapter->slug . '"', $otherPage->html); + $this->assertDatabaseHas('page_revisions', [ + 'page_id' => $otherPage->id, + 'summary' => 'System auto-update of internal links', + ]); + } + public function test_markdown_links_leading_to_entity_updated_on_url_change() { /** @var Page $page */