1 <?php namespace BookStack\Repos;
5 use BookStack\Exceptions\NotFoundException;
6 use BookStack\Services\RestrictionService;
7 use Illuminate\Support\Str;
14 protected $restrictionService;
17 * ChapterRepo constructor.
18 * @param Chapter $chapter
19 * @param RestrictionService $restrictionService
21 public function __construct(Chapter $chapter, RestrictionService $restrictionService)
23 $this->chapter = $chapter;
24 $this->restrictionService = $restrictionService;
28 * Base query for getting chapters, Takes restrictions into account.
31 private function chapterQuery()
33 return $this->restrictionService->enforceChapterRestrictions($this->chapter, 'view');
37 * Check if an id exists.
41 public function idExists($id)
43 return $this->chapterQuery()->where('id', '=', $id)->count() > 0;
47 * Get a chapter by a specific id.
51 public function getById($id)
53 return $this->chapterQuery()->findOrFail($id);
58 * @return \Illuminate\Database\Eloquent\Collection|static[]
60 public function getAll()
62 return $this->chapterQuery()->all();
66 * Get a chapter that has the given slug within the given book.
70 * @throws NotFoundException
72 public function getBySlug($slug, $bookId)
74 $chapter = $this->chapterQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
75 if ($chapter === null) throw new NotFoundException('Chapter not found');
80 * Get the child items for a chapter
81 * @param Chapter $chapter
83 public function getChildren(Chapter $chapter)
85 return $this->restrictionService->enforcePageRestrictions($chapter->pages())->get();
89 * Create a new chapter from request input.
93 public function newFromInput($input)
95 return $this->chapter->fill($input);
99 * Destroy a chapter and its relations by providing its slug.
100 * @param Chapter $chapter
102 public function destroy(Chapter $chapter)
104 if (count($chapter->pages) > 0) {
105 foreach ($chapter->pages as $page) {
106 $page->chapter_id = 0;
110 Activity::removeEntity($chapter);
111 $chapter->views()->delete();
112 $chapter->restrictions()->delete();
117 * Check if a chapter's slug exists.
120 * @param bool|false $currentId
123 public function doesSlugExist($slug, $bookId, $currentId = false)
125 $query = $this->chapter->where('slug', '=', $slug)->where('book_id', '=', $bookId);
127 $query = $query->where('id', '!=', $currentId);
129 return $query->count() > 0;
133 * Finds a suitable slug for the provided name.
134 * Checks database to prevent duplicate slugs.
137 * @param bool|false $currentId
140 public function findSuitableSlug($name, $bookId, $currentId = false)
142 $slug = Str::slug($name);
143 while ($this->doesSlugExist($slug, $bookId, $currentId)) {
144 $slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
150 * Get chapters by the given search term.
152 * @param array $whereTerms
154 * @param array $paginationAppends
157 public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
159 $terms = explode(' ', $term);
160 $chapters = $this->restrictionService->enforceChapterRestrictions($this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms))
161 ->paginate($count)->appends($paginationAppends);
162 $words = join('|', explode(' ', preg_quote(trim($term), '/')));
163 foreach ($chapters as $chapter) {
165 $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $chapter->getExcerpt(100));
166 $chapter->searchSnippet = $result;
172 * Changes the book relation of this chapter.
174 * @param Chapter $chapter
177 public function changeBook($bookId, Chapter $chapter)
179 $chapter->book_id = $bookId;
180 foreach ($chapter->activity as $activity) {
181 $activity->book_id = $bookId;
184 $chapter->slug = $this->findSuitableSlug($chapter->name, $bookId, $chapter->id);
190 * Updates pages restrictions from a request
194 public function updateRestrictionsFromRequest($request, $chapter)
196 // TODO - extract into shared repo
197 $chapter->restricted = $request->has('restricted') && $request->get('restricted') === 'true';
198 $chapter->restrictions()->delete();
199 if ($request->has('restrictions')) {
200 foreach($request->get('restrictions') as $roleId => $restrictions) {
201 foreach ($restrictions as $action => $value) {
202 $chapter->restrictions()->create([
203 'role_id' => $roleId,
204 'action' => strtolower($action)