1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* basic rest controller |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace Graviton\RestBundle\Controller; |
7
|
|
|
|
8
|
|
|
use Graviton\ExceptionBundle\Exception\DeserializationException; |
9
|
|
|
use Graviton\ExceptionBundle\Exception\InvalidJsonPatchException; |
10
|
|
|
use Graviton\ExceptionBundle\Exception\MalformedInputException; |
11
|
|
|
use Graviton\ExceptionBundle\Exception\NotFoundException; |
12
|
|
|
use Graviton\ExceptionBundle\Exception\SerializationException; |
13
|
|
|
use Graviton\JsonSchemaBundle\Exception\ValidationException; |
14
|
|
|
use Graviton\RestBundle\Model\DocumentModel; |
15
|
|
|
use Graviton\SchemaBundle\SchemaUtils; |
16
|
|
|
use Graviton\RestBundle\Service\RestUtilsInterface; |
17
|
|
|
use Graviton\SecurityBundle\Entities\SecurityUser; |
18
|
|
|
use Graviton\SecurityBundle\Service\SecurityUtils; |
19
|
|
|
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; |
20
|
|
|
use Symfony\Component\Security\Core\User\UserInterface; |
21
|
|
|
use Symfony\Component\DependencyInjection\ContainerInterface; |
22
|
|
|
use Symfony\Component\HttpFoundation\Request; |
23
|
|
|
use Symfony\Component\HttpFoundation\Response; |
24
|
|
|
use Symfony\Component\HttpKernel\Exception\PreconditionRequiredHttpException; |
25
|
|
|
use Symfony\Component\Routing\Exception\RouteNotFoundException; |
26
|
|
|
use Symfony\Bundle\FrameworkBundle\Routing\Router; |
27
|
|
|
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; |
28
|
|
|
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface; |
29
|
|
|
use Rs\Json\Patch; |
30
|
|
|
use Rs\Json\Patch\InvalidPatchDocumentJsonException; |
31
|
|
|
use Rs\Json\Patch\InvalidTargetDocumentJsonException; |
32
|
|
|
use Rs\Json\Patch\InvalidOperationException; |
33
|
|
|
use Rs\Json\Patch\FailedTestException; |
34
|
|
|
use Graviton\RestBundle\Service\JsonPatchValidator; |
35
|
|
|
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* This is a basic rest controller. It should fit the most needs but if you need to add some |
39
|
|
|
* extra functionality you can extend it and overwrite single/all actions. |
40
|
|
|
* You can also extend the model class to add some extra logic before save |
41
|
|
|
* |
42
|
|
|
* @author List of contributors <https://github.com/libgraviton/graviton/graphs/contributors> |
43
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GNU Public License |
44
|
|
|
* @link http://swisscom.ch |
45
|
|
|
*/ |
46
|
|
|
class RestController |
47
|
|
|
{ |
48
|
|
|
/** |
49
|
|
|
* @var DocumentModel |
50
|
|
|
*/ |
51
|
|
|
private $model; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @var ContainerInterface service_container |
55
|
|
|
*/ |
56
|
|
|
private $container; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var Response |
60
|
|
|
*/ |
61
|
|
|
private $response; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @var RestUtilsInterface |
65
|
|
|
*/ |
66
|
|
|
private $restUtils; |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* @var SchemaUtils |
70
|
|
|
*/ |
71
|
|
|
private $schemaUtils; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* @var Router |
75
|
|
|
*/ |
76
|
|
|
private $router; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @var EngineInterface |
80
|
|
|
*/ |
81
|
|
|
private $templating; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* @var JsonPatchValidator |
85
|
|
|
*/ |
86
|
|
|
private $jsonPatchValidator; |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* @var SecurityUtils |
90
|
|
|
*/ |
91
|
|
|
protected $securityUtils; |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @param Response $response Response |
95
|
|
|
* @param RestUtilsInterface $restUtils Rest utils |
96
|
|
|
* @param Router $router Router |
97
|
|
|
* @param EngineInterface $templating Templating |
98
|
|
|
* @param ContainerInterface $container Container |
99
|
|
|
* @param SchemaUtils $schemaUtils Schema utils |
100
|
|
|
*/ |
101
|
|
|
public function __construct( |
102
|
|
|
Response $response, |
103
|
|
|
RestUtilsInterface $restUtils, |
104
|
|
|
Router $router, |
105
|
|
|
EngineInterface $templating, |
106
|
|
|
ContainerInterface $container, |
107
|
|
|
SchemaUtils $schemaUtils |
108
|
|
|
) { |
109
|
|
|
$this->response = $response; |
110
|
|
|
$this->restUtils = $restUtils; |
111
|
|
|
$this->router = $router; |
112
|
|
|
$this->templating = $templating; |
113
|
|
|
$this->container = $container; |
114
|
|
|
$this->schemaUtils = $schemaUtils; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Setter for the SecurityUtils |
119
|
|
|
* |
120
|
|
|
* @param SecurityUtils $securityUtils The securityUtils service |
121
|
|
|
* @return void |
122
|
|
|
*/ |
123
|
|
|
public function setSecurityUtils(SecurityUtils $securityUtils) |
124
|
|
|
{ |
125
|
|
|
$this->securityUtils = $securityUtils; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* @param JsonPatchValidator $jsonPatchValidator Service for validation json patch |
130
|
|
|
* @return void |
131
|
|
|
*/ |
132
|
|
|
public function setJsonPatchValidator(JsonPatchValidator $jsonPatchValidator) |
133
|
|
|
{ |
134
|
|
|
$this->jsonPatchValidator = $jsonPatchValidator; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Get the container object |
139
|
|
|
* |
140
|
|
|
* @return \Symfony\Component\DependencyInjection\ContainerInterface |
141
|
|
|
* |
142
|
|
|
* @obsolete |
143
|
|
|
*/ |
144
|
|
|
public function getContainer() |
145
|
|
|
{ |
146
|
|
|
return $this->container; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Returns a single record |
151
|
|
|
* |
152
|
|
|
* @param Request $request Current http request |
153
|
|
|
* @param string $id ID of record |
154
|
|
|
* |
155
|
|
|
* @return \Symfony\Component\HttpFoundation\Response $response Response with result or error |
156
|
|
|
*/ |
157
|
|
View Code Duplication |
public function getAction(Request $request, $id) |
|
|
|
|
158
|
|
|
{ |
159
|
|
|
$response = $this->getResponse() |
160
|
|
|
->setStatusCode(Response::HTTP_OK) |
161
|
|
|
->setContent($this->serialize($this->findRecord($id, $request))); |
162
|
|
|
|
163
|
|
|
return $response; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Get the response object |
168
|
|
|
* |
169
|
|
|
* @return \Symfony\Component\HttpFoundation\Response $response Response object |
170
|
|
|
*/ |
171
|
|
|
public function getResponse() |
172
|
|
|
{ |
173
|
|
|
return $this->response; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* Get a single record from database or throw an exception if it doesn't exist |
178
|
|
|
* |
179
|
|
|
* @param mixed $id Record id |
180
|
|
|
* @param Request $request request |
|
|
|
|
181
|
|
|
* |
182
|
|
|
* @throws \Graviton\ExceptionBundle\Exception\NotFoundException |
183
|
|
|
* |
184
|
|
|
* @return object $record Document object |
185
|
|
|
*/ |
186
|
|
|
protected function findRecord($id, Request $request = null) |
187
|
|
|
{ |
188
|
|
|
$response = $this->getResponse(); |
189
|
|
|
|
190
|
|
|
if (!($this->getModel()->recordExists($id))) { |
191
|
|
|
$e = new NotFoundException("Entry with id " . $id . " not found!"); |
192
|
|
|
$e->setResponse($response); |
193
|
|
|
throw $e; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
return $this->getModel()->find($id, $request); |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Return the model |
201
|
|
|
* |
202
|
|
|
* @throws \Exception in case no model was defined. |
203
|
|
|
* |
204
|
|
|
* @return DocumentModel $model Model |
205
|
|
|
*/ |
206
|
|
|
public function getModel() |
207
|
|
|
{ |
208
|
|
|
if (!$this->model) { |
209
|
|
|
throw new \Exception('No model is set for this controller'); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
return $this->model; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Set the model class |
217
|
|
|
* |
218
|
|
|
* @param DocumentModel $model Model class |
219
|
|
|
* |
220
|
|
|
* @return self |
221
|
|
|
*/ |
222
|
|
|
public function setModel(DocumentModel $model) |
223
|
|
|
{ |
224
|
|
|
$this->model = $model; |
225
|
|
|
|
226
|
|
|
return $this; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Serialize the given record and throw an exception if something went wrong |
231
|
|
|
* |
232
|
|
|
* @param object|object[] $result Record(s) |
233
|
|
|
* |
234
|
|
|
* @throws \Graviton\ExceptionBundle\Exception\SerializationException |
235
|
|
|
* |
236
|
|
|
* @return string $content Json content |
237
|
|
|
*/ |
238
|
|
|
protected function serialize($result) |
239
|
|
|
{ |
240
|
|
|
$response = $this->getResponse(); |
241
|
|
|
|
242
|
|
|
try { |
243
|
|
|
// array is serialized as an object {"0":{...},"1":{...},...} when data contains an empty objects |
244
|
|
|
// we serialize each item because we can assume this bug affects only root array element |
245
|
|
|
if (is_array($result) && array_keys($result) === range(0, count($result) - 1)) { |
246
|
|
|
$result = array_map( |
247
|
|
|
function ($item) { |
248
|
|
|
return $this->getRestUtils()->serializeContent($item); |
249
|
|
|
}, |
250
|
|
|
$result |
251
|
|
|
); |
252
|
|
|
|
253
|
|
|
return '['.implode(',', array_filter($result)).']'; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
return $this->getRestUtils()->serializeContent($result); |
|
|
|
|
257
|
|
|
} catch (\Exception $e) { |
258
|
|
|
$exception = new SerializationException($e); |
259
|
|
|
$exception->setResponse($response); |
260
|
|
|
throw $exception; |
261
|
|
|
} |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* Get RestUtils service |
266
|
|
|
* |
267
|
|
|
* @return \Graviton\RestBundle\Service\RestUtils |
268
|
|
|
*/ |
269
|
|
|
public function getRestUtils() |
270
|
|
|
{ |
271
|
|
|
return $this->restUtils; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* Returns all records |
276
|
|
|
* |
277
|
|
|
* @param Request $request Current http request |
278
|
|
|
* |
279
|
|
|
* @return \Symfony\Component\HttpFoundation\Response $response Response with result or error |
280
|
|
|
*/ |
281
|
|
View Code Duplication |
public function allAction(Request $request) |
|
|
|
|
282
|
|
|
{ |
283
|
|
|
$model = $this->getModel(); |
284
|
|
|
|
285
|
|
|
$response = $this->getResponse() |
286
|
|
|
->setStatusCode(Response::HTTP_OK) |
287
|
|
|
->setContent($this->serialize($model->findAll($request))); |
288
|
|
|
|
289
|
|
|
return $response; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* Writes a new Entry to the database |
294
|
|
|
* |
295
|
|
|
* @param Request $request Current http request |
296
|
|
|
* |
297
|
|
|
* @return \Symfony\Component\HttpFoundation\Response $response Result of action with data (if successful) |
298
|
|
|
*/ |
299
|
|
|
public function postAction(Request $request) |
300
|
|
|
{ |
301
|
|
|
// Get the response object from container |
302
|
|
|
$response = $this->getResponse(); |
303
|
|
|
$model = $this->getModel(); |
304
|
|
|
|
305
|
|
|
$this->restUtils->checkJsonRequest($request, $response, $this->getModel()); |
306
|
|
|
|
307
|
|
|
$record = $this->validateRequest($request->getContent(), $model); |
|
|
|
|
308
|
|
|
|
309
|
|
|
// Insert the new record |
310
|
|
|
$record = $this->getModel()->insertRecord($record); |
311
|
|
|
|
312
|
|
|
// store id of new record so we dont need to reparse body later when needed |
313
|
|
|
$request->attributes->set('id', $record->getId()); |
314
|
|
|
|
315
|
|
|
// Set status code |
316
|
|
|
$response->setStatusCode(Response::HTTP_CREATED); |
317
|
|
|
|
318
|
|
|
$response->headers->set( |
319
|
|
|
'Location', |
320
|
|
|
$this->getRouter()->generate($this->getRouteName($request), array('id' => $record->getId())) |
321
|
|
|
); |
322
|
|
|
|
323
|
|
|
return $response; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* Validates the current request on schema violations. If there are errors, |
328
|
|
|
* the exception is thrown. If not, the deserialized record is returned. |
329
|
|
|
* |
330
|
|
|
* @param object|string $content \stdClass of the request content |
331
|
|
|
* @param DocumentModel $model the model to check the schema for |
332
|
|
|
* |
333
|
|
|
* @return \Graviton\JsonSchemaBundle\Exception\ValidationExceptionError[] |
|
|
|
|
334
|
|
|
* @throws \Exception |
335
|
|
|
*/ |
336
|
|
|
protected function validateRequest($content, DocumentModel $model) |
337
|
|
|
{ |
338
|
|
|
$errors = $this->restUtils->validateContent($content, $model); |
339
|
|
|
if (!empty($errors)) { |
340
|
|
|
throw new ValidationException($errors); |
341
|
|
|
} |
342
|
|
|
return $this->deserialize($content, $model->getEntityClass()); |
|
|
|
|
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Deserialize the given content throw an exception if something went wrong |
347
|
|
|
* |
348
|
|
|
* @param string $content Request content |
349
|
|
|
* @param string $documentClass Document class |
350
|
|
|
* |
351
|
|
|
* @throws DeserializationException |
352
|
|
|
* |
353
|
|
|
* @return object $record Document |
|
|
|
|
354
|
|
|
*/ |
355
|
|
|
protected function deserialize($content, $documentClass) |
356
|
|
|
{ |
357
|
|
|
$response = $this->getResponse(); |
358
|
|
|
|
359
|
|
|
try { |
360
|
|
|
$record = $this->getRestUtils()->deserializeContent( |
361
|
|
|
$content, |
362
|
|
|
$documentClass |
363
|
|
|
); |
364
|
|
|
} catch (\Exception $e) { |
365
|
|
|
// pass the previous exception in this case to get the error message in the handler |
366
|
|
|
// http://php.net/manual/de/exception.getprevious.php |
367
|
|
|
$exception = new DeserializationException("Deserialization failed", $e); |
368
|
|
|
|
369
|
|
|
// at the moment, the response has to be set on the exception object. |
370
|
|
|
// try to refactor this and return the graviton.rest.response if none is set... |
371
|
|
|
$exception->setResponse($response); |
372
|
|
|
throw $exception; |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
return $record; |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* Get the router from the dic |
380
|
|
|
* |
381
|
|
|
* @return Router |
382
|
|
|
*/ |
383
|
|
|
public function getRouter() |
384
|
|
|
{ |
385
|
|
|
return $this->router; |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
/** |
389
|
|
|
* Update a record |
390
|
|
|
* |
391
|
|
|
* @param Number $id ID of record |
392
|
|
|
* @param Request $request Current http request |
393
|
|
|
* |
394
|
|
|
* @throws MalformedInputException |
395
|
|
|
* |
396
|
|
|
* @return Response $response Result of action with data (if successful) |
397
|
|
|
*/ |
398
|
|
|
public function putAction($id, Request $request) |
399
|
|
|
{ |
400
|
|
|
$response = $this->getResponse(); |
401
|
|
|
$model = $this->getModel(); |
402
|
|
|
|
403
|
|
|
$this->restUtils->checkJsonRequest($request, $response, $this->getModel()); |
404
|
|
|
|
405
|
|
|
$record = $this->validateRequest($request->getContent(), $model); |
|
|
|
|
406
|
|
|
|
407
|
|
|
// handle missing 'id' field in input to a PUT operation |
408
|
|
|
// if it is settable on the document, let's set it and move on.. if not, inform the user.. |
409
|
|
|
if ($record->getId() != $id) { |
410
|
|
|
// try to set it.. |
411
|
|
|
if (is_callable(array($record, 'setId'))) { |
412
|
|
|
$record->setId($id); |
413
|
|
|
} else { |
414
|
|
|
throw new MalformedInputException('No ID was supplied in the request payload.'); |
415
|
|
|
} |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
// And update the record, if everything is ok |
419
|
|
|
if (!$this->getModel()->recordExists($id)) { |
420
|
|
|
$this->getModel()->insertRecord($record, false); |
421
|
|
|
} else { |
422
|
|
|
$this->getModel()->updateRecord($id, $record, false); |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
// Set status code |
426
|
|
|
$response->setStatusCode(Response::HTTP_NO_CONTENT); |
427
|
|
|
|
428
|
|
|
// store id of new record so we dont need to reparse body later when needed |
429
|
|
|
$request->attributes->set('id', $record->getId()); |
430
|
|
|
|
431
|
|
|
return $response; |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
/** |
435
|
|
|
* Patch a record |
436
|
|
|
* |
437
|
|
|
* @param Number $id ID of record |
438
|
|
|
* @param Request $request Current http request |
439
|
|
|
* |
440
|
|
|
* @throws MalformedInputException |
441
|
|
|
* |
442
|
|
|
* @return Response $response Result of action with data (if successful) |
443
|
|
|
*/ |
444
|
|
|
public function patchAction($id, Request $request) |
445
|
|
|
{ |
446
|
|
|
$response = $this->getResponse(); |
447
|
|
|
|
448
|
|
|
// Check JSON Patch request |
449
|
|
|
$this->restUtils->checkJsonRequest($request, $response, $this->getModel()); |
450
|
|
|
$this->restUtils->checkJsonPatchRequest(json_decode($request->getContent(), 1)); |
451
|
|
|
|
452
|
|
|
// Find record && apply $ref converter |
453
|
|
|
$record = $this->findRecord($id); |
454
|
|
|
$jsonDocument = $this->serialize($record); |
455
|
|
|
|
456
|
|
|
// Check/validate JSON Patch |
457
|
|
|
if (!$this->jsonPatchValidator->validate($jsonDocument, $request->getContent())) { |
|
|
|
|
458
|
|
|
throw new InvalidJsonPatchException($this->jsonPatchValidator->getException()->getMessage()); |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
try { |
462
|
|
|
// Apply JSON patches |
463
|
|
|
$patch = new Patch($jsonDocument, $request->getContent()); |
|
|
|
|
464
|
|
|
$patchedDocument = $patch->apply(); |
465
|
|
|
} catch (InvalidPatchDocumentJsonException $e) { |
466
|
|
|
throw new InvalidJsonPatchException($e->getMessage()); |
467
|
|
|
} catch (InvalidTargetDocumentJsonException $e) { |
468
|
|
|
throw new InvalidJsonPatchException($e->getMessage()); |
469
|
|
|
} catch (InvalidOperationException $e) { |
470
|
|
|
throw new InvalidJsonPatchException($e->getMessage()); |
471
|
|
|
} catch (FailedTestException $e) { |
472
|
|
|
throw new InvalidJsonPatchException($e->getMessage()); |
473
|
|
|
} |
474
|
|
|
|
475
|
|
|
// Validate result object |
476
|
|
|
$model = $this->getModel(); |
477
|
|
|
$record = $this->validateRequest($patchedDocument, $model); |
478
|
|
|
|
479
|
|
|
// Update object |
480
|
|
|
$this->getModel()->updateRecord($id, $record); |
481
|
|
|
|
482
|
|
|
// Set status code |
483
|
|
|
$response->setStatusCode(Response::HTTP_OK); |
484
|
|
|
|
485
|
|
|
// Set Content-Location header |
486
|
|
|
$response->headers->set( |
487
|
|
|
'Content-Location', |
488
|
|
|
$this->getRouter()->generate($this->getRouteName($request), array('id' => $record->getId())) |
489
|
|
|
); |
490
|
|
|
|
491
|
|
|
return $response; |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
/** |
495
|
|
|
* Deletes a record |
496
|
|
|
* |
497
|
|
|
* @param Number $id ID of record |
498
|
|
|
* |
499
|
|
|
* @return Response $response Result of the action |
500
|
|
|
*/ |
501
|
|
|
public function deleteAction($id) |
502
|
|
|
{ |
503
|
|
|
$response = $this->getResponse(); |
504
|
|
|
|
505
|
|
|
// does this record exist? |
506
|
|
|
$this->findRecord($id); |
507
|
|
|
|
508
|
|
|
$this->getModel()->deleteRecord($id); |
509
|
|
|
$response->setStatusCode(Response::HTTP_NO_CONTENT); |
510
|
|
|
|
511
|
|
|
return $response; |
512
|
|
|
} |
513
|
|
|
|
514
|
|
|
/** |
515
|
|
|
* Return OPTIONS results. |
516
|
|
|
* |
517
|
|
|
* @param Request $request Current http request |
518
|
|
|
* |
519
|
|
|
* @throws SerializationException |
520
|
|
|
* @return \Symfony\Component\HttpFoundation\Response $response Result of the action |
521
|
|
|
*/ |
522
|
|
|
public function optionsAction(Request $request) |
523
|
|
|
{ |
524
|
|
|
list($app, $module, , $modelName) = explode('.', $request->attributes->get('_route')); |
525
|
|
|
|
526
|
|
|
$response = $this->response; |
527
|
|
|
$response->setStatusCode(Response::HTTP_NO_CONTENT); |
528
|
|
|
|
529
|
|
|
// enabled methods for CorsListener |
530
|
|
|
$corsMethods = 'GET, POST, PUT, PATCH, DELETE, OPTIONS'; |
531
|
|
|
try { |
532
|
|
|
$router = $this->getRouter(); |
533
|
|
|
// if post route is available we assume everything is readable |
534
|
|
|
$router->generate(implode('.', array($app, $module, 'rest', $modelName, 'post'))); |
535
|
|
|
} catch (RouteNotFoundException $exception) { |
536
|
|
|
// only allow read methods |
537
|
|
|
$corsMethods = 'GET, OPTIONS'; |
538
|
|
|
} |
539
|
|
|
$request->attributes->set('corsMethods', $corsMethods); |
540
|
|
|
|
541
|
|
|
return $response; |
542
|
|
|
} |
543
|
|
|
|
544
|
|
|
|
545
|
|
|
/** |
546
|
|
|
* Return schema GET results. |
547
|
|
|
* |
548
|
|
|
* @param Request $request Current http request |
549
|
|
|
* @param string $id ID of record |
|
|
|
|
550
|
|
|
* |
551
|
|
|
* @throws SerializationException |
552
|
|
|
* @return \Symfony\Component\HttpFoundation\Response $response Result of the action |
553
|
|
|
*/ |
554
|
|
|
public function schemaAction(Request $request, $id = null) |
555
|
|
|
{ |
556
|
|
|
$request->attributes->set('schemaRequest', true); |
557
|
|
|
|
558
|
|
|
list($app, $module, , $modelName, $schemaType) = explode('.', $request->attributes->get('_route')); |
559
|
|
|
|
560
|
|
|
$response = $this->response; |
561
|
|
|
$response->setStatusCode(Response::HTTP_OK); |
562
|
|
|
$response->setPublic(); |
563
|
|
|
|
564
|
|
|
if (!$id && $schemaType != 'canonicalIdSchema') { |
565
|
|
|
$schema = $this->schemaUtils->getCollectionSchema($modelName, $this->getModel()); |
566
|
|
|
} else { |
567
|
|
|
$schema = $this->schemaUtils->getModelSchema($modelName, $this->getModel()); |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
// enabled methods for CorsListener |
571
|
|
|
$corsMethods = 'GET, POST, PUT, PATCH, DELETE, OPTIONS'; |
572
|
|
|
try { |
573
|
|
|
$router = $this->getRouter(); |
574
|
|
|
// if post route is available we assume everything is readable |
575
|
|
|
$router->generate(implode('.', array($app, $module, 'rest', $modelName, 'post'))); |
576
|
|
|
} catch (RouteNotFoundException $exception) { |
577
|
|
|
// only allow read methods |
578
|
|
|
$corsMethods = 'GET, OPTIONS'; |
579
|
|
|
} |
580
|
|
|
$request->attributes->set('corsMethods', $corsMethods); |
581
|
|
|
|
582
|
|
|
|
583
|
|
|
return $this->render( |
584
|
|
|
'GravitonRestBundle:Main:index.json.twig', |
585
|
|
|
['response' => $this->serialize($schema)], |
586
|
|
|
$response |
587
|
|
|
); |
588
|
|
|
} |
589
|
|
|
|
590
|
|
|
/** |
591
|
|
|
* Renders a view. |
592
|
|
|
* |
593
|
|
|
* @param string $view The view name |
594
|
|
|
* @param array $parameters An array of parameters to pass to the view |
595
|
|
|
* @param Response $response A response instance |
|
|
|
|
596
|
|
|
* |
597
|
|
|
* @return Response A Response instance |
598
|
|
|
*/ |
599
|
|
|
public function render($view, array $parameters = array(), Response $response = null) |
600
|
|
|
{ |
601
|
|
|
return $this->templating->renderResponse($view, $parameters, $response); |
602
|
|
|
} |
603
|
|
|
|
604
|
|
|
/** |
605
|
|
|
* @param Request $request request |
606
|
|
|
* @return string |
607
|
|
|
*/ |
608
|
|
|
private function getRouteName(Request $request) |
609
|
|
|
{ |
610
|
|
|
$routeName = $request->get('_route'); |
611
|
|
|
$routeParts = explode('.', $routeName); |
612
|
|
|
$routeType = end($routeParts); |
613
|
|
|
|
614
|
|
|
if ($routeType == 'post') { |
615
|
|
|
$routeName = substr($routeName, 0, -4) . 'get'; |
616
|
|
|
} |
617
|
|
|
|
618
|
|
|
return $routeName; |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
/** |
622
|
|
|
* Security needs to be enabled to get Object. |
623
|
|
|
* |
624
|
|
|
* @return SecurityUser |
625
|
|
|
* @throws UsernameNotFoundException |
626
|
|
|
*/ |
627
|
|
|
public function getSecurityUser() |
628
|
|
|
{ |
629
|
|
|
return $this->securityUtils->getSecurityUser(); |
630
|
|
|
} |
631
|
|
|
} |
632
|
|
|
|
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.