1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace NavJobs\Transmit; |
4
|
|
|
|
5
|
|
|
use Illuminate\Pagination\Paginator; |
6
|
|
|
use Illuminate\Support\Facades\App; |
7
|
|
|
use Illuminate\Support\Facades\Input; |
8
|
|
|
use Illuminate\Pagination\LengthAwarePaginator; |
9
|
|
|
use Illuminate\Routing\Controller as BaseController; |
10
|
|
|
use League\Fractal\Pagination\IlluminatePaginatorAdapter; |
11
|
|
|
use NavJobs\Transmit\Traits\QueryHelperTrait; |
12
|
|
|
|
13
|
|
|
abstract class Controller extends BaseController |
14
|
|
|
{ |
15
|
|
|
use QueryHelperTrait; |
16
|
|
|
|
17
|
|
|
const CODE_WRONG_ARGS = 'GEN-WRONG-ARGS'; |
18
|
|
|
const CODE_NOT_FOUND = 'GEN-NOT-FOUND'; |
19
|
|
|
const CODE_INTERNAL_ERROR = 'GEN-INTERNAL-ERROR'; |
20
|
|
|
const CODE_UNAUTHORIZED = 'GEN-UNAUTHORIZED'; |
21
|
|
|
const CODE_FORBIDDEN = 'GEN-FORBIDDEN'; |
22
|
|
|
const CODE_UNPROCESSABLE_ENTITY = 'GEN-UNPROCESSABLE-ENTITY'; |
23
|
|
|
|
24
|
|
|
protected $statusCode = 200; |
25
|
|
|
protected $fractal; |
26
|
|
|
|
27
|
|
|
public function __construct() |
28
|
|
|
{ |
29
|
|
|
$this->fractal = App::make(Fractal::class); |
30
|
|
|
|
31
|
|
|
$this->parseIncludes(); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Parses includes from either the header or query string. |
36
|
|
|
* |
37
|
|
|
* @return mixed |
38
|
|
|
*/ |
39
|
|
|
protected function parseIncludes() |
40
|
|
|
{ |
41
|
|
|
if (Input::header('include')) { |
42
|
|
|
return $this->fractal->parseIncludes(Input::header('include')); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
if (Input::get('include')) { |
46
|
|
|
return $this->fractal->parseIncludes(Input::get('include')); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
return null; |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Returns the current status code. |
54
|
|
|
* |
55
|
|
|
* @return int |
56
|
|
|
*/ |
57
|
|
|
protected function getStatusCode() |
58
|
|
|
{ |
59
|
|
|
return $this->statusCode; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Sets the current status code. |
64
|
|
|
* |
65
|
|
|
* @param $statusCode |
66
|
|
|
* @return $this |
67
|
|
|
*/ |
68
|
|
|
protected function setStatusCode($statusCode) |
69
|
|
|
{ |
70
|
|
|
$this->statusCode = $statusCode; |
71
|
|
|
|
72
|
|
|
return $this; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Returns a json response that contains the specified resource |
77
|
|
|
* passed through fractal and optionally a transformer. |
78
|
|
|
* |
79
|
|
|
* @param $item |
80
|
|
|
* @param null $callback |
81
|
|
|
* @param null $resourceKey |
82
|
|
|
* @return \Illuminate\Http\JsonResponse |
83
|
|
|
*/ |
84
|
|
|
protected function respondWithItem($item, $callback = null, $resourceKey = null) |
85
|
|
|
{ |
86
|
|
|
$rootScope = $this->fractal->item($item, $callback, $resourceKey); |
87
|
|
|
|
88
|
|
|
return $this->respondWithArray($rootScope->toArray()); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Returns a json response that indicates the resource was successfully created also |
93
|
|
|
* returns the resource passed through fractal and optionally a transformer. |
94
|
|
|
* |
95
|
|
|
* @param $item |
96
|
|
|
* @param null $callback |
97
|
|
|
* @param null $resourceKey |
98
|
|
|
* @return \Illuminate\Http\JsonResponse |
99
|
|
|
*/ |
100
|
|
View Code Duplication |
protected function respondWithItemCreated($item, $callback = null, $resourceKey = null) |
|
|
|
|
101
|
|
|
{ |
102
|
|
|
$this->setStatusCode(201); |
103
|
|
|
$rootScope = $this->fractal->item($item, $callback, $resourceKey); |
104
|
|
|
|
105
|
|
|
return $this->respondWithArray($rootScope->toArray()); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Returns a json response that contains the specified collection |
110
|
|
|
* passed through fractal and optionally a transformer. |
111
|
|
|
* |
112
|
|
|
* @param $collection |
113
|
|
|
* @param $callback |
114
|
|
|
* @param null $resourceKey |
115
|
|
|
* @return \Illuminate\Http\JsonResponse |
116
|
|
|
*/ |
117
|
|
|
protected function respondWithCollection($collection, $callback, $resourceKey = null) |
118
|
|
|
{ |
119
|
|
|
$rootScope = $this->fractal->collection($collection, $callback, $resourceKey); |
120
|
|
|
|
121
|
|
|
return $this->respondWithArray($rootScope->toArray()); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* Returns a json response that contains the specified paginated collection |
126
|
|
|
* passed through fractal and optionally a transformer. |
127
|
|
|
* |
128
|
|
|
* @param $collection |
129
|
|
|
* @param $callback |
130
|
|
|
* @param int $perPage |
131
|
|
|
* @param null $resourceKey |
132
|
|
|
* @return \Illuminate\Http\JsonResponse |
133
|
|
|
*/ |
134
|
|
|
protected function respondWithPaginatedCollection($collection, $callback, $perPage = 10, $resourceKey = null) |
135
|
|
|
{ |
136
|
|
|
$paginator = $this->paginateCollection($collection, $perPage); |
137
|
|
|
|
138
|
|
|
$rootScope = $this->fractal |
139
|
|
|
->collection($paginator->getCollection(), $callback, $resourceKey) |
140
|
|
|
->paginateWith(new IlluminatePaginatorAdapter($paginator)); |
141
|
|
|
|
142
|
|
|
return $this->respondWithArray($rootScope->toArray()); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* @param $collection |
147
|
|
|
* @param $perPage |
148
|
|
|
* @return LengthAwarePaginator |
149
|
|
|
*/ |
150
|
|
|
protected function paginateCollection($collection, $perPage) |
151
|
|
|
{ |
152
|
|
|
$paginator = new LengthAwarePaginator( |
153
|
|
|
$collection->forPage(Paginator::resolveCurrentPage(), $perPage), |
154
|
|
|
$collection->count(), |
155
|
|
|
$perPage, |
156
|
|
|
Paginator::resolveCurrentPage(), |
157
|
|
|
['path' => Paginator::resolveCurrentPath()] |
158
|
|
|
); |
159
|
|
|
$paginator->appends($this->getQueryParameters()); |
160
|
|
|
|
161
|
|
|
return $paginator; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Returns an array of Query Parameters, not including pagination. |
166
|
|
|
* |
167
|
|
|
* @return array |
168
|
|
|
*/ |
169
|
|
|
protected function getQueryParameters() |
|
|
|
|
170
|
|
|
{ |
171
|
|
|
return array_diff_key($_GET, array_flip(['page'])); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* Returns a json response that contains the specified array, |
176
|
|
|
* the current status code and optional headers. |
177
|
|
|
* |
178
|
|
|
* @param array $array |
179
|
|
|
* @param array $headers |
180
|
|
|
* @return \Illuminate\Http\JsonResponse |
181
|
|
|
*/ |
182
|
|
|
protected function respondWithArray(array $array, array $headers = []) |
183
|
|
|
{ |
184
|
|
|
return response()->json($array, $this->statusCode, $headers); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Returns a response that indicates success but no content returned. |
189
|
|
|
* |
190
|
|
|
* @return \Illuminate\Http\Response |
191
|
|
|
*/ |
192
|
|
|
protected function respondWithNoContent() |
193
|
|
|
{ |
194
|
|
|
return response()->make('', 204); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* Returns a response that indicates a 403 Forbidden. |
199
|
|
|
* |
200
|
|
|
* @param string $message |
201
|
|
|
* @return \Illuminate\Http\JsonResponse |
202
|
|
|
*/ |
203
|
|
|
protected function errorForbidden($message = 'Forbidden') |
204
|
|
|
{ |
205
|
|
|
return $this->setStatusCode(403)->respondWithError($message, self::CODE_FORBIDDEN); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* Returns a response that indicates an Internal Error has occurred. |
210
|
|
|
* |
211
|
|
|
* @param string $message |
212
|
|
|
* @return \Illuminate\Http\JsonResponse |
213
|
|
|
*/ |
214
|
|
|
protected function errorInternalError($message = 'Internal Error') |
215
|
|
|
{ |
216
|
|
|
return $this->setStatusCode(500)->respondWithError($message, self::CODE_INTERNAL_ERROR); |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Returns a response that indicates a 404 Not Found. |
221
|
|
|
* |
222
|
|
|
* @param string $message |
223
|
|
|
* @return \Illuminate\Http\JsonResponse |
224
|
|
|
*/ |
225
|
|
|
protected function errorNotFound($message = 'Resource Not Found') |
226
|
|
|
{ |
227
|
|
|
return $this->setStatusCode(404)->respondWithError($message, self::CODE_NOT_FOUND); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* Returns a response that indicates a 401 Unauthorized. |
232
|
|
|
* |
233
|
|
|
* @param string $message |
234
|
|
|
* @return \Illuminate\Http\JsonResponse |
235
|
|
|
*/ |
236
|
|
|
protected function errorUnauthorized($message = 'Unauthorized') |
237
|
|
|
{ |
238
|
|
|
return $this->setStatusCode(401)->respondWithError($message, self::CODE_UNAUTHORIZED); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Returns a response that indicates a 422 Unprocessable Entity. |
243
|
|
|
* |
244
|
|
|
* @param string $message |
245
|
|
|
* @return \Illuminate\Http\JsonResponse |
246
|
|
|
*/ |
247
|
|
|
protected function errorUnprocessableEntity($message = 'Unprocessable Entity') |
248
|
|
|
{ |
249
|
|
|
return $this->setStatusCode(422)->respondWithError($message, self::CODE_UNPROCESSABLE_ENTITY); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Returns a response that indicates the wrong arguments were specified. |
254
|
|
|
* |
255
|
|
|
* @param string $message |
256
|
|
|
* @return \Illuminate\Http\JsonResponse |
257
|
|
|
*/ |
258
|
|
|
protected function errorWrongArgs($message = 'Wrong Arguments') |
259
|
|
|
{ |
260
|
|
|
return $this->setStatusCode(400)->respondWithError($message, self::CODE_WRONG_ARGS); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* Returns a response that indicates an an error occurred. |
265
|
|
|
* |
266
|
|
|
* @param $message |
267
|
|
|
* @param $errorCode |
268
|
|
|
* @return \Illuminate\Http\JsonResponse |
269
|
|
|
*/ |
270
|
|
|
private function respondWithError($message, $errorCode) |
271
|
|
|
{ |
272
|
|
|
return $this->respondWithArray([ |
273
|
|
|
'errors' => [ |
274
|
|
|
'code' => $errorCode, |
275
|
|
|
'http_code' => $this->statusCode, |
276
|
|
|
'message' => $message, |
277
|
|
|
] |
278
|
|
|
]); |
279
|
|
|
} |
280
|
|
|
} |
281
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.