]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/Api/SearchApiController.php
bf59ec67162f1a264c59a734ba9c33634f5d15bf
[bookstack] / app / Http / Controllers / Api / SearchApiController.php
1 <?php
2
3 namespace BookStack\Http\Controllers\Api;
4
5 use BookStack\Api\ApiEntityListFormatter;
6 use BookStack\Entities\Models\Entity;
7 use BookStack\Search\SearchOptions;
8 use BookStack\Search\SearchResultsFormatter;
9 use BookStack\Search\SearchRunner;
10 use Illuminate\Http\Request;
11
12 class SearchApiController extends ApiController
13 {
14     protected SearchRunner $searchRunner;
15     protected SearchResultsFormatter $resultsFormatter;
16
17     protected $rules = [
18         'all' => [
19             'query'  => ['required'],
20             'page'   => ['integer', 'min:1'],
21             'count'  => ['integer', 'min:1', 'max:100'],
22         ],
23     ];
24
25     public function __construct(SearchRunner $searchRunner, SearchResultsFormatter $resultsFormatter)
26     {
27         $this->searchRunner = $searchRunner;
28         $this->resultsFormatter = $resultsFormatter;
29     }
30
31     /**
32      * Run a search query against all main content types (shelves, books, chapters & pages)
33      * in the system. Takes the same input as the main search bar within the BookStack
34      * interface as a 'query' parameter. See https://www.bookstackapp.com/docs/user/searching/
35      * for a full list of search term options. Results contain a 'type' property to distinguish
36      * between: bookshelf, book, chapter & page.
37      *
38      * The paging parameters and response format emulates a standard listing endpoint
39      * but standard sorting and filtering cannot be done on this endpoint. If a count value
40      * is provided this will only be taken as a suggestion. The results in the response
41      * may currently be up to 4x this value.
42      */
43     public function all(Request $request)
44     {
45         $this->validate($request, $this->rules['all']);
46
47         $options = SearchOptions::fromString($request->get('query') ?? '');
48         $page = intval($request->get('page', '0')) ?: 1;
49         $count = min(intval($request->get('count', '0')) ?: 20, 100);
50
51         $results = $this->searchRunner->searchEntities($options, 'all', $page, $count);
52         $this->resultsFormatter->format($results['results']->all(), $options);
53
54         $data = (new ApiEntityListFormatter($results['results']->all()))
55             ->withType()->withTags()
56             ->withField('preview_html', function (Entity $entity) {
57                 return [
58                     'name'    => (string) $entity->getAttribute('preview_name'),
59                     'content' => (string) $entity->getAttribute('preview_content'),
60                 ];
61             })->format();
62
63         return response()->json([
64             'data'  => $data,
65             'total' => $results['total'],
66         ]);
67     }
68 }