Showing
9 changed files
with
113 additions
and
229 deletions
| ... | @@ -4,6 +4,8 @@ | ... | @@ -4,6 +4,8 @@ |
| 4 | class Entity extends Ownable | 4 | class Entity extends Ownable |
| 5 | { | 5 | { |
| 6 | 6 | ||
| 7 | + protected $fieldsToSearch = ['name', 'description']; | ||
| 8 | + | ||
| 7 | /** | 9 | /** |
| 8 | * Compares this entity to another given entity. | 10 | * Compares this entity to another given entity. |
| 9 | * Matches by comparing class and id. | 11 | * Matches by comparing class and id. |
| ... | @@ -157,7 +159,7 @@ class Entity extends Ownable | ... | @@ -157,7 +159,7 @@ class Entity extends Ownable |
| 157 | * @param string[] array $wheres | 159 | * @param string[] array $wheres |
| 158 | * @return mixed | 160 | * @return mixed |
| 159 | */ | 161 | */ |
| 160 | - public function fullTextSearchQuery($fieldsToSearch, $terms, $wheres = []) | 162 | + public function fullTextSearchQuery($terms, $wheres = []) |
| 161 | { | 163 | { |
| 162 | $exactTerms = []; | 164 | $exactTerms = []; |
| 163 | $fuzzyTerms = []; | 165 | $fuzzyTerms = []; |
| ... | @@ -181,16 +183,16 @@ class Entity extends Ownable | ... | @@ -181,16 +183,16 @@ class Entity extends Ownable |
| 181 | // Perform fulltext search if relevant terms exist. | 183 | // Perform fulltext search if relevant terms exist. |
| 182 | if ($isFuzzy) { | 184 | if ($isFuzzy) { |
| 183 | $termString = implode(' ', $fuzzyTerms); | 185 | $termString = implode(' ', $fuzzyTerms); |
| 184 | - $fields = implode(',', $fieldsToSearch); | 186 | + $fields = implode(',', $this->fieldsToSearch); |
| 185 | $search = $search->selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]); | 187 | $search = $search->selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]); |
| 186 | $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]); | 188 | $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]); |
| 187 | } | 189 | } |
| 188 | 190 | ||
| 189 | // Ensure at least one exact term matches if in search | 191 | // Ensure at least one exact term matches if in search |
| 190 | if (count($exactTerms) > 0) { | 192 | if (count($exactTerms) > 0) { |
| 191 | - $search = $search->where(function ($query) use ($exactTerms, $fieldsToSearch) { | 193 | + $search = $search->where(function ($query) use ($exactTerms) { |
| 192 | foreach ($exactTerms as $exactTerm) { | 194 | foreach ($exactTerms as $exactTerm) { |
| 193 | - foreach ($fieldsToSearch as $field) { | 195 | + foreach ($this->fieldsToSearch as $field) { |
| 194 | $query->orWhere($field, 'like', $exactTerm); | 196 | $query->orWhere($field, 'like', $exactTerm); |
| 195 | } | 197 | } |
| 196 | } | 198 | } | ... | ... |
| ... | @@ -118,7 +118,7 @@ class ChapterController extends Controller | ... | @@ -118,7 +118,7 @@ class ChapterController extends Controller |
| 118 | $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); | 118 | $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); |
| 119 | $this->checkOwnablePermission('chapter-update', $chapter); | 119 | $this->checkOwnablePermission('chapter-update', $chapter); |
| 120 | if ($chapter->name !== $request->get('name')) { | 120 | if ($chapter->name !== $request->get('name')) { |
| 121 | - $chapter->slug = $this->chapterRepo->findSuitableSlug($request->get('name'), $chapter->book->id, $chapter->id); | 121 | + $chapter->slug = $this->entityRepo->findSuitableSlug('chapter', $request->get('name'), $chapter->id, $chapter->book->id); |
| 122 | } | 122 | } |
| 123 | $chapter->fill($request->all()); | 123 | $chapter->fill($request->all()); |
| 124 | $chapter->updated_by = user()->id; | 124 | $chapter->updated_by = user()->id; | ... | ... |
| ... | @@ -26,6 +26,7 @@ class PageController extends Controller | ... | @@ -26,6 +26,7 @@ class PageController extends Controller |
| 26 | 26 | ||
| 27 | /** | 27 | /** |
| 28 | * PageController constructor. | 28 | * PageController constructor. |
| 29 | + * @param EntityRepo $entityRepo | ||
| 29 | * @param PageRepo $pageRepo | 30 | * @param PageRepo $pageRepo |
| 30 | * @param BookRepo $bookRepo | 31 | * @param BookRepo $bookRepo |
| 31 | * @param ChapterRepo $chapterRepo | 32 | * @param ChapterRepo $chapterRepo | ... | ... |
| 1 | <?php namespace BookStack\Http\Controllers; | 1 | <?php namespace BookStack\Http\Controllers; |
| 2 | 2 | ||
| 3 | +use BookStack\Repos\EntityRepo; | ||
| 3 | use BookStack\Services\ViewService; | 4 | use BookStack\Services\ViewService; |
| 4 | use Illuminate\Http\Request; | 5 | use Illuminate\Http\Request; |
| 5 | -use BookStack\Repos\BookRepo; | ||
| 6 | -use BookStack\Repos\ChapterRepo; | ||
| 7 | -use BookStack\Repos\PageRepo; | ||
| 8 | 6 | ||
| 9 | class SearchController extends Controller | 7 | class SearchController extends Controller |
| 10 | { | 8 | { |
| 11 | - protected $pageRepo; | 9 | + protected $entityRepo; |
| 12 | - protected $bookRepo; | ||
| 13 | - protected $chapterRepo; | ||
| 14 | protected $viewService; | 10 | protected $viewService; |
| 15 | 11 | ||
| 16 | /** | 12 | /** |
| 17 | * SearchController constructor. | 13 | * SearchController constructor. |
| 18 | - * @param PageRepo $pageRepo | 14 | + * @param EntityRepo $entityRepo |
| 19 | - * @param BookRepo $bookRepo | ||
| 20 | - * @param ChapterRepo $chapterRepo | ||
| 21 | * @param ViewService $viewService | 15 | * @param ViewService $viewService |
| 22 | */ | 16 | */ |
| 23 | - public function __construct(PageRepo $pageRepo, BookRepo $bookRepo, ChapterRepo $chapterRepo, ViewService $viewService) | 17 | + public function __construct(EntityRepo $entityRepo, ViewService $viewService) |
| 24 | { | 18 | { |
| 25 | - $this->pageRepo = $pageRepo; | 19 | + $this->entityRepo = $entityRepo; |
| 26 | - $this->bookRepo = $bookRepo; | ||
| 27 | - $this->chapterRepo = $chapterRepo; | ||
| 28 | $this->viewService = $viewService; | 20 | $this->viewService = $viewService; |
| 29 | parent::__construct(); | 21 | parent::__construct(); |
| 30 | } | 22 | } |
| ... | @@ -42,9 +34,9 @@ class SearchController extends Controller | ... | @@ -42,9 +34,9 @@ class SearchController extends Controller |
| 42 | } | 34 | } |
| 43 | $searchTerm = $request->get('term'); | 35 | $searchTerm = $request->get('term'); |
| 44 | $paginationAppends = $request->only('term'); | 36 | $paginationAppends = $request->only('term'); |
| 45 | - $pages = $this->pageRepo->getBySearch($searchTerm, [], 20, $paginationAppends); | 37 | + $pages = $this->entityRepo->getBySearch('page', $searchTerm, [], 20, $paginationAppends); |
| 46 | - $books = $this->bookRepo->getBySearch($searchTerm, 10, $paginationAppends); | 38 | + $books = $this->entityRepo->getBySearch('book', $searchTerm, [], 10, $paginationAppends); |
| 47 | - $chapters = $this->chapterRepo->getBySearch($searchTerm, [], 10, $paginationAppends); | 39 | + $chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, [], 10, $paginationAppends); |
| 48 | $this->setPageTitle(trans('entities.search_for_term', ['term' => $searchTerm])); | 40 | $this->setPageTitle(trans('entities.search_for_term', ['term' => $searchTerm])); |
| 49 | return view('search/all', [ | 41 | return view('search/all', [ |
| 50 | 'pages' => $pages, | 42 | 'pages' => $pages, |
| ... | @@ -65,7 +57,7 @@ class SearchController extends Controller | ... | @@ -65,7 +57,7 @@ class SearchController extends Controller |
| 65 | 57 | ||
| 66 | $searchTerm = $request->get('term'); | 58 | $searchTerm = $request->get('term'); |
| 67 | $paginationAppends = $request->only('term'); | 59 | $paginationAppends = $request->only('term'); |
| 68 | - $pages = $this->pageRepo->getBySearch($searchTerm, [], 20, $paginationAppends); | 60 | + $pages = $this->entityRepo->getBySearch('page', $searchTerm, [], 20, $paginationAppends); |
| 69 | $this->setPageTitle(trans('entities.search_page_for_term', ['term' => $searchTerm])); | 61 | $this->setPageTitle(trans('entities.search_page_for_term', ['term' => $searchTerm])); |
| 70 | return view('search/entity-search-list', [ | 62 | return view('search/entity-search-list', [ |
| 71 | 'entities' => $pages, | 63 | 'entities' => $pages, |
| ... | @@ -85,7 +77,7 @@ class SearchController extends Controller | ... | @@ -85,7 +77,7 @@ class SearchController extends Controller |
| 85 | 77 | ||
| 86 | $searchTerm = $request->get('term'); | 78 | $searchTerm = $request->get('term'); |
| 87 | $paginationAppends = $request->only('term'); | 79 | $paginationAppends = $request->only('term'); |
| 88 | - $chapters = $this->chapterRepo->getBySearch($searchTerm, [], 20, $paginationAppends); | 80 | + $chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, [], 20, $paginationAppends); |
| 89 | $this->setPageTitle(trans('entities.search_chapter_for_term', ['term' => $searchTerm])); | 81 | $this->setPageTitle(trans('entities.search_chapter_for_term', ['term' => $searchTerm])); |
| 90 | return view('search/entity-search-list', [ | 82 | return view('search/entity-search-list', [ |
| 91 | 'entities' => $chapters, | 83 | 'entities' => $chapters, |
| ... | @@ -105,7 +97,7 @@ class SearchController extends Controller | ... | @@ -105,7 +97,7 @@ class SearchController extends Controller |
| 105 | 97 | ||
| 106 | $searchTerm = $request->get('term'); | 98 | $searchTerm = $request->get('term'); |
| 107 | $paginationAppends = $request->only('term'); | 99 | $paginationAppends = $request->only('term'); |
| 108 | - $books = $this->bookRepo->getBySearch($searchTerm, 20, $paginationAppends); | 100 | + $books = $this->entityRepo->getBySearch('book', $searchTerm, [], 20, $paginationAppends); |
| 109 | $this->setPageTitle(trans('entities.search_book_for_term', ['term' => $searchTerm])); | 101 | $this->setPageTitle(trans('entities.search_book_for_term', ['term' => $searchTerm])); |
| 110 | return view('search/entity-search-list', [ | 102 | return view('search/entity-search-list', [ |
| 111 | 'entities' => $books, | 103 | 'entities' => $books, |
| ... | @@ -128,8 +120,8 @@ class SearchController extends Controller | ... | @@ -128,8 +120,8 @@ class SearchController extends Controller |
| 128 | } | 120 | } |
| 129 | $searchTerm = $request->get('term'); | 121 | $searchTerm = $request->get('term'); |
| 130 | $searchWhereTerms = [['book_id', '=', $bookId]]; | 122 | $searchWhereTerms = [['book_id', '=', $bookId]]; |
| 131 | - $pages = $this->pageRepo->getBySearch($searchTerm, $searchWhereTerms); | 123 | + $pages = $this->entityRepo->getBySearch('page', $searchTerm, $searchWhereTerms); |
| 132 | - $chapters = $this->chapterRepo->getBySearch($searchTerm, $searchWhereTerms); | 124 | + $chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, $searchWhereTerms); |
| 133 | return view('search/book', ['pages' => $pages, 'chapters' => $chapters, 'searchTerm' => $searchTerm]); | 125 | return view('search/book', ['pages' => $pages, 'chapters' => $chapters, 'searchTerm' => $searchTerm]); |
| 134 | } | 126 | } |
| 135 | 127 | ||
| ... | @@ -148,9 +140,11 @@ class SearchController extends Controller | ... | @@ -148,9 +140,11 @@ class SearchController extends Controller |
| 148 | 140 | ||
| 149 | // Search for entities otherwise show most popular | 141 | // Search for entities otherwise show most popular |
| 150 | if ($searchTerm !== false) { | 142 | if ($searchTerm !== false) { |
| 151 | - if ($entityTypes->contains('page')) $entities = $entities->merge($this->pageRepo->getBySearch($searchTerm)->items()); | 143 | + foreach (['page', 'chapter', 'book'] as $entityType) { |
| 152 | - if ($entityTypes->contains('chapter')) $entities = $entities->merge($this->chapterRepo->getBySearch($searchTerm)->items()); | 144 | + if ($entityTypes->contains($entityType)) { |
| 153 | - if ($entityTypes->contains('book')) $entities = $entities->merge($this->bookRepo->getBySearch($searchTerm)->items()); | 145 | + $entities = $entities->merge($this->entityRepo->getBySearch($entityType, $searchTerm)->items()); |
| 146 | + } | ||
| 147 | + } | ||
| 154 | $entities = $entities->sortByDesc('title_relevance'); | 148 | $entities = $entities->sortByDesc('title_relevance'); |
| 155 | } else { | 149 | } else { |
| 156 | $entityNames = $entityTypes->map(function ($type) { | 150 | $entityNames = $entityTypes->map(function ($type) { | ... | ... |
| ... | @@ -9,6 +9,8 @@ class Page extends Entity | ... | @@ -9,6 +9,8 @@ class Page extends Entity |
| 9 | 9 | ||
| 10 | protected $with = ['book']; | 10 | protected $with = ['book']; |
| 11 | 11 | ||
| 12 | + protected $fieldsToSearch = ['name', 'text']; | ||
| 13 | + | ||
| 12 | /** | 14 | /** |
| 13 | * Converts this page into a simplified array. | 15 | * Converts this page into a simplified array. |
| 14 | * @return mixed | 16 | * @return mixed | ... | ... |
| ... | @@ -27,7 +27,7 @@ class BookRepo extends EntityRepo | ... | @@ -27,7 +27,7 @@ class BookRepo extends EntityRepo |
| 27 | public function createFromInput($input) | 27 | public function createFromInput($input) |
| 28 | { | 28 | { |
| 29 | $book = $this->book->newInstance($input); | 29 | $book = $this->book->newInstance($input); |
| 30 | - $book->slug = $this->findSuitableSlug($book->name); | 30 | + $book->slug = $this->findSuitableSlug('book', $book->name); |
| 31 | $book->created_by = user()->id; | 31 | $book->created_by = user()->id; |
| 32 | $book->updated_by = user()->id; | 32 | $book->updated_by = user()->id; |
| 33 | $book->save(); | 33 | $book->save(); |
| ... | @@ -44,7 +44,7 @@ class BookRepo extends EntityRepo | ... | @@ -44,7 +44,7 @@ class BookRepo extends EntityRepo |
| 44 | public function updateFromInput(Book $book, $input) | 44 | public function updateFromInput(Book $book, $input) |
| 45 | { | 45 | { |
| 46 | if ($book->name !== $input['name']) { | 46 | if ($book->name !== $input['name']) { |
| 47 | - $book->slug = $this->findSuitableSlug($input['name'], $book->id); | 47 | + $book->slug = $this->findSuitableSlug('book', $input['name'], $book->id); |
| 48 | } | 48 | } |
| 49 | $book->fill($input); | 49 | $book->fill($input); |
| 50 | $book->updated_by = user()->id; | 50 | $book->updated_by = user()->id; |
| ... | @@ -84,36 +84,6 @@ class BookRepo extends EntityRepo | ... | @@ -84,36 +84,6 @@ class BookRepo extends EntityRepo |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | /** | 86 | /** |
| 87 | - * @param string $slug | ||
| 88 | - * @param bool|false $currentId | ||
| 89 | - * @return bool | ||
| 90 | - */ | ||
| 91 | - public function doesSlugExist($slug, $currentId = false) | ||
| 92 | - { | ||
| 93 | - $query = $this->book->where('slug', '=', $slug); | ||
| 94 | - if ($currentId) { | ||
| 95 | - $query = $query->where('id', '!=', $currentId); | ||
| 96 | - } | ||
| 97 | - return $query->count() > 0; | ||
| 98 | - } | ||
| 99 | - | ||
| 100 | - /** | ||
| 101 | - * Provides a suitable slug for the given book name. | ||
| 102 | - * Ensures the returned slug is unique in the system. | ||
| 103 | - * @param string $name | ||
| 104 | - * @param bool|false $currentId | ||
| 105 | - * @return string | ||
| 106 | - */ | ||
| 107 | - public function findSuitableSlug($name, $currentId = false) | ||
| 108 | - { | ||
| 109 | - $slug = $this->nameToSlug($name); | ||
| 110 | - while ($this->doesSlugExist($slug, $currentId)) { | ||
| 111 | - $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); | ||
| 112 | - } | ||
| 113 | - return $slug; | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - /** | ||
| 117 | * Get all child objects of a book. | 87 | * Get all child objects of a book. |
| 118 | * Returns a sorted collection of Pages and Chapters. | 88 | * Returns a sorted collection of Pages and Chapters. |
| 119 | * Loads the book slug onto child elements to prevent access database access for getting the slug. | 89 | * Loads the book slug onto child elements to prevent access database access for getting the slug. |
| ... | @@ -166,26 +136,4 @@ class BookRepo extends EntityRepo | ... | @@ -166,26 +136,4 @@ class BookRepo extends EntityRepo |
| 166 | }); | 136 | }); |
| 167 | } | 137 | } |
| 168 | 138 | ||
| 169 | - /** | ||
| 170 | - * Get books by search term. | ||
| 171 | - * @param $term | ||
| 172 | - * @param int $count | ||
| 173 | - * @param array $paginationAppends | ||
| 174 | - * @return mixed | ||
| 175 | - */ | ||
| 176 | - public function getBySearch($term, $count = 20, $paginationAppends = []) | ||
| 177 | - { | ||
| 178 | - $terms = $this->prepareSearchTerms($term); | ||
| 179 | - $bookQuery = $this->permissionService->enforceBookRestrictions($this->book->fullTextSearchQuery(['name', 'description'], $terms)); | ||
| 180 | - $bookQuery = $this->addAdvancedSearchQueries($bookQuery, $term); | ||
| 181 | - $books = $bookQuery->paginate($count)->appends($paginationAppends); | ||
| 182 | - $words = join('|', explode(' ', preg_quote(trim($term), '/'))); | ||
| 183 | - foreach ($books as $book) { | ||
| 184 | - //highlight | ||
| 185 | - $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $book->getExcerpt(100)); | ||
| 186 | - $book->searchSnippet = $result; | ||
| 187 | - } | ||
| 188 | - return $books; | ||
| 189 | - } | ||
| 190 | - | ||
| 191 | } | 139 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -45,7 +45,7 @@ class ChapterRepo extends EntityRepo | ... | @@ -45,7 +45,7 @@ class ChapterRepo extends EntityRepo |
| 45 | public function createFromInput($input, Book $book) | 45 | public function createFromInput($input, Book $book) |
| 46 | { | 46 | { |
| 47 | $chapter = $this->chapter->newInstance($input); | 47 | $chapter = $this->chapter->newInstance($input); |
| 48 | - $chapter->slug = $this->findSuitableSlug($chapter->name, $book->id); | 48 | + $chapter->slug = $this->findSuitableSlug('chapter', $chapter->name, false, $book->id); |
| 49 | $chapter->created_by = user()->id; | 49 | $chapter->created_by = user()->id; |
| 50 | $chapter->updated_by = user()->id; | 50 | $chapter->updated_by = user()->id; |
| 51 | $chapter = $book->chapters()->save($chapter); | 51 | $chapter = $book->chapters()->save($chapter); |
| ... | @@ -72,38 +72,6 @@ class ChapterRepo extends EntityRepo | ... | @@ -72,38 +72,6 @@ class ChapterRepo extends EntityRepo |
| 72 | $chapter->delete(); | 72 | $chapter->delete(); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | - /** | ||
| 76 | - * Check if a chapter's slug exists. | ||
| 77 | - * @param $slug | ||
| 78 | - * @param $bookId | ||
| 79 | - * @param bool|false $currentId | ||
| 80 | - * @return bool | ||
| 81 | - */ | ||
| 82 | - public function doesSlugExist($slug, $bookId, $currentId = false) | ||
| 83 | - { | ||
| 84 | - $query = $this->chapter->where('slug', '=', $slug)->where('book_id', '=', $bookId); | ||
| 85 | - if ($currentId) { | ||
| 86 | - $query = $query->where('id', '!=', $currentId); | ||
| 87 | - } | ||
| 88 | - return $query->count() > 0; | ||
| 89 | - } | ||
| 90 | - | ||
| 91 | - /** | ||
| 92 | - * Finds a suitable slug for the provided name. | ||
| 93 | - * Checks database to prevent duplicate slugs. | ||
| 94 | - * @param $name | ||
| 95 | - * @param $bookId | ||
| 96 | - * @param bool|false $currentId | ||
| 97 | - * @return string | ||
| 98 | - */ | ||
| 99 | - public function findSuitableSlug($name, $bookId, $currentId = false) | ||
| 100 | - { | ||
| 101 | - $slug = $this->nameToSlug($name); | ||
| 102 | - while ($this->doesSlugExist($slug, $bookId, $currentId)) { | ||
| 103 | - $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); | ||
| 104 | - } | ||
| 105 | - return $slug; | ||
| 106 | - } | ||
| 107 | 75 | ||
| 108 | /** | 76 | /** |
| 109 | * Get a new priority value for a new page to be added | 77 | * Get a new priority value for a new page to be added |
| ... | @@ -118,29 +86,6 @@ class ChapterRepo extends EntityRepo | ... | @@ -118,29 +86,6 @@ class ChapterRepo extends EntityRepo |
| 118 | } | 86 | } |
| 119 | 87 | ||
| 120 | /** | 88 | /** |
| 121 | - * Get chapters by the given search term. | ||
| 122 | - * @param string $term | ||
| 123 | - * @param array $whereTerms | ||
| 124 | - * @param int $count | ||
| 125 | - * @param array $paginationAppends | ||
| 126 | - * @return mixed | ||
| 127 | - */ | ||
| 128 | - public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = []) | ||
| 129 | - { | ||
| 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) { | ||
| 136 | - //highlight | ||
| 137 | - $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $chapter->getExcerpt(100)); | ||
| 138 | - $chapter->searchSnippet = $result; | ||
| 139 | - } | ||
| 140 | - return $chapters; | ||
| 141 | - } | ||
| 142 | - | ||
| 143 | - /** | ||
| 144 | * Changes the book relation of this chapter. | 89 | * Changes the book relation of this chapter. |
| 145 | * @param $bookId | 90 | * @param $bookId |
| 146 | * @param Chapter $chapter | 91 | * @param Chapter $chapter |
| ... | @@ -155,7 +100,7 @@ class ChapterRepo extends EntityRepo | ... | @@ -155,7 +100,7 @@ class ChapterRepo extends EntityRepo |
| 155 | $activity->book_id = $bookId; | 100 | $activity->book_id = $bookId; |
| 156 | $activity->save(); | 101 | $activity->save(); |
| 157 | } | 102 | } |
| 158 | - $chapter->slug = $this->findSuitableSlug($chapter->name, $bookId, $chapter->id); | 103 | + $chapter->slug = $this->findSuitableSlug('chapter', $chapter->name, $chapter->id, $bookId); |
| 159 | $chapter->save(); | 104 | $chapter->save(); |
| 160 | // Update all child pages | 105 | // Update all child pages |
| 161 | foreach ($chapter->pages as $page) { | 106 | foreach ($chapter->pages as $page) { | ... | ... |
| ... | @@ -238,6 +238,83 @@ class EntityRepo | ... | @@ -238,6 +238,83 @@ class EntityRepo |
| 238 | ->skip($count * $page)->take($count)->get(); | 238 | ->skip($count * $page)->take($count)->get(); |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | + public function getBySearch($type, $term, $whereTerms = [], $count = 20, $paginationAppends = []) | ||
| 242 | + { | ||
| 243 | + $terms = $this->prepareSearchTerms($term); | ||
| 244 | + $q = $this->permissionService->enforceChapterRestrictions($this->getEntity($type)->fullTextSearchQuery($terms, $whereTerms)); | ||
| 245 | + $q = $this->addAdvancedSearchQueries($q, $term); | ||
| 246 | + $entities = $q->paginate($count)->appends($paginationAppends); | ||
| 247 | + $words = join('|', explode(' ', preg_quote(trim($term), '/'))); | ||
| 248 | + | ||
| 249 | + // Highlight page content | ||
| 250 | + if ($type === 'page') { | ||
| 251 | + //lookahead/behind assertions ensures cut between words | ||
| 252 | + $s = '\s\x00-/:-@\[-`{-~'; //character set for start/end of words | ||
| 253 | + | ||
| 254 | + foreach ($entities as $page) { | ||
| 255 | + preg_match_all('#(?<=[' . $s . ']).{1,30}((' . $words . ').{1,30})+(?=[' . $s . '])#uis', $page->text, $matches, PREG_SET_ORDER); | ||
| 256 | + //delimiter between occurrences | ||
| 257 | + $results = []; | ||
| 258 | + foreach ($matches as $line) { | ||
| 259 | + $results[] = htmlspecialchars($line[0], 0, 'UTF-8'); | ||
| 260 | + } | ||
| 261 | + $matchLimit = 6; | ||
| 262 | + if (count($results) > $matchLimit) $results = array_slice($results, 0, $matchLimit); | ||
| 263 | + $result = join('... ', $results); | ||
| 264 | + | ||
| 265 | + //highlight | ||
| 266 | + $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $result); | ||
| 267 | + if (strlen($result) < 5) $result = $page->getExcerpt(80); | ||
| 268 | + | ||
| 269 | + $page->searchSnippet = $result; | ||
| 270 | + } | ||
| 271 | + return $entities; | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + // Highlight chapter/book content | ||
| 275 | + foreach ($entities as $entity) { | ||
| 276 | + //highlight | ||
| 277 | + $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $entity->getExcerpt(100)); | ||
| 278 | + $entity->searchSnippet = $result; | ||
| 279 | + } | ||
| 280 | + return $entities; | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + /** | ||
| 284 | + * Find a suitable slug for an entity. | ||
| 285 | + * @param string $type | ||
| 286 | + * @param string $name | ||
| 287 | + * @param bool|integer $currentId | ||
| 288 | + * @param bool|integer $bookId Only pass if type is not a book | ||
| 289 | + * @return string | ||
| 290 | + */ | ||
| 291 | + public function findSuitableSlug($type, $name, $currentId = false, $bookId = false) | ||
| 292 | + { | ||
| 293 | + $slug = $this->nameToSlug($name); | ||
| 294 | + while ($this->slugExists($type, $slug, $currentId, $bookId)) { | ||
| 295 | + $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); | ||
| 296 | + } | ||
| 297 | + return $slug; | ||
| 298 | + } | ||
| 299 | + | ||
| 300 | + /** | ||
| 301 | + * Check if a slug already exists in the database. | ||
| 302 | + * @param string $type | ||
| 303 | + * @param string $slug | ||
| 304 | + * @param bool|integer $currentId | ||
| 305 | + * @param bool|integer $bookId | ||
| 306 | + * @return bool | ||
| 307 | + */ | ||
| 308 | + protected function slugExists($type, $slug, $currentId = false, $bookId = false) | ||
| 309 | + { | ||
| 310 | + $query = $this->getEntity($type)->where('slug', '=', $slug); | ||
| 311 | + if (strtolower($type) === 'page' || strtolower($type) === 'chapter') { | ||
| 312 | + $query = $query->where('book_id', '=', $bookId); | ||
| 313 | + } | ||
| 314 | + if ($currentId) $query = $query->where('id', '!=', $currentId); | ||
| 315 | + return $query->count() > 0; | ||
| 316 | + } | ||
| 317 | + | ||
| 241 | /** | 318 | /** |
| 242 | * Updates entity restrictions from a request | 319 | * Updates entity restrictions from a request |
| 243 | * @param $request | 320 | * @param $request | ... | ... |
| ... | @@ -66,17 +66,6 @@ class PageRepo extends EntityRepo | ... | @@ -66,17 +66,6 @@ class PageRepo extends EntityRepo |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | /** | 68 | /** |
| 69 | - * Get a new Page instance from the given input. | ||
| 70 | - * @param $input | ||
| 71 | - * @return Page | ||
| 72 | - */ | ||
| 73 | - public function newFromInput($input) | ||
| 74 | - { | ||
| 75 | - $page = $this->page->fill($input); | ||
| 76 | - return $page; | ||
| 77 | - } | ||
| 78 | - | ||
| 79 | - /** | ||
| 80 | * Count the pages with a particular slug within a book. | 69 | * Count the pages with a particular slug within a book. |
| 81 | * @param $slug | 70 | * @param $slug |
| 82 | * @param $bookId | 71 | * @param $bookId |
| ... | @@ -103,7 +92,7 @@ class PageRepo extends EntityRepo | ... | @@ -103,7 +92,7 @@ class PageRepo extends EntityRepo |
| 103 | $this->tagRepo->saveTagsToEntity($draftPage, $input['tags']); | 92 | $this->tagRepo->saveTagsToEntity($draftPage, $input['tags']); |
| 104 | } | 93 | } |
| 105 | 94 | ||
| 106 | - $draftPage->slug = $this->findSuitableSlug($draftPage->name, $draftPage->book->id); | 95 | + $draftPage->slug = $this->findSuitableSlug('page', $draftPage->name, false, $draftPage->book->id); |
| 107 | $draftPage->html = $this->formatHtml($input['html']); | 96 | $draftPage->html = $this->formatHtml($input['html']); |
| 108 | $draftPage->text = strip_tags($draftPage->html); | 97 | $draftPage->text = strip_tags($draftPage->html); |
| 109 | $draftPage->draft = false; | 98 | $draftPage->draft = false; |
| ... | @@ -223,50 +212,6 @@ class PageRepo extends EntityRepo | ... | @@ -223,50 +212,6 @@ class PageRepo extends EntityRepo |
| 223 | 212 | ||
| 224 | 213 | ||
| 225 | /** | 214 | /** |
| 226 | - * Gets pages by a search term. | ||
| 227 | - * Highlights page content for showing in results. | ||
| 228 | - * @param string $term | ||
| 229 | - * @param array $whereTerms | ||
| 230 | - * @param int $count | ||
| 231 | - * @param array $paginationAppends | ||
| 232 | - * @return mixed | ||
| 233 | - */ | ||
| 234 | - public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = []) | ||
| 235 | - { | ||
| 236 | - $terms = $this->prepareSearchTerms($term); | ||
| 237 | - $pageQuery = $this->permissionService->enforcePageRestrictions($this->page->fullTextSearchQuery(['name', 'text'], $terms, $whereTerms)); | ||
| 238 | - $pageQuery = $this->addAdvancedSearchQueries($pageQuery, $term); | ||
| 239 | - $pages = $pageQuery->paginate($count)->appends($paginationAppends); | ||
| 240 | - | ||
| 241 | - // Add highlights to page text. | ||
| 242 | - $words = join('|', explode(' ', preg_quote(trim($term), '/'))); | ||
| 243 | - //lookahead/behind assertions ensures cut between words | ||
| 244 | - $s = '\s\x00-/:-@\[-`{-~'; //character set for start/end of words | ||
| 245 | - | ||
| 246 | - foreach ($pages as $page) { | ||
| 247 | - preg_match_all('#(?<=[' . $s . ']).{1,30}((' . $words . ').{1,30})+(?=[' . $s . '])#uis', $page->text, $matches, PREG_SET_ORDER); | ||
| 248 | - //delimiter between occurrences | ||
| 249 | - $results = []; | ||
| 250 | - foreach ($matches as $line) { | ||
| 251 | - $results[] = htmlspecialchars($line[0], 0, 'UTF-8'); | ||
| 252 | - } | ||
| 253 | - $matchLimit = 6; | ||
| 254 | - if (count($results) > $matchLimit) { | ||
| 255 | - $results = array_slice($results, 0, $matchLimit); | ||
| 256 | - } | ||
| 257 | - $result = join('... ', $results); | ||
| 258 | - | ||
| 259 | - //highlight | ||
| 260 | - $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $result); | ||
| 261 | - if (strlen($result) < 5) { | ||
| 262 | - $result = $page->getExcerpt(80); | ||
| 263 | - } | ||
| 264 | - $page->searchSnippet = $result; | ||
| 265 | - } | ||
| 266 | - return $pages; | ||
| 267 | - } | ||
| 268 | - | ||
| 269 | - /** | ||
| 270 | * Search for image usage. | 215 | * Search for image usage. |
| 271 | * @param $imageString | 216 | * @param $imageString |
| 272 | * @return mixed | 217 | * @return mixed |
| ... | @@ -297,7 +242,7 @@ class PageRepo extends EntityRepo | ... | @@ -297,7 +242,7 @@ class PageRepo extends EntityRepo |
| 297 | 242 | ||
| 298 | // Prevent slug being updated if no name change | 243 | // Prevent slug being updated if no name change |
| 299 | if ($page->name !== $input['name']) { | 244 | if ($page->name !== $input['name']) { |
| 300 | - $page->slug = $this->findSuitableSlug($input['name'], $book_id, $page->id); | 245 | + $page->slug = $this->findSuitableSlug('page', $input['name'], $page->id, $book_id); |
| 301 | } | 246 | } |
| 302 | 247 | ||
| 303 | // Save page tags if present | 248 | // Save page tags if present |
| ... | @@ -337,7 +282,7 @@ class PageRepo extends EntityRepo | ... | @@ -337,7 +282,7 @@ class PageRepo extends EntityRepo |
| 337 | $this->saveRevision($page); | 282 | $this->saveRevision($page); |
| 338 | $revision = $this->getRevisionById($revisionId); | 283 | $revision = $this->getRevisionById($revisionId); |
| 339 | $page->fill($revision->toArray()); | 284 | $page->fill($revision->toArray()); |
| 340 | - $page->slug = $this->findSuitableSlug($page->name, $book->id, $page->id); | 285 | + $page->slug = $this->findSuitableSlug('page', $page->name, $page->id, $book->id); |
| 341 | $page->text = strip_tags($page->html); | 286 | $page->text = strip_tags($page->html); |
| 342 | $page->updated_by = user()->id; | 287 | $page->updated_by = user()->id; |
| 343 | $page->save(); | 288 | $page->save(); |
| ... | @@ -530,20 +475,6 @@ class PageRepo extends EntityRepo | ... | @@ -530,20 +475,6 @@ class PageRepo extends EntityRepo |
| 530 | } | 475 | } |
| 531 | 476 | ||
| 532 | /** | 477 | /** |
| 533 | - * Checks if a slug exists within a book already. | ||
| 534 | - * @param $slug | ||
| 535 | - * @param $bookId | ||
| 536 | - * @param bool|false $currentId | ||
| 537 | - * @return bool | ||
| 538 | - */ | ||
| 539 | - public function doesSlugExist($slug, $bookId, $currentId = false) | ||
| 540 | - { | ||
| 541 | - $query = $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId); | ||
| 542 | - if ($currentId) $query = $query->where('id', '!=', $currentId); | ||
| 543 | - return $query->count() > 0; | ||
| 544 | - } | ||
| 545 | - | ||
| 546 | - /** | ||
| 547 | * Changes the related book for the specified page. | 478 | * Changes the related book for the specified page. |
| 548 | * Changes the book id of any relations to the page that store the book id. | 479 | * Changes the book id of any relations to the page that store the book id. |
| 549 | * @param int $bookId | 480 | * @param int $bookId |
| ... | @@ -557,7 +488,7 @@ class PageRepo extends EntityRepo | ... | @@ -557,7 +488,7 @@ class PageRepo extends EntityRepo |
| 557 | $activity->book_id = $bookId; | 488 | $activity->book_id = $bookId; |
| 558 | $activity->save(); | 489 | $activity->save(); |
| 559 | } | 490 | } |
| 560 | - $page->slug = $this->findSuitableSlug($page->name, $bookId, $page->id); | 491 | + $page->slug = $this->findSuitableSlug('page', $page->name, $page->id, $bookId); |
| 561 | $page->save(); | 492 | $page->save(); |
| 562 | return $page; | 493 | return $page; |
| 563 | } | 494 | } |
| ... | @@ -579,22 +510,6 @@ class PageRepo extends EntityRepo | ... | @@ -579,22 +510,6 @@ class PageRepo extends EntityRepo |
| 579 | } | 510 | } |
| 580 | 511 | ||
| 581 | /** | 512 | /** |
| 582 | - * Gets a suitable slug for the resource | ||
| 583 | - * @param string $name | ||
| 584 | - * @param int $bookId | ||
| 585 | - * @param bool|false $currentId | ||
| 586 | - * @return string | ||
| 587 | - */ | ||
| 588 | - public function findSuitableSlug($name, $bookId, $currentId = false) | ||
| 589 | - { | ||
| 590 | - $slug = $this->nameToSlug($name); | ||
| 591 | - while ($this->doesSlugExist($slug, $bookId, $currentId)) { | ||
| 592 | - $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); | ||
| 593 | - } | ||
| 594 | - return $slug; | ||
| 595 | - } | ||
| 596 | - | ||
| 597 | - /** | ||
| 598 | * Destroy a given page along with its dependencies. | 513 | * Destroy a given page along with its dependencies. |
| 599 | * @param $page | 514 | * @param $page |
| 600 | */ | 515 | */ | ... | ... |
-
Please register or sign in to post a comment