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')); |
|
|
|
|
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')); |
|
|
|
|
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) |
|
|
|
|
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
|
|
|
|
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.