1 <?php namespace BookStack\Entities\Managers;
3 use BookStack\Entities\Book;
4 use BookStack\Entities\Bookshelf;
5 use BookStack\Entities\Chapter;
6 use BookStack\Entities\Deletion;
7 use BookStack\Entities\Entity;
8 use BookStack\Entities\EntityProvider;
9 use BookStack\Entities\HasCoverImage;
10 use BookStack\Entities\Page;
11 use BookStack\Exceptions\NotifyException;
12 use BookStack\Facades\Activity;
13 use BookStack\Uploads\AttachmentService;
14 use BookStack\Uploads\ImageService;
21 * Send a shelf to the recycle bin.
23 public function softDestroyShelf(Bookshelf $shelf)
25 Deletion::createForEntity($shelf);
30 * Send a book to the recycle bin.
33 public function softDestroyBook(Book $book)
35 Deletion::createForEntity($book);
37 foreach ($book->pages as $page) {
38 $this->softDestroyPage($page, false);
41 foreach ($book->chapters as $chapter) {
42 $this->softDestroyChapter($chapter, false);
49 * Send a chapter to the recycle bin.
52 public function softDestroyChapter(Chapter $chapter, bool $recordDelete = true)
55 Deletion::createForEntity($chapter);
58 if (count($chapter->pages) > 0) {
59 foreach ($chapter->pages as $page) {
60 $this->softDestroyPage($page, false);
68 * Send a page to the recycle bin.
71 public function softDestroyPage(Page $page, bool $recordDelete = true)
74 Deletion::createForEntity($page);
77 // Check if set as custom homepage & remove setting if not used or throw error if active
78 $customHome = setting('app-homepage', '0:');
79 if (intval($page->id) === intval(explode(':', $customHome)[0])) {
80 if (setting('app-homepage-type') === 'page') {
81 throw new NotifyException(trans('errors.page_custom_home_deletion'), $page->getUrl());
83 setting()->remove('app-homepage');
90 * Remove a bookshelf from the system.
93 public function destroyShelf(Bookshelf $shelf): int
95 $this->destroyCommonRelations($shelf);
96 $shelf->forceDelete();
101 * Remove a book from the system.
102 * Destroys any child chapters and pages.
105 public function destroyBook(Book $book): int
108 $pages = $book->pages()->withTrashed()->get();
109 foreach ($pages as $page) {
110 $this->destroyPage($page);
114 $chapters = $book->chapters()->withTrashed()->get();
115 foreach ($chapters as $chapter) {
116 $this->destroyChapter($chapter);
120 $this->destroyCommonRelations($book);
121 $book->forceDelete();
126 * Remove a chapter from the system.
127 * Destroys all pages within.
130 public function destroyChapter(Chapter $chapter): int
133 $pages = $chapter->pages()->withTrashed()->get();
135 foreach ($pages as $page) {
136 $this->destroyPage($page);
141 $this->destroyCommonRelations($chapter);
142 $chapter->forceDelete();
147 * Remove a page from the system.
150 public function destroyPage(Page $page): int
152 $this->destroyCommonRelations($page);
154 // Delete Attached Files
155 $attachmentService = app(AttachmentService::class);
156 foreach ($page->attachments as $attachment) {
157 $attachmentService->deleteFile($attachment);
160 $page->forceDelete();
165 * Get the total counts of those that have been trashed
166 * but not yet fully deleted (In recycle bin).
168 public function getTrashedCounts(): array
170 $provider = app(EntityProvider::class);
173 /** @var Entity $instance */
174 foreach ($provider->all() as $key => $instance) {
175 $counts[$key] = $instance->newQuery()->onlyTrashed()->count();
182 * Destroy all items that have pending deletions.
184 public function destroyFromAllDeletions(): int
186 $deletions = Deletion::all();
188 foreach ($deletions as $deletion) {
189 // For each one we load in the relation since it may have already
190 // been deleted as part of another deletion in this loop.
191 $entity = $deletion->deletable()->first();
193 $count = $this->destroyEntity($deletion->deletable);
194 $deleteCount += $count;
202 * Destroy the given entity.
204 protected function destroyEntity(Entity $entity): int
206 if ($entity->isA('page')) {
207 return $this->destroyPage($entity);
209 if ($entity->isA('chapter')) {
210 return $this->destroyChapter($entity);
212 if ($entity->isA('book')) {
213 return $this->destroyBook($entity);
215 if ($entity->isA('shelf')) {
216 return $this->destroyShelf($entity);
221 * Update entity relations to remove or update outstanding connections.
223 protected function destroyCommonRelations(Entity $entity)
225 Activity::removeEntity($entity);
226 $entity->views()->delete();
227 $entity->permissions()->delete();
228 $entity->tags()->delete();
229 $entity->comments()->delete();
230 $entity->jointPermissions()->delete();
231 $entity->searchTerms()->delete();
232 $entity->deletions()->delete();
234 if ($entity instanceof HasCoverImage && $entity->cover) {
235 $imageService = app()->make(ImageService::class);
236 $imageService->destroy($entity->cover);