Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.33% covered (success)
93.33%
14 / 15
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
Search
93.33% covered (success)
93.33%
14 / 15
66.67% covered (warning)
66.67%
2 / 3
3.00
0.00% covered (danger)
0.00%
0 / 1
 search
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 modifySearchQuery
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 afterSearch
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace DevToolbelt\LaravelFastCrud\Actions;
6
7use DevToolbelt\LaravelFastCrud\Traits\Limitable;
8use DevToolbelt\LaravelFastCrud\Traits\Pageable;
9use DevToolbelt\LaravelFastCrud\Traits\Searchable;
10use DevToolbelt\LaravelFastCrud\Traits\Sortable;
11use Exception;
12use Illuminate\Database\Eloquent\Builder;
13use Illuminate\Http\JsonResponse;
14use Illuminate\Http\Request;
15use Psr\Http\Message\ResponseInterface;
16
17/**
18 * Provides the search/list (GET collection) action for CRUD controllers.
19 *
20 * Retrieves a paginated, filtered, and sorted list of model instances.
21 * Supports the following query parameters:
22 * - filter[column][operator]=value - Filter records (see SearchOperator enum)
23 * - sort=column,-desc_column - Sort by columns (prefix with - for DESC)
24 * - perPage=N - Items per page (default from config or 40)
25 * - skipPagination=true - Return all records without pagination
26 *
27 * @method string modelClassName() Returns the Eloquent model class name
28 * @method JsonResponse|ResponseInterface answerSuccess(array $data, array $meta = []) Returns success response
29 *
30 * @property array $data Paginated records data (from Pageable trait)
31 * @property array $paginationData Pagination metadata (from Pageable trait)
32 */
33trait Search
34{
35    use Searchable;
36    use Sortable;
37    use Limitable;
38    use Pageable;
39
40    /**
41     * Searches and returns a paginated list of records.
42     *
43     * @param Request $request The HTTP request with filter, sort, and pagination parameters
44     * @param string|null $method Model serialization method (default from config or 'toArray')
45     * @return JsonResponse|ResponseInterface JSON response with records and pagination metadata
46     *
47     * @throws Exception When an invalid search operator is provided
48     *
49     * @example
50     * ```
51     * GET /products?filter[name][like]=Samsung&filter[price][gte]=100&sort=-created_at&perPage=20
52     * ```
53     */
54    public function search(Request $request, ?string $method = null): JsonResponse|ResponseInterface
55    {
56        $method = $method ?? config('devToolbelt.fast-crud.search.method', 'toArray');
57        $defaultPerPage = config('devToolbelt.fast-crud.search.per_page', 40);
58        $perPage = (int) $request->input('perPage', $defaultPerPage);
59        $modelName = $this->modelClassName();
60        $query = $modelName::query();
61
62        $this->modifySearchQuery($query);
63        $this->processSearch($query, $request->get('filter', []));
64        $this->processSort($query, $request->input('sort', ''));
65
66        $this->buildPagination($query, $perPage, $method);
67        $this->afterSearch($this->data);
68
69        return $this->answerSuccess($this->data, meta: [
70            'pagination' => $this->paginationData
71        ]);
72    }
73
74    /**
75     * Hook to modify the search query before filters and sorting are applied.
76     *
77     * Override this method to add base conditions, eager loading,
78     * or scopes that should always be applied to search queries.
79     *
80     * @param Builder $query The query builder instance
81     *
82     * @example
83     * ```php
84     * protected function modifySearchQuery(Builder $query): void
85     * {
86     *     $query->with(['category', 'tags'])
87     *           ->where('is_active', true);
88     * }
89     * ```
90     */
91    protected function modifySearchQuery(Builder $query): void
92    {
93    }
94
95    /**
96     * Hook called after the search results have been fetched.
97     *
98     * Override this method to perform post-search actions,
99     * such as caching, analytics, or result transformation.
100     *
101     * @param array<int, array<string, mixed>> $data The search results array
102     */
103    protected function afterSearch(array $data): void
104    {
105    }
106}