Skip to content

Commit b866dee

Browse files
committed
Entities: Updated repos to act on refreshed clones
Changes to core entity models are now done on clones to ensure clean state before save, and those clones are returned back if changes are needed after that action.
1 parent bf09b42 commit b866dee

30 files changed

+100
-63
lines changed

app/Entities/Controllers/ChapterController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public function update(Request $request, string $bookSlug, string $chapterSlug)
130130
$chapter = $this->queries->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
131131
$this->checkOwnablePermission(Permission::ChapterUpdate, $chapter);
132132

133-
$this->chapterRepo->update($chapter, $validated);
133+
$chapter = $this->chapterRepo->update($chapter, $validated);
134134

135135
return redirect($chapter->getUrl());
136136
}

app/Entities/Models/Book.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ public function getBookCover(int $width = 440, int $height = 250): string
5959
}
6060
}
6161

62+
// TODO - Still handle cover as relation through containerData (since it's used in code)
63+
// TODO - Remove above since we can access that via containerData
64+
6265
/**
6366
* Get the Page that is used as default template for newly created pages within this Book.
6467
*/

app/Entities/Models/BookChild.php

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace BookStack\Entities\Models;
44

55
use BookStack\References\ReferenceUpdater;
6-
use Illuminate\Database\Eloquent\Builder;
76
use Illuminate\Database\Eloquent\Relations\BelongsTo;
87

98
/**
@@ -27,25 +26,25 @@ public function book(): BelongsTo
2726
/**
2827
* Change the book that this entity belongs to.
2928
*/
30-
public function changeBook(int $newBookId): Entity
29+
public function changeBook(int $newBookId): self
3130
{
32-
$oldUrl = $this->getUrl();
33-
$this->book_id = $newBookId;
34-
$this->refreshSlug();
35-
$this->save();
36-
$this->refresh();
31+
$altered = $this->clone()->refresh();
32+
$oldUrl = $altered->getUrl();
33+
$altered->book_id = $newBookId;
34+
$altered->refreshSlug();
35+
$altered->save();
3736

38-
if ($oldUrl !== $this->getUrl()) {
39-
app()->make(ReferenceUpdater::class)->updateEntityReferences($this, $oldUrl);
37+
if ($oldUrl !== $altered->getUrl()) {
38+
app()->make(ReferenceUpdater::class)->updateEntityReferences($altered, $oldUrl);
4039
}
4140

4241
// Update all child pages if a chapter
43-
if ($this instanceof Chapter) {
44-
foreach ($this->pages()->withTrashed()->get() as $page) {
42+
if ($altered instanceof Chapter) {
43+
foreach ($altered->pages()->withTrashed()->get() as $page) {
4544
$page->changeBook($newBookId);
4645
}
4746
}
4847

49-
return $this;
48+
return $altered;
5049
}
5150
}

app/Entities/Models/Bookshelf.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ public function getBookCover(int $width = 440, int $height = 250): string
5959
}
6060
}
6161

62+
// TODO - Still handle cover as relation through containerData (since it's used in code)
63+
// TODO - Remove above since we can access that via containerData
64+
6265
/**
6366
* Check if this shelf contains the given book.
6467
*/

app/Entities/Models/Entity.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public function shouldHaveContainerData(): bool
101101
}
102102

103103
/**
104-
* Get the container-specific data for this page.
104+
* Get the container-specific data for this item.
105105
*/
106106
public function containerData(): HasOne
107107
{

app/Entities/Models/EntityContainerData.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use BookStack\Uploads\Image;
66
use BookStack\Util\HtmlContentFilter;
7+
use Exception;
78
use Illuminate\Database\Eloquent\Model;
89
use Illuminate\Database\Eloquent\Relations\HasOne;
910

@@ -27,6 +28,22 @@ public function cover(): HasOne
2728
return $this->hasOne(Image::class, 'image_id');
2829
}
2930

31+
/**
32+
* Returns a shelf cover image URL, if cover not exists return default cover image.
33+
*/
34+
public function getCoverUrl(int $width = 440, int $height = 250, string|null $default = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='): string|null
35+
{
36+
if (!$this->image_id) {
37+
return $default;
38+
}
39+
40+
try {
41+
return $this->cover->getThumb($width, $height, false) ?? $default;
42+
} catch (Exception $err) {
43+
return $default;
44+
}
45+
}
46+
3047
/**
3148
* Check if this data supports having a default template assigned.
3249
*/
@@ -46,7 +63,7 @@ public function supportsCoverImage(): bool
4663
/**
4764
* Get the description as a cleaned/handled HTML string.
4865
*/
49-
public function descriptionHtml(bool $raw = false): string
66+
public function getDescriptionHtml(bool $raw = false): string
5067
{
5168
$html = $this->description_html ?: '<p>' . nl2br(e($this->description)) . '</p>';
5269
if ($raw) {
@@ -69,7 +86,7 @@ public function setDescriptionHtml(string $html, string|null $plaintext = null):
6986
}
7087

7188
if (empty($html) && !empty($plaintext)) {
72-
$this->description_html = $this->descriptionHtml();
89+
$this->description_html = $this->getDescriptionHtml();
7390
}
7491
}
7592
}

app/Entities/Repos/BaseRepo.php

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
namespace BookStack\Entities\Repos;
44

55
use BookStack\Activity\TagRepo;
6-
use BookStack\Entities\Models\Book;
76
use BookStack\Entities\Models\BookChild;
8-
use BookStack\Entities\Models\Chapter;
97
use BookStack\Entities\Models\Entity;
108
use BookStack\Entities\Models\EntityContainerData;
119
use BookStack\Entities\Queries\PageQueries;
@@ -31,9 +29,13 @@ public function __construct(
3129

3230
/**
3331
* Create a new entity in the system.
32+
* @template T of Entity
33+
* @param T $entity
34+
* @return T
3435
*/
35-
public function create(Entity $entity, array $input): void
36+
public function create(Entity $entity, array $input): Entity
3637
{
38+
$entity = $entity->clone()->refresh();
3739
$entityInput = array_intersect_key($input, ['name', 'priority']);
3840
$entity->forceFill($entityInput);
3941
$entity->forceFill([
@@ -59,13 +61,19 @@ public function create(Entity $entity, array $input): void
5961
$entity->indexForSearch();
6062

6163
$this->referenceStore->updateForEntity($entity);
64+
65+
return $entity;
6266
}
6367

6468
/**
6569
* Update the given entity.
70+
* @template T of Entity
71+
* @param T $entity
72+
* @return T
6673
*/
67-
public function update(Entity $entity, array $input): void
74+
public function update(Entity $entity, array $input): Entity
6875
{
76+
$entity = $entity->clone()->refresh();
6977
$oldUrl = $entity->getUrl();
7078

7179
$entity->fill($input);
@@ -78,6 +86,7 @@ public function update(Entity $entity, array $input): void
7886
$entity->save();
7987
if ($entity->shouldHaveContainerData() && $entity->containerData) {
8088
$this->updateContainerDescription($entity->containerData, $input);
89+
$entity->containerData->save();
8190
}
8291

8392
if (isset($input['tags'])) {
@@ -91,6 +100,8 @@ public function update(Entity $entity, array $input): void
91100
if ($oldUrl !== $entity->getUrl()) {
92101
$this->referenceUpdater->updateEntityReferences($entity, $oldUrl);
93102
}
103+
104+
return $entity;
94105
}
95106

96107
/**
@@ -147,7 +158,7 @@ public function updateDefaultTemplate(EntityContainerData $containerData, int $t
147158
}
148159

149160
/**
150-
* Sort the parent of the given entity, if any auto sort actions are set for it.
161+
* Sort the parent of the given entity if any auto sort actions are set for it.
151162
* Typically ran during create/update/insert events.
152163
*/
153164
public function sortParent(Entity $entity): void
@@ -158,6 +169,9 @@ public function sortParent(Entity $entity): void
158169
}
159170
}
160171

172+
/**
173+
* Update the description of the given container data from input data.
174+
*/
161175
protected function updateContainerDescription(EntityContainerData $data, array $input): void
162176
{
163177
if (isset($input['description_html'])) {

app/Entities/Repos/BookRepo.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ public function __construct(
3030
public function create(array $input): Book
3131
{
3232
return (new DatabaseTransaction(function () use ($input) {
33-
$book = new Book();
34-
35-
$this->baseRepo->create($book, $input);
33+
$book = $this->baseRepo->create(new Book(), $input);
3634
$this->baseRepo->updateCoverImage($book->containerData, $input['image'] ?? null);
3735
$this->baseRepo->updateDefaultTemplate($book->containerData, intval($input['default_template_id'] ?? null));
3836
Activity::add(ActivityType::BOOK_CREATE, $book);
@@ -52,7 +50,7 @@ public function create(array $input): Book
5250
*/
5351
public function update(Book $book, array $input): Book
5452
{
55-
$this->baseRepo->update($book, $input);
53+
$book = $this->baseRepo->update($book, $input);
5654

5755
if (array_key_exists('default_template_id', $input)) {
5856
$this->baseRepo->updateDefaultTemplate($book->containerData, intval($input['default_template_id']));

app/Entities/Repos/BookshelfRepo.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ public function __construct(
2525
public function create(array $input, array $bookIds): Bookshelf
2626
{
2727
return (new DatabaseTransaction(function () use ($input, $bookIds) {
28-
$shelf = new Bookshelf();
29-
$this->baseRepo->create($shelf, $input);
28+
$shelf = $this->baseRepo->create(new Bookshelf(), $input);
3029
$this->baseRepo->updateCoverImage($shelf->containerData, $input['image'] ?? null);
3130
$this->updateBooks($shelf, $bookIds);
3231
Activity::add(ActivityType::BOOKSHELF_CREATE, $shelf);
@@ -39,7 +38,7 @@ public function create(array $input, array $bookIds): Bookshelf
3938
*/
4039
public function update(Bookshelf $shelf, array $input, ?array $bookIds): Bookshelf
4140
{
42-
$this->baseRepo->update($shelf, $input);
41+
$shelf = $this->baseRepo->update($shelf, $input);
4342

4443
if (!is_null($bookIds)) {
4544
$this->updateBooks($shelf, $bookIds);

app/Entities/Repos/ChapterRepo.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public function create(array $input, Book $parentBook): Chapter
3333
$chapter = new Chapter();
3434
$chapter->book_id = $parentBook->id;
3535
$chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1;
36-
$this->baseRepo->create($chapter, $input);
36+
37+
$chapter = $this->baseRepo->create($chapter, $input);
3738
$this->baseRepo->updateDefaultTemplate($chapter->containerData, intval($input['default_template_id'] ?? null));
3839
Activity::add(ActivityType::CHAPTER_CREATE, $chapter);
3940

@@ -48,7 +49,7 @@ public function create(array $input, Book $parentBook): Chapter
4849
*/
4950
public function update(Chapter $chapter, array $input): Chapter
5051
{
51-
$this->baseRepo->update($chapter, $input);
52+
$chapter = $this->baseRepo->update($chapter, $input);
5253

5354
if (array_key_exists('default_template_id', $input)) {
5455
$this->baseRepo->updateDefaultTemplate($chapter->containerData, intval($input['default_template_id']));
@@ -93,7 +94,7 @@ public function move(Chapter $chapter, string $parentIdentifier): Book
9394
}
9495

9596
return (new DatabaseTransaction(function () use ($chapter, $parent) {
96-
$chapter->changeBook($parent->id);
97+
$chapter = $chapter->changeBook($parent->id);
9798
$chapter->rebuildPermissions();
9899
Activity::add(ActivityType::CHAPTER_MOVE, $chapter);
99100

0 commit comments

Comments
 (0)