1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Happyr\ApiBundle\Service; |
4
|
|
|
|
5
|
|
|
use League\Fractal\Manager; |
6
|
|
|
use League\Fractal\Pagination\CursorInterface; |
7
|
|
|
use League\Fractal\Pagination\PaginatorInterface; |
8
|
|
|
use League\Fractal\Resource\Collection; |
9
|
|
|
use League\Fractal\Resource\Item; |
10
|
|
|
use Symfony\Component\HttpFoundation\JsonResponse; |
11
|
|
|
use Symfony\Component\Validator\ConstraintViolationInterface; |
12
|
|
|
use Symfony\Component\Validator\ConstraintViolationListInterface; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* @author Tobias Nyholm <[email protected]> |
16
|
|
|
*/ |
17
|
|
|
final class ResponseFactory |
18
|
|
|
{ |
19
|
|
|
const CODE_WRONG_ARGS = 'GEN-ARGUMENTS'; |
20
|
|
|
|
21
|
|
|
const CODE_NOT_FOUND = 'GEN-NOTFOUND'; |
22
|
|
|
|
23
|
|
|
const CODE_INTERNAL_ERROR = 'GEN-SERVERERROR'; |
24
|
|
|
|
25
|
|
|
const CODE_UNAUTHORIZED = 'GEN-UNAUTHORIZED'; |
26
|
|
|
|
27
|
|
|
const CODE_FORBIDDEN = 'GEN-FORBIDDEN'; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var Manager |
31
|
|
|
*/ |
32
|
|
|
private $fractal; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var PaginatorInterface |
36
|
|
|
*/ |
37
|
|
|
private $paginator; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var CursorInterface |
41
|
|
|
*/ |
42
|
|
|
private $cursor; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @param Manager $fractal |
46
|
|
|
*/ |
47
|
|
|
public function __construct(Manager $fractal) |
48
|
|
|
{ |
49
|
|
|
$this->fractal = $fractal; |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @return Manager |
54
|
|
|
*/ |
55
|
|
|
public function getFractal() |
56
|
|
|
{ |
57
|
|
|
return $this->fractal; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @param mixed $item |
62
|
|
|
* @param $callback |
63
|
|
|
* |
64
|
|
|
* @return JsonResponse |
65
|
|
|
*/ |
66
|
|
|
public function createWithItem($item, $callback) |
67
|
|
|
{ |
68
|
|
|
$resource = new Item($item, $callback); |
69
|
|
|
$rootScope = $this->fractal->createData($resource); |
70
|
|
|
|
71
|
|
|
return $this->createWithArray($rootScope->toArray()); |
|
|
|
|
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* @param mixed $collection |
76
|
|
|
* @param $callback |
77
|
|
|
* |
78
|
|
|
* @return JsonResponse |
79
|
|
|
*/ |
80
|
|
|
public function createWithCollection($collection, $callback) |
81
|
|
|
{ |
82
|
|
|
$resource = new Collection($collection, $callback); |
83
|
|
|
if (null !== $this->paginator) { |
84
|
|
|
$resource->setPaginator($this->paginator); |
85
|
|
|
} elseif (null !== $this->cursor) { |
86
|
|
|
$resource->setCursor($this->cursor); |
87
|
|
|
} |
88
|
|
|
$rootScope = $this->fractal->createData($resource); |
89
|
|
|
|
90
|
|
|
return $this->createWithArray($rootScope->toArray()); |
|
|
|
|
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @param PaginatorInterface $paginator |
95
|
|
|
* |
96
|
|
|
* @return ResponseFactory |
97
|
|
|
*/ |
98
|
|
|
public function withPaginator(PaginatorInterface $paginator) |
99
|
|
|
{ |
100
|
|
|
$new = clone $this; |
101
|
|
|
$new->paginator = $paginator; |
102
|
|
|
|
103
|
|
|
return $new; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* @param CursorInterface $cursor |
108
|
|
|
* |
109
|
|
|
* @return ResponseFactory |
110
|
|
|
*/ |
111
|
|
|
public function withCursor(CursorInterface $cursor) |
112
|
|
|
{ |
113
|
|
|
$new = clone $this; |
114
|
|
|
$new->cursor = $cursor; |
115
|
|
|
|
116
|
|
|
return $new; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* @param array $array |
121
|
|
|
* @param int $statusCode |
122
|
|
|
* @param array $headers |
123
|
|
|
* |
124
|
|
|
* @return JsonResponse |
125
|
|
|
*/ |
126
|
|
|
public function createWithArray(array $array, $statusCode = 200, array $headers = []) |
127
|
|
|
{ |
128
|
|
|
return new JsonResponse($array, $statusCode, $headers); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* @param string $message |
133
|
|
|
* @param int $statusCode |
134
|
|
|
* @param string $errorCode |
135
|
|
|
* |
136
|
|
|
* @return JsonResponse |
137
|
|
|
*/ |
138
|
|
|
public function createWithError($message, $statusCode, $errorCode) |
139
|
|
|
{ |
140
|
|
|
if (200 === $statusCode) { |
141
|
|
|
trigger_error( |
142
|
|
|
'You better have a really good reason for erroring on a 200...', |
143
|
|
|
E_USER_WARNING |
144
|
|
|
); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
return $this->createWithArray([ |
148
|
|
|
'error' => [ |
149
|
|
|
'code' => $errorCode, |
150
|
|
|
'http_code' => $statusCode, |
151
|
|
|
'message' => $message, |
152
|
|
|
], |
153
|
|
|
], $statusCode); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* Generates a Response with a 403 HTTP header and a given message. |
158
|
|
|
* |
159
|
|
|
* @param string $message |
160
|
|
|
* |
161
|
|
|
* @return JsonResponse |
162
|
|
|
*/ |
163
|
|
|
public function createForbidden($message = 'Forbidden') |
164
|
|
|
{ |
165
|
|
|
return $this->createWithError($message, 403, self::CODE_FORBIDDEN); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Generates a Response with a 500 HTTP header and a given message. |
170
|
|
|
* |
171
|
|
|
* @param string $message |
172
|
|
|
* |
173
|
|
|
* @return JsonResponse |
174
|
|
|
*/ |
175
|
|
|
public function createInternalError($message = 'Internal Error') |
176
|
|
|
{ |
177
|
|
|
return $this->createWithError($message, 500, self::CODE_INTERNAL_ERROR); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Generates a Response with a 404 HTTP header and a given message. |
182
|
|
|
* |
183
|
|
|
* @param string $message |
184
|
|
|
* |
185
|
|
|
* @return JsonResponse |
186
|
|
|
*/ |
187
|
|
|
public function createNotFound($message = 'Resource Not Found') |
188
|
|
|
{ |
189
|
|
|
return $this->createWithError($message, 404, self::CODE_NOT_FOUND); |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
/** |
193
|
|
|
* Generates a Response with a 401 HTTP header and a given message. |
194
|
|
|
* |
195
|
|
|
* @param string $message |
196
|
|
|
* |
197
|
|
|
* @return JsonResponse |
198
|
|
|
*/ |
199
|
|
|
public function createUnauthorized($message = 'Unauthorized') |
200
|
|
|
{ |
201
|
|
|
return $this->createWithError($message, 401, self::CODE_UNAUTHORIZED); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Generates a Response with a 400 HTTP header and a given message. |
206
|
|
|
* |
207
|
|
|
* @param string $message |
208
|
|
|
* |
209
|
|
|
* @return JsonResponse |
210
|
|
|
*/ |
211
|
|
|
public function createWrongArgs($message = 'Wrong Arguments') |
212
|
|
|
{ |
213
|
|
|
return $this->createWithError($message, 400, self::CODE_WRONG_ARGS); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* @param ConstraintViolationListInterface $constraintViolationList |
218
|
|
|
* @param string $message |
219
|
|
|
* @param int $statusCode |
220
|
|
|
* |
221
|
|
|
* @return JsonResponse |
222
|
|
|
*/ |
223
|
|
|
public function createValidationFailed( |
224
|
|
|
ConstraintViolationListInterface $constraintViolationList, |
225
|
|
|
$message = 'Validation Failed', |
226
|
|
|
$statusCode = 400 |
227
|
|
|
) { |
228
|
|
|
$errors = []; |
229
|
|
|
/** @var ConstraintViolationInterface $constraintViolation */ |
230
|
|
|
foreach ($constraintViolationList as $constraintViolation) { |
231
|
|
|
$errors[] = [ |
232
|
|
|
'property' => $constraintViolation->getPropertyPath(), |
233
|
|
|
'message' => $constraintViolation->getMessage(), |
234
|
|
|
]; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
return $this->createWithArray([ |
238
|
|
|
'error' => [ |
239
|
|
|
'code' => self::CODE_WRONG_ARGS, |
240
|
|
|
'http_code' => $statusCode, |
241
|
|
|
'message' => $message, |
242
|
|
|
], |
243
|
|
|
'data' => [ |
244
|
|
|
'errors' => $errors, |
245
|
|
|
], |
246
|
|
|
], $statusCode); |
247
|
|
|
} |
248
|
|
|
} |
249
|
|
|
|
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.