]> BookStack Code Mirror - bookstack/blob - app/Entities/Repos/ChapterRepo.php
added template to chapter API controller
[bookstack] / app / Entities / Repos / ChapterRepo.php
1 <?php
2
3 namespace BookStack\Entities\Repos;
4
5 use BookStack\Activity\ActivityType;
6 use BookStack\Entities\Models\Book;
7 use BookStack\Entities\Models\Page;
8 use BookStack\Entities\Models\Chapter;
9 use BookStack\Entities\Models\Entity;
10 use BookStack\Entities\Tools\BookContents;
11 use BookStack\Entities\Tools\TrashCan;
12 use BookStack\Exceptions\MoveOperationException;
13 use BookStack\Exceptions\NotFoundException;
14 use BookStack\Exceptions\PermissionsException;
15 use BookStack\Facades\Activity;
16 use Exception;
17
18 class ChapterRepo
19 {
20     public function __construct(
21         protected BaseRepo $baseRepo
22     ) {
23     }
24
25     /**
26      * Get a chapter via the slug.
27      *
28      * @throws NotFoundException
29      */
30     public function getBySlug(string $bookSlug, string $chapterSlug): Chapter
31     {
32         $chapter = Chapter::visible()->whereSlugs($bookSlug, $chapterSlug)->first();
33
34         if ($chapter === null) {
35             throw new NotFoundException(trans('errors.chapter_not_found'));
36         }
37
38         return $chapter;
39     }
40
41     /**
42      * Create a new chapter in the system.
43      */
44     public function create(array $input, Book $parentBook): Chapter
45     {
46         $chapter = new Chapter();
47         $chapter->book_id = $parentBook->id;
48         $chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1;
49         $this->baseRepo->create($chapter, $input);
50         $this->updateChapterDefaultTemplate($chapter, intval($input['default_template_id'] ?? null));
51         Activity::add(ActivityType::CHAPTER_CREATE, $chapter);
52
53         return $chapter;
54     }
55
56     /**
57      * Update the given chapter.
58      */
59     public function update(Chapter $chapter, array $input): Chapter
60     {
61         $this->baseRepo->update($chapter, $input);
62
63         if (array_key_exists('default_template_id', $input)) {
64             $this->updateChapterDefaultTemplate($chapter, intval($input['default_template_id']));
65         }
66
67         Activity::add(ActivityType::CHAPTER_UPDATE, $chapter);
68
69         return $chapter;
70     }
71
72     /**
73      * Remove a chapter from the system.
74      *
75      * @throws Exception
76      */
77     public function destroy(Chapter $chapter)
78     {
79         $trashCan = new TrashCan();
80         $trashCan->softDestroyChapter($chapter);
81         Activity::add(ActivityType::CHAPTER_DELETE, $chapter);
82         $trashCan->autoClearOld();
83     }
84
85     /**
86      * Move the given chapter into a new parent book.
87      * The $parentIdentifier must be a string of the following format:
88      * 'book:<id>' (book:5).
89      *
90      * @throws MoveOperationException
91      * @throws PermissionsException
92      */
93     public function move(Chapter $chapter, string $parentIdentifier): Book
94     {
95         $parent = $this->findParentByIdentifier($parentIdentifier);
96         if (is_null($parent)) {
97             throw new MoveOperationException('Book to move chapter into not found');
98         }
99
100         if (!userCan('chapter-create', $parent)) {
101             throw new PermissionsException('User does not have permission to create a chapter within the chosen book');
102         }
103
104         $chapter->changeBook($parent->id);
105         $chapter->rebuildPermissions();
106         Activity::add(ActivityType::CHAPTER_MOVE, $chapter);
107
108         return $parent;
109     }
110
111     /**
112      * Update the default page template used for this chapter.
113      * Checks that, if changing, the provided value is a valid template and the user
114      * has visibility of the provided page template id.
115      */
116     protected function updateChapterDefaultTemplate(Chapter $chapter, int $templateId): void
117     {
118         $changing = $templateId !== intval($chapter->default_template_id);
119         if (!$changing) {
120             return;
121         }
122
123         if ($templateId === 0) {
124             $chapter->default_template_id = null;
125             $chapter->save();
126             return;
127         }
128
129         $templateExists = Page::query()->visible()
130             ->where('template', '=', true)
131             ->where('id', '=', $templateId)
132             ->exists();
133
134         $chapter->default_template_id = $templateExists ? $templateId : null;
135         $chapter->save();
136     }
137
138     /**
139      * Find a page parent entity via an identifier string in the format:
140      * {type}:{id}
141      * Example: (book:5).
142      *
143      * @throws MoveOperationException
144      */
145     public function findParentByIdentifier(string $identifier): ?Book
146     {
147         $stringExploded = explode(':', $identifier);
148         $entityType = $stringExploded[0];
149         $entityId = intval($stringExploded[1]);
150
151         if ($entityType !== 'book') {
152             throw new MoveOperationException('Chapters can only be in books');
153         }
154
155         return Book::visible()->where('id', '=', $entityId)->first();
156     }
157 }