Completed
Push — develop ( ffa447...291184 )
by Alex
02:11
created

JsonApiController::updateAction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 7
rs 9.4285
cc 2
eloc 4
nc 2
nop 2
1
<?php
2
3
namespace Huntie\JsonApi\Http\Controllers;
4
5
use Huntie\JsonApi\Http\JsonApiResponse;
6
use Huntie\JsonApi\Support\JsonApiErrors;
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Http\Request;
9
use Illuminate\Http\Response;
10
use Illuminate\Routing\Controller;
11
12
abstract class JsonApiController extends Controller
13
{
14
    use JsonApiErrors;
15
16
    /**
17
     * Return the Eloquent Model for the resource.
18
     *
19
     * @return Model
20
     */
21
    abstract protected function getModel();
22
23
    /**
24
     * Return the type name of the resource.
25
     *
26
     * @return string
27
     */
28
    protected function getModelType()
29
    {
30
        return $this->getModel()->getTable();
31
    }
32
33
    /**
34
     * Return a listing of the resource.
35
     *
36
     * @param Request $request
37
     *
38
     * @return JsonApiResponse
39
     */
40
    public function indexAction(Request $request)
41
    {
42
        $records = $this->getModel()->all();
43
        $params = $this->getRequestParameters($request);
44
45
        return new JsonApiResponse($this->transformCollection($records, $params['fields']));
46
    }
47
48
    /**
49
     * Store a new record.
50
     *
51
     * @param Request $request
52
     *
53
     * @return JsonApiResponse
54
     */
55
    public function storeAction(Request $request)
56
    {
57
        $record = $this->getModel()->create($request->input('data.attributes'));
0 ignored issues
show
Bug introduced by
It seems like $request->input('data.attributes') targeting Illuminate\Http\Request::input() can also be of type string; however, Illuminate\Database\Eloquent\Model::create() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
58
59
        return new JsonApiResponse($this->transformRecord($record), Response::HTTP_CREATED);
60
    }
61
62
    /**
63
     * Return a specified record.
64
     *
65
     * @param Request   $request
66
     * @param Model|int $record
67
     *
68
     * @return JsonApiResponse
69
     */
70
    public function showAction(Request $request, $record)
71
    {
72
        $record = $record instanceof Model ? $record : $this->findModelInstance($record);
73
        $params = $this->getRequestParameters($request);
74
75
        return new JsonApiResponse($this->transformRecord($record, $params['fields'], $params['include']));
76
    }
77
78
    /**
79
     * Update a specified record.
80
     *
81
     * @param Request   $request
82
     * @param Model|int $record
83
     *
84
     * @return JsonApiResponse
85
     */
86
    public function updateAction(Request $request, $record)
87
    {
88
        $record = $record instanceof Model ? $record : $this->findModelInstance($record);
89
        $record->update($request->input('data.attributes'));
0 ignored issues
show
Bug introduced by
It seems like $request->input('data.attributes') targeting Illuminate\Http\Request::input() can also be of type string; however, Illuminate\Database\Eloquent\Model::update() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
90
91
        return $this->showAction($request, $record);
92
    }
93
94
    /**
95
     * Destroy a specified record.
96
     *
97
     * @param Request   $request
98
     * @param Model|int $record
99
     *
100
     * @return JsonApiResponse
101
     */
102
    public function destroyAction(Request $request, $record)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
103
    {
104
        $record = $record instanceof Model ? $record : $this->findModelInstance($record);
105
        $record->delete();
106
107
        return new JsonApiResponse(null, Response::HTTP_NO_CONTENT);
108
    }
109
110
    /**
111
     * Return an instance of the resource by primary key.
112
     *
113
     * @param int $key
114
     *
115
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
116
     *
117
     * @return Model
118
     */
119
    protected function findModelInstance($key)
120
    {
121
        return $this->getModel()->findOrFail($key);
122
    }
123
124
    /**
125
     * Return any JSON API resource parameters from a request.
126
     *
127
     * @param Request $request
128
     *
129
     * @return array
130
     */
131
    protected function getRequestParameters($request)
132
    {
133
        return [
134
            'fields' => $this->getRequestQuerySet($request, 'fields.' . $this->getModelType()),
135
            'include' => $this->getRequestQuerySet($request, 'include'),
136
        ];
137
    }
138
139
    /**
140
     * Return any comma separated values in a request query field as an array.
141
     *
142
     * @param Request $request
143
     * @param string  $key
144
     *
145
     * @return array
146
     */
147
    protected function getRequestQuerySet($request, $key)
148
    {
149
        return preg_split('/,/', $request->input($key), null, PREG_SPLIT_NO_EMPTY);
150
    }
151
152
    /**
153
     * Transform a set of models into a JSON API collection.
154
     *
155
     * @param \Illuminate\Support\Collection $records
156
     * @param array                          $fields
157
     *
158
     * @return array
159
     */
160
    protected function transformCollection($records, array $fields = [])
161
    {
162
        $data = [];
163
164
        foreach ($records as $record) {
165
            $data[] = $this->transformRecord($record, $fields)['data'];
166
        }
167
168
        return compact('data');
169
    }
170
171
    /**
172
     * Transform a model instance into a JSON API object.
173
     *
174
     * @param Model      $record
175
     * @param array|null $fields  Field names of attributes to limit to
176
     * @param array|null $include Relations to include
177
     *
178
     * @return array
179
     */
180
    protected function transformRecord($record, array $fields = [], array $include = [])
181
    {
182
        $relations = array_unique(array_merge($record->getRelations(), $include));
183
        $attributes = $record->load($relations)->toArray();
184
        $relationships = [];
185
        $included = [];
186
187
        foreach ($relations as $relation) {
188
            $relationships[$relation] = [
189
                'data' => []
190
            ];
191
192
            foreach (array_pull($attributes, $relation) as $relatedRecord) {
193
                $relationships[$relation]['data'][] = [
194
                    'type' => $relation,
195
                    'id' => $relatedRecord['id'],
196
                ];
197
198
                if (in_array($relation, $include)) {
199
                    $included[] = [
200
                        'type' => $relation,
201
                        'id' => $relatedRecord['id'],
202
                        'attributes' => array_except($relatedRecord, ['id', 'pivot']),
203
                    ];
204
                }
205
            }
206
        }
207
208
        if (!empty($fields)) {
209
            $attributes = array_only($attributes, $fields);
210
        }
211
212
        $data = [
213
            'type' => $record->getTable(),
214
            'id' => $record->id,
215
            'attributes' => array_except($attributes, ['id']),
216
        ];
217
218
        if (!empty($relationships)) {
219
            $data['relationships'] = $relationships;
220
        }
221
222
        return !empty($included) ? compact('data', 'included') : compact('data');
223
    }
224
}
225