1 <?php namespace BookStack\Repos;
6 use BookStack\Exceptions\NotFoundException;
7 use Illuminate\Support\Str;
10 class ChapterRepo extends EntityRepo
15 * ChapterRepo constructor.
18 public function __construct(PageRepo $pageRepo)
20 $this->pageRepo = $pageRepo;
21 parent::__construct();
25 * Get the child items for a chapter
26 * @param Chapter $chapter
28 public function getChildren(Chapter $chapter)
30 $pages = $this->permissionService->enforcePageRestrictions($chapter->pages())->get();
31 // Sort items with drafts first then by priority.
32 return $pages->sortBy(function ($child, $key) {
33 $score = $child->priority;
34 if ($child->draft) $score -= 100;
40 * Create a new chapter from request input.
45 public function createFromInput($input, Book $book)
47 $chapter = $this->chapter->newInstance($input);
48 $chapter->slug = $this->findSuitableSlug($chapter->name, $book->id);
49 $chapter->created_by = user()->id;
50 $chapter->updated_by = user()->id;
51 $chapter = $book->chapters()->save($chapter);
52 $this->permissionService->buildJointPermissionsForEntity($chapter);
57 * Destroy a chapter and its relations by providing its slug.
58 * @param Chapter $chapter
60 public function destroy(Chapter $chapter)
62 if (count($chapter->pages) > 0) {
63 foreach ($chapter->pages as $page) {
64 $page->chapter_id = 0;
68 Activity::removeEntity($chapter);
69 $chapter->views()->delete();
70 $chapter->permissions()->delete();
71 $this->permissionService->deleteJointPermissionsForEntity($chapter);
76 * Check if a chapter's slug exists.
79 * @param bool|false $currentId
82 public function doesSlugExist($slug, $bookId, $currentId = false)
84 $query = $this->chapter->where('slug', '=', $slug)->where('book_id', '=', $bookId);
86 $query = $query->where('id', '!=', $currentId);
88 return $query->count() > 0;
92 * Finds a suitable slug for the provided name.
93 * Checks database to prevent duplicate slugs.
96 * @param bool|false $currentId
99 public function findSuitableSlug($name, $bookId, $currentId = false)
101 $slug = $this->nameToSlug($name);
102 while ($this->doesSlugExist($slug, $bookId, $currentId)) {
103 $slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
109 * Get a new priority value for a new page to be added
110 * to the given chapter.
111 * @param Chapter $chapter
114 public function getNewPriority(Chapter $chapter)
116 $lastPage = $chapter->pages->last();
117 return $lastPage !== null ? $lastPage->priority + 1 : 0;
121 * Get chapters by the given search term.
122 * @param string $term
123 * @param array $whereTerms
125 * @param array $paginationAppends
128 public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
130 $terms = $this->prepareSearchTerms($term);
131 $chapterQuery = $this->permissionService->enforceChapterRestrictions($this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms));
132 $chapterQuery = $this->addAdvancedSearchQueries($chapterQuery, $term);
133 $chapters = $chapterQuery->paginate($count)->appends($paginationAppends);
134 $words = join('|', explode(' ', preg_quote(trim($term), '/')));
135 foreach ($chapters as $chapter) {
137 $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $chapter->getExcerpt(100));
138 $chapter->searchSnippet = $result;
144 * Changes the book relation of this chapter.
146 * @param Chapter $chapter
147 * @param bool $rebuildPermissions
150 public function changeBook($bookId, Chapter $chapter, $rebuildPermissions = false)
152 $chapter->book_id = $bookId;
153 // Update related activity
154 foreach ($chapter->activity as $activity) {
155 $activity->book_id = $bookId;
158 $chapter->slug = $this->findSuitableSlug($chapter->name, $bookId, $chapter->id);
160 // Update all child pages
161 foreach ($chapter->pages as $page) {
162 $this->pageRepo->changeBook($bookId, $page);
165 // Update permissions if applicable
166 if ($rebuildPermissions) {
167 $chapter->load('book');
168 $this->permissionService->buildJointPermissionsForEntity($chapter->book);