Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
Options
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
3 / 3
5
100.00% covered (success)
100.00%
1 / 1
 options
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
3
 modifyOptionsQuery
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 afterOptions
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 Illuminate\Database\Eloquent\Builder;
8use Illuminate\Database\Eloquent\Model;
9use Illuminate\Http\JsonResponse;
10use Illuminate\Http\Request;
11use Psr\Http\Message\ResponseInterface;
12
13/**
14 * Provides the options (GET /options) action for CRUD controllers.
15 *
16 * Returns a list of label-value pairs suitable for populating select dropdowns
17 * or autocomplete fields in frontend applications.
18 *
19 * Query parameters:
20 * - label (required) - The column name to use as the display label
21 * - value (optional) - The column name to use as the value (default: external_id)
22 *
23 * @method string modelClassName() Returns the Eloquent model class name
24 * @method JsonResponse|ResponseInterface answerRequired(string $field) Returns required field error response
25 * @method JsonResponse|ResponseInterface answerColumnNotFound(string $field) Returns column not found error response
26 * @method JsonResponse|ResponseInterface answerSuccess(array $data, array $meta = []) Returns success response
27 */
28trait Options
29{
30    /**
31     * Returns a list of label-value pairs for select dropdowns.
32     *
33     * @param Request $request The HTTP request with label and optional value parameters
34     * @return JsonResponse|ResponseInterface JSON response with array of {label, value} objects
35     *
36     * @example
37     * ```
38     * GET /products/options?label=name
39     * GET /categories/options?label=title&value=slug
40     * ```
41     */
42    public function options(Request $request): JsonResponse|ResponseInterface
43    {
44        $defaultValue = config('devToolbelt.fast-crud.options.default_value', 'id');
45        $value = $request->get('value', $defaultValue);
46        $label = $request->get('label');
47
48        if ($label === null) {
49            return $this->answerRequired('label');
50        }
51
52        $modelName = $this->modelClassName();
53
54        /** @var Model $model */
55        $model = new $modelName();
56
57        if (!$this->hasModelAttribute($model, $label)) {
58            return $this->answerColumnNotFound($label);
59        }
60
61        $query = $model->newQuery()
62            ->select([$value . ' as value', $label . ' as label'])
63            ->orderBy($label, 'ASC');
64
65        $this->modifyOptionsQuery($query);
66
67        $records = $query->get()->toArray();
68
69        $rows = array_map(static fn(array $record): array => [
70            'label' => $record['label'],
71            'value' => $record['value'],
72        ], $records);
73
74        $this->afterOptions($rows);
75
76        return $this->answerSuccess($rows);
77    }
78
79    /**
80     * Hook to modify the options query before execution.
81     *
82     * Override this method to add conditions, such as filtering
83     * only active records or scoping to a specific user.
84     *
85     * @param Builder $query The query builder instance
86     *
87     * @example
88     * ```php
89     * protected function modifyOptionsQuery(Builder $query): void
90     * {
91     *     $query->where('is_active', true);
92     * }
93     * ```
94     */
95    protected function modifyOptionsQuery(Builder $query): void
96    {
97    }
98
99    /**
100     * Hook called after the options have been fetched and formatted.
101     *
102     * Override this method to perform post-fetch actions,
103     * such as caching or modifying the results.
104     *
105     * @param array<int, array{label: mixed, value: mixed}> $rows The formatted options array
106     */
107    protected function afterOptions(array $rows): void
108    {
109    }
110}