Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
Read
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
3 / 3
6
100.00% covered (success)
100.00%
1 / 1
 read
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
4
 modifyReadQuery
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 afterRead
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\Enums\Http\HttpStatusCode;
8use Illuminate\Database\Eloquent\Builder;
9use Illuminate\Database\Eloquent\Model;
10use Illuminate\Http\JsonResponse;
11use Illuminate\Support\Str;
12use Psr\Http\Message\ResponseInterface;
13
14/**
15 * Provides the read (GET by ID) action for CRUD controllers.
16 *
17 * Retrieves a single model instance by its identifier field (configurable).
18 *
19 * @method string modelClassName() Returns the Eloquent model class name
20 * @method JsonResponse|ResponseInterface answerInvalidUuid(HttpStatusCode $code) Returns invalid UUID error response
21 * @method JsonResponse|ResponseInterface answerRecordNotFound(HttpStatusCode $code = HttpStatusCode::NOT_FOUND)
22 *         Returns not found error response
23 * @method JsonResponse|ResponseInterface answerSuccess(mixed $data, HttpStatusCode $code, array $meta = [])
24 *         Returns success response
25 */
26trait Read
27{
28    /**
29     * Retrieves a single record by its identifier field.
30     *
31     * @param string $id The identifier value of the record
32     * @param string|null $method Model serialization method (default from config or 'toArray')
33     * @return JsonResponse|ResponseInterface JSON response with the record data or error response
34     */
35    public function read(string $id, ?string $method = null): JsonResponse|ResponseInterface
36    {
37        $method = $method ?? config('devToolbelt.fast-crud.read.method', 'toArray');
38
39        $httpStatus = HttpStatusCode::from(
40            config('devToolbelt.fast-crud.read.http_status', HttpStatusCode::OK->value)
41        );
42
43        $validationHttpStatus = HttpStatusCode::from(
44            config('devToolbelt.fast-crud.global.validation.http_status', HttpStatusCode::BAD_REQUEST->value)
45        );
46
47        $findField = config('devToolbelt.fast-crud.read.find_field')
48            ?? config('devToolbelt.fast-crud.global.find_field', 'id');
49
50        $isUuid = config('devToolbelt.fast-crud.read.find_field_is_uuid')
51            ?? config('devToolbelt.fast-crud.global.find_field_is_uuid', false);
52
53        if ($isUuid && !Str::isUuid($id)) {
54            return $this->answerInvalidUuid($validationHttpStatus);
55        }
56
57        $modelName = $this->modelClassName();
58        $query = $modelName::query()->where($findField, $id);
59        $this->modifyReadQuery($query);
60
61        /** @var Model|null $record */
62        $record = $query->first();
63
64        if ($record === null) {
65            return $this->answerRecordNotFound();
66        }
67
68        $response = $this->answerSuccess(data: $record->{$method}(), code: $httpStatus);
69        $this->afterRead($record);
70
71        return $response;
72    }
73
74    /**
75     * Hook to modify the read query before execution.
76     *
77     * Override this method to add eager loading, additional conditions,
78     * or scopes to the query.
79     *
80     * @param Builder $query The query builder instance
81     *
82     * @example
83     * ```php
84     * protected function modifyReadQuery(Builder $query): void
85     * {
86     *     $query->with(['category', 'tags']);
87     * }
88     * ```
89     */
90    protected function modifyReadQuery(Builder $query): void
91    {
92    }
93
94    /**
95     * Hook called after the record has been read and response prepared.
96     *
97     * Override this method to perform post-read actions,
98     * such as logging, analytics, or cache warming.
99     *
100     * @param Model $record The model instance that was read
101     */
102    protected function afterRead(Model $record): void
103    {
104    }
105}