Completed
Push — feature/other-validation ( 15ee30...6fb65c )
by Narcotic
08:45
created

RestController   F

Complexity

Total Complexity 53

Size/Duplication

Total Lines 726
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 22

Test Coverage

Coverage 0%

Importance

Changes 5
Bugs 0 Features 1
Metric Value
wmc 53
c 5
b 0
f 1
lcom 1
cbo 22
dl 0
loc 726
ccs 0
cts 320
cp 0
rs 1.3677

26 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 21 1
A setTokenStorage() 0 4 1
A setFormDataMapper() 0 4 1
A setJsonPatchValidator() 0 4 1
A setFormValidator() 0 4 1
A getContainer() 0 4 1
A getAction() 0 13 1
A getResponse() 0 4 1
A findRecord() 0 12 2
A getModel() 0 8 2
A setModel() 0 6 1
B serialize() 0 32 4
A getRestUtils() 0 4 1
B allAction() 0 30 4
B postAction() 0 30 1
A deserialize() 0 22 2
A getRouter() 0 4 1
C putAction() 0 81 7
B patchAction() 0 54 6
A deleteAction() 0 12 1
A optionsAction() 0 21 2
B schemaAction() 0 35 4
A getValidator() 0 4 1
A render() 0 4 1
A getRouteName() 0 12 2
A getSecurityUser() 0 10 3

How to fix   Complexity   

Complex Class

Complex classes like RestController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RestController, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * basic rest controller
4
 */
5
6
namespace Graviton\RestBundle\Controller;
7
8
use Graviton\DocumentBundle\Service\FormDataMapperInterface;
9
use Graviton\ExceptionBundle\Exception\DeserializationException;
10
use Graviton\ExceptionBundle\Exception\InvalidJsonPatchException;
11
use Graviton\ExceptionBundle\Exception\MalformedInputException;
12
use Graviton\ExceptionBundle\Exception\NotFoundException;
13
use Graviton\ExceptionBundle\Exception\SerializationException;
14
use Graviton\JsonSchemaBundle\Schema\RefResolver;
15
use Graviton\JsonSchemaBundle\Schema\SchemaFactory;
16
use Graviton\JsonSchemaBundle\Validator\Validator;
17
use Graviton\RestBundle\Validator\Form;
18
use Graviton\RestBundle\Model\DocumentModel;
19
use Graviton\RestBundle\Model\PaginatorAwareInterface;
20
use Graviton\SchemaBundle\SchemaUtils;
21
use Graviton\DocumentBundle\Form\Type\DocumentType;
22
use Graviton\RestBundle\Service\RestUtilsInterface;
23
use HadesArchitect\JsonSchemaBundle\Validator\ValidatorService;
24
use Symfony\Component\Security\Core\User\UserInterface;
25
use Knp\Component\Pager\Paginator;
26
use Symfony\Component\DependencyInjection\ContainerInterface;
27
use Symfony\Component\HttpFoundation\Request;
28
use Symfony\Component\HttpFoundation\Response;
29
use Symfony\Component\HttpKernel\Exception\PreconditionRequiredHttpException;
30
use Symfony\Component\Routing\Exception\RouteNotFoundException;
31
use Symfony\Component\Form\FormFactory;
32
use Symfony\Bundle\FrameworkBundle\Routing\Router;
33
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
34
use Symfony\Component\Validator\Validator\ValidatorInterface;
35
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
36
use Rs\Json\Patch;
37
use Rs\Json\Patch\InvalidPatchDocumentJsonException;
38
use Rs\Json\Patch\InvalidTargetDocumentJsonException;
39
use Rs\Json\Patch\InvalidOperationException;
40
use Rs\Json\Patch\FailedTestException;
41
use Graviton\RestBundle\Service\JsonPatchValidator;
42
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
43
44
/**
45
 * This is a basic rest controller. It should fit the most needs but if you need to add some
46
 * extra functionality you can extend it and overwrite single/all actions.
47
 * You can also extend the model class to add some extra logic before save
48
 *
49
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
50
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
51
 * @link     http://swisscom.ch
52
 */
53
class RestController
54
{
55
    /**
56
     * @var DocumentModel
57
     */
58
    private $model;
59
60
    /**
61
     * @var ContainerInterface service_container
62
     */
63
    private $container;
64
65
    /**
66
     * @var Response
67
     */
68
    private $response;
69
70
    /**
71
     * @var FormFactory
72
     */
73
    private $formFactory;
74
75
    /**
76
     * @var DocumentType
77
     */
78
    private $formType;
79
80
    /**
81
     * @var RestUtilsInterface
82
     */
83
    private $restUtils;
84
85
    /**
86
     * @var SchemaUtils
87
     */
88
    private $schemaUtils;
89
90
    /**
91
     * @var FormDataMapperInterface
92
     */
93
    protected $formDataMapper;
94
95
    /**
96
     * @var Router
97
     */
98
    private $router;
99
100
    /**
101
     * @var ValidatorInterface
102
     */
103
    private $validator;
104
105
    /**
106
     * @var EngineInterface
107
     */
108
    private $templating;
109
110
    /**
111
     * @var JsonPatchValidator
112
     */
113
    private $jsonPatchValidator;
114
115
    /**
116
     * @var Form
117
     */
118
    protected $formValidator;
119
120
    /**
121
     * @var TokenStorage
122
     */
123
    protected $tokenStorage;
124
125
    /**
126
     * @param Response           $response    Response
127
     * @param RestUtilsInterface $restUtils   Rest utils
128
     * @param Router             $router      Router
129
     * @param ValidatorInterface $validator   Validator
130
     * @param EngineInterface    $templating  Templating
131
     * @param FormFactory        $formFactory form factory
132
     * @param DocumentType       $formType    generic form
133
     * @param ContainerInterface $container   Container
134
     * @param SchemaUtils        $schemaUtils Schema utils
135
     */
136
    public function __construct(
137
        Response $response,
138
        RestUtilsInterface $restUtils,
139
        Router $router,
140
        ValidatorInterface $validator,
141
        EngineInterface $templating,
142
        FormFactory $formFactory,
143
        DocumentType $formType,
144
        ContainerInterface $container,
145
        SchemaUtils $schemaUtils
146
    ) {
147
        $this->response = $response;
148
        $this->restUtils = $restUtils;
149
        $this->router = $router;
150
        $this->validator = $validator;
151
        $this->templating = $templating;
152
        $this->formFactory = $formFactory;
153
        $this->formType = $formType;
154
        $this->container = $container;
155
        $this->schemaUtils = $schemaUtils;
156
    }
157
158
    /**
159
     * Setter for the tokenStorage
160
     *
161
     * @param TokenStorage $tokenStorage The token storage
162
     * @return void
163
     */
164
    public function setTokenStorage(TokenStorage $tokenStorage)
165
    {
166
        $this->tokenStorage = $tokenStorage;
167
    }
168
169
    /**
170
     * Set form data mapper
171
     *
172
     * @param FormDataMapperInterface $formDataMapper Form data mapper
173
     * @return void
174
     */
175
    public function setFormDataMapper(FormDataMapperInterface $formDataMapper)
176
    {
177
        $this->formDataMapper = $formDataMapper;
178
    }
179
180
    /**
181
     * @param JsonPatchValidator $jsonPatchValidator Service for validation json patch
182
     * @return void
183
     */
184
    public function setJsonPatchValidator(JsonPatchValidator $jsonPatchValidator)
185
    {
186
        $this->jsonPatchValidator = $jsonPatchValidator;
187
    }
188
189
    /**
190
     * Defines the Form validator to be used.
191
     *
192
     * @param Form $validator Validator to be used
193
     *
194
     * @return void
195
     */
196
    public function setFormValidator(Form $validator)
197
    {
198
        $this->formValidator = $validator;
199
    }
200
201
    /**
202
     * Get the container object
203
     *
204
     * @return \Symfony\Component\DependencyInjection\ContainerInterface
205
     *
206
     * @obsolete
207
     */
208
    public function getContainer()
209
    {
210
        return $this->container;
211
    }
212
213
    /**
214
     * Returns a single record
215
     *
216
     * @param Request $request Current http request
217
     * @param string  $id      ID of record
218
     *
219
     * @return \Symfony\Component\HttpFoundation\Response $response Response with result or error
220
     */
221
    public function getAction(Request $request, $id)
222
    {
223
        $response = $this->getResponse()
224
            ->setStatusCode(Response::HTTP_OK);
225
226
        $record = $this->findRecord($id);
227
228
        return $this->render(
229
            'GravitonRestBundle:Main:index.json.twig',
230
            ['response' => $this->serialize($record)],
231
            $response
232
        );
233
    }
234
235
    /**
236
     * Get the response object
237
     *
238
     * @return \Symfony\Component\HttpFoundation\Response $response Response object
239
     */
240
    public function getResponse()
241
    {
242
        return $this->response;
243
    }
244
245
    /**
246
     * Get a single record from database or throw an exception if it doesn't exist
247
     *
248
     * @param mixed $id Record id
249
     *
250
     * @throws \Graviton\ExceptionBundle\Exception\NotFoundException
251
     *
252
     * @return object $record Document object
253
     */
254
    protected function findRecord($id)
255
    {
256
        $response = $this->getResponse();
257
258
        if (!($record = $this->getModel()->find($id))) {
259
            $e = new NotFoundException("Entry with id " . $id . " not found!");
260
            $e->setResponse($response);
261
            throw $e;
262
        }
263
264
        return $record;
265
    }
266
267
    /**
268
     * Return the model
269
     *
270
     * @throws \Exception in case no model was defined.
271
     *
272
     * @return DocumentModel $model Model
273
     */
274
    public function getModel()
275
    {
276
        if (!$this->model) {
277
            throw new \Exception('No model is set for this controller');
278
        }
279
280
        return $this->model;
281
    }
282
283
    /**
284
     * Set the model class
285
     *
286
     * @param DocumentModel $model Model class
287
     *
288
     * @return self
289
     */
290
    public function setModel(DocumentModel $model)
291
    {
292
        $this->model = $model;
293
294
        return $this;
295
    }
296
297
    /**
298
     * Serialize the given record and throw an exception if something went wrong
299
     *
300
     * @param object|object[] $result Record(s)
301
     *
302
     * @throws \Graviton\ExceptionBundle\Exception\SerializationException
303
     *
304
     * @return string $content Json content
305
     */
306
    protected function serialize($result)
307
    {
308
        $response = $this->getResponse();
309
310
        try {
311
            // array is serialized as an object {"0":{...},"1":{...},...} when data contains an empty objects
312
            // we serialize each item because we can assume this bug affects only root array element
313
            if (is_array($result) && array_keys($result) === range(0, count($result) - 1)) {
314
                $result = array_map(
315
                    function ($item) {
316
                        return $this->getRestUtils()->serializeContent($item);
317
                    },
318
                    $result
319
                );
320
321
                /*
322
                 * clean up:
323
                 *
324
                 * - remove empty entries
325
                 */
326
                $result = array_filter($result);
327
328
                return '['.implode(',', $result).']';
329
            }
330
331
            return $this->getRestUtils()->serializeContent($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by parameter $result on line 306 can also be of type array; however, Graviton\RestBundle\Serv...ils::serializeContent() does only seem to accept object, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and 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...
332
        } catch (\Exception $e) {
333
            $exception = new SerializationException($e);
334
            $exception->setResponse($response);
335
            throw $exception;
336
        }
337
    }
338
339
    /**
340
     * Get RestUtils service
341
     *
342
     * @return \Graviton\RestBundle\Service\RestUtils
343
     */
344
    public function getRestUtils()
345
    {
346
        return $this->restUtils;
347
    }
348
349
    /**
350
     * Returns all records
351
     *
352
     * @param Request $request Current http request
353
     *
354
     * @return \Symfony\Component\HttpFoundation\Response $response Response with result or error
355
     */
356
    public function allAction(Request $request)
357
    {
358
        $model = $this->getModel();
359
360
        list($app, $module, , $modelName, $schemaType) = explode('.', $request->attributes->get('_route'));
361
362
        $schema = $this->schemaUtils->getModelSchema($modelName, $model);
363
364
        // Security is optional configured in Parameters
365
        try {
366
            /** @var SecurityUser $securityUser */
367
            $securityUser = $this->getSecurityUser();
368
        } catch (PreconditionRequiredHttpException $e) {
369
            $securityUser = null;
370
        }
371
372
        if ($model instanceof PaginatorAwareInterface && !$model->hasPaginator()) {
373
            $paginator = new Paginator();
374
            $model->setPaginator($paginator);
375
        }
376
377
        $response = $this->getResponse()
378
            ->setStatusCode(Response::HTTP_OK);
379
380
        return $this->render(
381
            'GravitonRestBundle:Main:index.json.twig',
382
            ['response' => $this->serialize($model->findAll($request, $securityUser, $schema))],
383
            $response
384
        );
385
    }
386
387
    /**
388
     * Writes a new Entry to the database
389
     *
390
     * @param Request $request Current http request
391
     *
392
     * @return \Symfony\Component\HttpFoundation\Response $response Result of action with data (if successful)
393
     */
394
    public function postAction(Request $request)
395
    {
396
        // Get the response object from container
397
        $response = $this->getResponse();
398
        $model = $this->getModel();
399
400
        $this->formValidator->checkJsonRequest($request, $response);
401
        $record = $this->formValidator->checkForm(
402
            $this->formValidator->getForm($request, $model),
403
            $model,
404
            $this->formDataMapper,
405
            $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, Graviton\RestBundle\Validator\Form::checkForm() does only seem to accept string, 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...
406
        );
407
408
        // Insert the new record
409
        $record = $this->getModel()->insertRecord($record);
410
411
        // store id of new record so we dont need to reparse body later when needed
412
        $request->attributes->set('id', $record->getId());
413
414
        // Set status code
415
        $response->setStatusCode(Response::HTTP_CREATED);
416
417
        $response->headers->set(
418
            'Location',
419
            $this->getRouter()->generate($this->getRouteName($request), array('id' => $record->getId()))
420
        );
421
422
        return $response;
423
    }
424
425
    /**
426
     * Deserialize the given content throw an exception if something went wrong
427
     *
428
     * @param string $content       Request content
429
     * @param string $documentClass Document class
430
     *
431
     * @throws DeserializationException
432
     *
433
     * @return object $record Document
0 ignored issues
show
Documentation introduced by
Should the return type not be object|array|integer|double|string|boolean? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
434
     */
435
    protected function deserialize($content, $documentClass)
436
    {
437
        $response = $this->getResponse();
438
439
        try {
440
            $record = $this->getRestUtils()->deserializeContent(
441
                $content,
442
                $documentClass
443
            );
444
        } catch (\Exception $e) {
445
            // pass the previous exception in this case to get the error message in the handler
446
            // http://php.net/manual/de/exception.getprevious.php
447
            $exception = new DeserializationException("Deserialization failed", $e);
448
449
            // at the moment, the response has to be set on the exception object.
450
            // try to refactor this and return the graviton.rest.response if none is set...
451
            $exception->setResponse($response);
452
            throw $exception;
453
        }
454
455
        return $record;
456
    }
457
458
    /**
459
     * Get the router from the dic
460
     *
461
     * @return Router
462
     */
463
    public function getRouter()
464
    {
465
        return $this->router;
466
    }
467
468
    /**
469
     * Update a record
470
     *
471
     * @param Number  $id      ID of record
472
     * @param Request $request Current http request
473
     *
474
     * @throws MalformedInputException
475
     *
476
     * @return Response $response Result of action with data (if successful)
0 ignored issues
show
Documentation introduced by
Should the return type not be Response|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
477
     */
478
    public function putAction($id, Request $request)
479
    {
480
        $response = $this->getResponse();
481
        $model = $this->getModel();
482
483
        $this->formValidator->checkJsonRequest($request, $response);
484
485
        list(, , , $modelName, ) = explode('.', $request->attributes->get('_route'));
486
487
        $file = '/tmp/hans-'.$modelName;
488
489
        if (!file_exists($file)) {
490
            $schema = $this->getRestUtils()->serializeContent($this->schemaUtils->getModelSchema($modelName, $this->getModel()));
491
            $schema = json_decode($schema);
492
            file_put_contents($file, $schema);
493
        } else {
494
            $schema = file_get_contents($file);
495
        }
496
497
        $validator = new ValidatorService('JsonSchema\Validator');
498
499
        try {
500
            $validator->check(json_decode($request->getContent()), $schema);
501
        } catch (\Exception $e) {
502
            var_dump($validator->getErrors());
0 ignored issues
show
Security Debugging Code introduced by
var_dump($validator->getErrors()); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
503
            die;
0 ignored issues
show
Coding Style Compatibility introduced by
The method putAction() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
504
        }
505
506
        $record = $this->getRestUtils()->deserializeContent($request->getContent(), $model->getEntityClass());
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, Graviton\RestBundle\Serv...s::deserializeContent() does only seem to accept string, 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...
507
508
        /*
509
        $validator = new Validator(
510
            ,
511
            json_decode($schema)
512
        );
513
        */
514
515
        /*
516
        $record = $this->formValidator->checkForm(
517
            $this->formValidator->getForm($request, $model),
518
            $model,
519
            $this->formDataMapper,
520
            $request->getContent()
521
        );
522
        */
523
524
        // does it really exist??
525
        $upsert = false;
526
        try {
527
            $this->findRecord($id);
528
        } catch (NotFoundException $e) {
529
            // who cares, we'll upsert it
530
            $upsert = true;
531
        }
532
533
        // handle missing 'id' field in input to a PUT operation
534
        // if it is settable on the document, let's set it and move on.. if not, inform the user..
535
        if ($record->getId() != $id) {
536
            // try to set it..
537
            if (is_callable(array($record, 'setId'))) {
538
                $record->setId($id);
539
            } else {
540
                throw new MalformedInputException('No ID was supplied in the request payload.');
541
            }
542
        }
543
544
        // And update the record, if everything is ok
545
        if ($upsert) {
546
            $this->getModel()->insertRecord($record);
547
        } else {
548
            $this->getModel()->updateRecord($id, $record);
549
        }
550
551
        // Set status code
552
        $response->setStatusCode(Response::HTTP_NO_CONTENT);
553
554
        // store id of new record so we dont need to reparse body later when needed
555
        $request->attributes->set('id', $record->getId());
556
557
        return $response;
558
    }
559
560
    /**
561
     * Patch a record
562
     *
563
     * @param Number  $id      ID of record
564
     * @param Request $request Current http request
565
     *
566
     * @throws MalformedInputException
567
     *
568
     * @return Response $response Result of action with data (if successful)
569
     */
570
    public function patchAction($id, Request $request)
571
    {
572
        $response = $this->getResponse();
573
        $this->formValidator->checkJsonRequest($request, $response);
574
575
        // Check JSON Patch request
576
        $this->formValidator->checkJsonPatchRequest(json_decode($request->getContent(), 1));
577
578
        // Find record && apply $ref converter
579
        $record = $this->findRecord($id);
580
        $jsonDocument = $this->serialize($record);
581
582
        // Check/validate JSON Patch
583
        if (!$this->jsonPatchValidator->validate($jsonDocument, $request->getContent())) {
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, Graviton\RestBundle\Serv...chValidator::validate() does only seem to accept string, 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...
584
            throw new InvalidJsonPatchException($this->jsonPatchValidator->getException()->getMessage());
585
        }
586
587
        try {
588
            // Apply JSON patches
589
            $patch = new Patch($jsonDocument, $request->getContent());
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, Rs\Json\Patch::__construct() does only seem to accept string, 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...
590
            $patchedDocument = $patch->apply();
591
        } catch (InvalidPatchDocumentJsonException $e) {
592
            throw new InvalidJsonPatchException($e->getMessage());
593
        } catch (InvalidTargetDocumentJsonException $e) {
594
            throw new InvalidJsonPatchException($e->getMessage());
595
        } catch (InvalidOperationException $e) {
596
            throw new InvalidJsonPatchException($e->getMessage());
597
        } catch (FailedTestException $e) {
598
            throw new InvalidJsonPatchException($e->getMessage());
599
        }
600
601
        // Validate result object
602
        $model = $this->getModel();
603
        $record = $this->formValidator->checkForm(
604
            $this->formValidator->getForm($request, $model),
605
            $model,
606
            $this->formDataMapper,
607
            $patchedDocument
608
        );
609
610
        // Update object
611
        $this->getModel()->updateRecord($id, $record);
612
613
        // Set status code
614
        $response->setStatusCode(Response::HTTP_OK);
615
616
        // Set Content-Location header
617
        $response->headers->set(
618
            'Content-Location',
619
            $this->getRouter()->generate($this->getRouteName($request), array('id' => $record->getId()))
620
        );
621
622
        return $response;
623
    }
624
625
    /**
626
     * Deletes a record
627
     *
628
     * @param Number $id ID of record
629
     *
630
     * @return Response $response Result of the action
631
     */
632
    public function deleteAction($id)
633
    {
634
        $response = $this->getResponse();
635
636
        // does this record exist?
637
        $this->findRecord($id);
638
639
        $this->getModel()->deleteRecord($id);
640
        $response->setStatusCode(Response::HTTP_NO_CONTENT);
641
642
        return $response;
643
    }
644
645
    /**
646
     * Return OPTIONS results.
647
     *
648
     * @param Request $request Current http request
649
     *
650
     * @throws SerializationException
651
     * @return \Symfony\Component\HttpFoundation\Response $response Result of the action
652
     */
653
    public function optionsAction(Request $request)
654
    {
655
        list($app, $module, , $modelName) = explode('.', $request->attributes->get('_route'));
656
657
        $response = $this->response;
658
        $response->setStatusCode(Response::HTTP_NO_CONTENT);
659
660
        // enabled methods for CorsListener
661
        $corsMethods = 'GET, POST, PUT, PATCH, DELETE, OPTIONS';
662
        try {
663
            $router = $this->getRouter();
664
            // if post route is available we assume everything is readable
665
            $router->generate(implode('.', array($app, $module, 'rest', $modelName, 'post')));
666
        } catch (RouteNotFoundException $exception) {
667
            // only allow read methods
668
            $corsMethods = 'GET, OPTIONS';
669
        }
670
        $request->attributes->set('corsMethods', $corsMethods);
671
672
        return $response;
673
    }
674
675
676
    /**
677
     * Return schema GET results.
678
     *
679
     * @param Request $request Current http request
680
     * @param string  $id      ID of record
0 ignored issues
show
Documentation introduced by
Should the type for parameter $id not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
681
     *
682
     * @throws SerializationException
683
     * @return \Symfony\Component\HttpFoundation\Response $response Result of the action
684
     */
685
    public function schemaAction(Request $request, $id = null)
686
    {
687
        $request->attributes->set('schemaRequest', true);
688
689
        list($app, $module, , $modelName, $schemaType) = explode('.', $request->attributes->get('_route'));
690
691
        $response = $this->response;
692
        $response->setStatusCode(Response::HTTP_OK);
693
        $response->setPublic();
694
695
        if (!$id && $schemaType != 'canonicalIdSchema') {
696
            $schema = $this->schemaUtils->getCollectionSchema($modelName, $this->getModel());
697
        } else {
698
            $schema = $this->schemaUtils->getModelSchema($modelName, $this->getModel());
699
        }
700
701
        // enabled methods for CorsListener
702
        $corsMethods = 'GET, POST, PUT, PATCH, DELETE, OPTIONS';
703
        try {
704
            $router = $this->getRouter();
705
            // if post route is available we assume everything is readable
706
            $router->generate(implode('.', array($app, $module, 'rest', $modelName, 'post')));
707
        } catch (RouteNotFoundException $exception) {
708
            // only allow read methods
709
            $corsMethods = 'GET, OPTIONS';
710
        }
711
        $request->attributes->set('corsMethods', $corsMethods);
712
713
714
        return $this->render(
715
            'GravitonRestBundle:Main:index.json.twig',
716
            ['response' => $this->serialize($schema)],
717
            $response
718
        );
719
    }
720
721
    /**
722
     * Get the validator
723
     *
724
     * @return ValidatorInterface
725
     */
726
    public function getValidator()
727
    {
728
        return $this->validator;
729
    }
730
731
    /**
732
     * Renders a view.
733
     *
734
     * @param string   $view       The view name
735
     * @param array    $parameters An array of parameters to pass to the view
736
     * @param Response $response   A response instance
0 ignored issues
show
Documentation introduced by
Should the type for parameter $response not be null|Response?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
737
     *
738
     * @return Response A Response instance
739
     */
740
    public function render($view, array $parameters = array(), Response $response = null)
741
    {
742
        return $this->templating->renderResponse($view, $parameters, $response);
743
    }
744
745
    /**
746
     * @param Request $request request
747
     * @return string
748
     */
749
    private function getRouteName(Request $request)
750
    {
751
        $routeName = $request->get('_route');
752
        $routeParts = explode('.', $routeName);
753
        $routeType = end($routeParts);
754
755
        if ($routeType == 'post') {
756
            $routeName = substr($routeName, 0, -4) . 'get';
757
        }
758
759
        return $routeName;
760
    }
761
762
    /**
763
     * Security needs to be enabled to get Object.
764
     *
765
     * @return SecurityUser
0 ignored issues
show
Documentation introduced by
Should the return type not be UserInterface?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
766
     * @throws PreconditionRequiredHttpException
767
     */
768
    public function getSecurityUser()
769
    {
770
        /** @var PreAuthenticatedToken $token */
771
        if (($token = $this->tokenStorage->getToken())
772
            && ($user = $token->getUser()) instanceof UserInterface ) {
773
            return $user;
774
        }
775
776
        throw new PreconditionRequiredHttpException('Not allowed');
777
    }
778
}
779