1 <?php namespace BookStack\Repos;
6 use BookStack\Exceptions\NotFoundException;
7 use Illuminate\Support\Str;
10 class ChapterRepo extends EntityRepo
13 * Base query for getting chapters, Takes permissions into account.
16 private function chapterQuery()
18 return $this->permissionService->enforceChapterRestrictions($this->chapter, 'view');
22 * Check if an id exists.
26 public function idExists($id)
28 return $this->chapterQuery()->where('id', '=', $id)->count() > 0;
32 * Get a chapter by a specific id.
36 public function getById($id)
38 return $this->chapterQuery()->findOrFail($id);
43 * @return \Illuminate\Database\Eloquent\Collection|static[]
45 public function getAll()
47 return $this->chapterQuery()->all();
51 * Get a chapter that has the given slug within the given book.
55 * @throws NotFoundException
57 public function getBySlug($slug, $bookId)
59 $chapter = $this->chapterQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
60 if ($chapter === null) throw new NotFoundException('Chapter not found');
65 * Get the child items for a chapter
66 * @param Chapter $chapter
68 public function getChildren(Chapter $chapter)
70 $pages = $this->permissionService->enforcePageRestrictions($chapter->pages())->get();
71 // Sort items with drafts first then by priority.
72 return $pages->sortBy(function($child, $key) {
73 $score = $child->priority;
74 if ($child->draft) $score -= 100;
80 * Create a new chapter from request input.
85 public function createFromInput($input, Book $book)
87 $chapter = $this->chapter->newInstance($input);
88 $chapter->slug = $this->findSuitableSlug($chapter->name, $book->id);
89 $chapter->created_by = auth()->user()->id;
90 $chapter->updated_by = auth()->user()->id;
91 $chapter = $book->chapters()->save($chapter);
92 $this->permissionService->buildJointPermissionsForEntity($chapter);
97 * Destroy a chapter and its relations by providing its slug.
98 * @param Chapter $chapter
100 public function destroy(Chapter $chapter)
102 if (count($chapter->pages) > 0) {
103 foreach ($chapter->pages as $page) {
104 $page->chapter_id = 0;
108 Activity::removeEntity($chapter);
109 $chapter->views()->delete();
110 $chapter->permissions()->delete();
111 $this->permissionService->deleteJointPermissionsForEntity($chapter);
116 * Check if a chapter's slug exists.
119 * @param bool|false $currentId
122 public function doesSlugExist($slug, $bookId, $currentId = false)
124 $query = $this->chapter->where('slug', '=', $slug)->where('book_id', '=', $bookId);
126 $query = $query->where('id', '!=', $currentId);
128 return $query->count() > 0;
132 * Finds a suitable slug for the provided name.
133 * Checks database to prevent duplicate slugs.
136 * @param bool|false $currentId
139 public function findSuitableSlug($name, $bookId, $currentId = false)
141 $slug = Str::slug($name);
142 while ($this->doesSlugExist($slug, $bookId, $currentId)) {
143 $slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
149 * Get a new priority value for a new page to be added
150 * to the given chapter.
151 * @param Chapter $chapter
154 public function getNewPriority(Chapter $chapter)
156 $lastPage = $chapter->pages->last();
157 return $lastPage !== null ? $lastPage->priority + 1 : 0;
161 * Get chapters by the given search term.
162 * @param string $term
163 * @param array $whereTerms
165 * @param array $paginationAppends
168 public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
170 $terms = $this->prepareSearchTerms($term);
171 $chapters = $this->permissionService->enforceChapterRestrictions($this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms))
172 ->paginate($count)->appends($paginationAppends);
173 $words = join('|', explode(' ', preg_quote(trim($term), '/')));
174 foreach ($chapters as $chapter) {
176 $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $chapter->getExcerpt(100));
177 $chapter->searchSnippet = $result;
183 * Changes the book relation of this chapter.
185 * @param Chapter $chapter
188 public function changeBook($bookId, Chapter $chapter)
190 $chapter->book_id = $bookId;
191 foreach ($chapter->activity as $activity) {
192 $activity->book_id = $bookId;
195 $chapter->slug = $this->findSuitableSlug($chapter->name, $bookId, $chapter->id);