Completed
Push — feature/other-validation ( a3189f...c451b7 )
by Narcotic
13:21
created

RestController::validateRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 5
nc 2
nop 2
crap 2
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\Exception\ValidationException;
15
use Graviton\RestBundle\Validator\Form;
16
use Graviton\RestBundle\Model\DocumentModel;
17
use Graviton\RestBundle\Model\PaginatorAwareInterface;
18
use Graviton\SchemaBundle\SchemaUtils;
19
use Graviton\DocumentBundle\Form\Type\DocumentType;
20
use Graviton\RestBundle\Service\RestUtilsInterface;
21
use Symfony\Component\Security\Core\User\UserInterface;
22
use Knp\Component\Pager\Paginator;
23
use Symfony\Component\DependencyInjection\ContainerInterface;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\HttpFoundation\Response;
26
use Symfony\Component\HttpKernel\Exception\PreconditionRequiredHttpException;
27
use Symfony\Component\Routing\Exception\RouteNotFoundException;
28
use Symfony\Component\Form\FormFactory;
29
use Symfony\Bundle\FrameworkBundle\Routing\Router;
30
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
31
use Symfony\Component\Validator\Validator\ValidatorInterface;
32
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
33
use Rs\Json\Patch;
34
use Rs\Json\Patch\InvalidPatchDocumentJsonException;
35
use Rs\Json\Patch\InvalidTargetDocumentJsonException;
36
use Rs\Json\Patch\InvalidOperationException;
37
use Rs\Json\Patch\FailedTestException;
38
use Graviton\RestBundle\Service\JsonPatchValidator;
39
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
40
41
/**
42
 * This is a basic rest controller. It should fit the most needs but if you need to add some
43
 * extra functionality you can extend it and overwrite single/all actions.
44
 * You can also extend the model class to add some extra logic before save
45
 *
46
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
47
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
48
 * @link     http://swisscom.ch
49
 */
50
class RestController
51
{
52
    /**
53
     * @var DocumentModel
54
     */
55
    private $model;
56
57
    /**
58
     * @var ContainerInterface service_container
59
     */
60
    private $container;
61
62
    /**
63
     * @var Response
64
     */
65
    private $response;
66
67
    /**
68
     * @var FormFactory
69
     */
70
    private $formFactory;
71
72
    /**
73
     * @var DocumentType
74
     */
75
    private $formType;
76
77
    /**
78
     * @var RestUtilsInterface
79
     */
80
    private $restUtils;
81
82
    /**
83
     * @var SchemaUtils
84
     */
85
    private $schemaUtils;
86
87
    /**
88
     * @var FormDataMapperInterface
89
     */
90
    protected $formDataMapper;
91
92
    /**
93
     * @var Router
94
     */
95
    private $router;
96
97
    /**
98
     * @var ValidatorInterface
99
     */
100
    private $validator;
101
102
    /**
103
     * @var EngineInterface
104
     */
105
    private $templating;
106
107
    /**
108
     * @var JsonPatchValidator
109
     */
110
    private $jsonPatchValidator;
111
112
    /**
113
     * @var Form
114
     */
115
    protected $formValidator;
116
117
    /**
118
     * @var TokenStorage
119
     */
120
    protected $tokenStorage;
121
122
    /**
123
     * @param Response           $response    Response
124
     * @param RestUtilsInterface $restUtils   Rest utils
125
     * @param Router             $router      Router
126
     * @param ValidatorInterface $validator   Validator
127
     * @param EngineInterface    $templating  Templating
128
     * @param FormFactory        $formFactory form factory
129
     * @param DocumentType       $formType    generic form
130
     * @param ContainerInterface $container   Container
131
     * @param SchemaUtils        $schemaUtils Schema utils
132
     */
133 4
    public function __construct(
134
        Response $response,
135
        RestUtilsInterface $restUtils,
136
        Router $router,
137
        ValidatorInterface $validator,
138
        EngineInterface $templating,
139
        FormFactory $formFactory,
140
        DocumentType $formType,
141
        ContainerInterface $container,
142
        SchemaUtils $schemaUtils
143
    ) {
144 4
        $this->response = $response;
145 4
        $this->restUtils = $restUtils;
146 4
        $this->router = $router;
147 4
        $this->validator = $validator;
148 4
        $this->templating = $templating;
149 4
        $this->formFactory = $formFactory;
150 4
        $this->formType = $formType;
151 4
        $this->container = $container;
152 4
        $this->schemaUtils = $schemaUtils;
153 4
    }
154
155
    /**
156
     * Setter for the tokenStorage
157
     *
158
     * @param TokenStorage $tokenStorage The token storage
159
     * @return void
160
     */
161 4
    public function setTokenStorage(TokenStorage $tokenStorage)
162
    {
163 4
        $this->tokenStorage = $tokenStorage;
164 4
    }
165
166
    /**
167
     * Set form data mapper
168
     *
169
     * @param FormDataMapperInterface $formDataMapper Form data mapper
170
     * @return void
171
     */
172 4
    public function setFormDataMapper(FormDataMapperInterface $formDataMapper)
173
    {
174 4
        $this->formDataMapper = $formDataMapper;
175 4
    }
176
177
    /**
178
     * @param JsonPatchValidator $jsonPatchValidator Service for validation json patch
179
     * @return void
180
     */
181 4
    public function setJsonPatchValidator(JsonPatchValidator $jsonPatchValidator)
182
    {
183 4
        $this->jsonPatchValidator = $jsonPatchValidator;
184 4
    }
185
186
    /**
187
     * Defines the Form validator to be used.
188
     *
189
     * @param Form $validator Validator to be used
190
     *
191
     * @return void
192
     */
193 4
    public function setFormValidator(Form $validator)
194
    {
195 4
        $this->formValidator = $validator;
196 4
    }
197
198
    /**
199
     * Get the container object
200
     *
201
     * @return \Symfony\Component\DependencyInjection\ContainerInterface
202
     *
203
     * @obsolete
204
     */
205
    public function getContainer()
206
    {
207
        return $this->container;
208
    }
209
210
    /**
211
     * Returns a single record
212
     *
213
     * @param Request $request Current http request
214
     * @param string  $id      ID of record
215
     *
216
     * @return \Symfony\Component\HttpFoundation\Response $response Response with result or error
217
     */
218 4
    public function getAction(Request $request, $id)
219
    {
220 4
        $response = $this->getResponse()
221 4
            ->setStatusCode(Response::HTTP_OK);
222
223 4
        $record = $this->findRecord($id);
224
225 4
        return $this->render(
226 4
            'GravitonRestBundle:Main:index.json.twig',
227 4
            ['response' => $this->serialize($record)],
0 ignored issues
show
Bug introduced by
It seems like $record defined by $this->findRecord($id) on line 223 can also be of type null; however, Graviton\RestBundle\Cont...Controller::serialize() does only seem to accept object|array<integer,object>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
228
            $response
229 2
        );
230
    }
231
232
    /**
233
     * Get the response object
234
     *
235
     * @return \Symfony\Component\HttpFoundation\Response $response Response object
236
     */
237 4
    public function getResponse()
238
    {
239 4
        return $this->response;
240
    }
241
242
    /**
243
     * Get a single record from database or throw an exception if it doesn't exist
244
     *
245
     * @param mixed $id Record id
246
     *
247
     * @throws \Graviton\ExceptionBundle\Exception\NotFoundException
248
     *
249
     * @return object $record Document object
0 ignored issues
show
Documentation introduced by
Should the return type not be object|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...
250
     */
251 4
    protected function findRecord($id)
252
    {
253 4
        $response = $this->getResponse();
254
255 4
        if (!($this->getModel()->recordExists($id))) {
256
            $e = new NotFoundException("Entry with id " . $id . " not found!");
257
            $e->setResponse($response);
258
            throw $e;
259
        }
260
261 4
        return $this->getModel()->find($id);
262
    }
263
264
    /**
265
     * Return the model
266
     *
267
     * @throws \Exception in case no model was defined.
268
     *
269
     * @return DocumentModel $model Model
270
     */
271 4
    public function getModel()
272
    {
273 4
        if (!$this->model) {
274
            throw new \Exception('No model is set for this controller');
275
        }
276
277 4
        return $this->model;
278
    }
279
280
    /**
281
     * Set the model class
282
     *
283
     * @param DocumentModel $model Model class
284
     *
285
     * @return self
286
     */
287 4
    public function setModel(DocumentModel $model)
288
    {
289 4
        $this->model = $model;
290
291 4
        return $this;
292
    }
293
294
    /**
295
     * Serialize the given record and throw an exception if something went wrong
296
     *
297
     * @param object|object[] $result Record(s)
298
     *
299
     * @throws \Graviton\ExceptionBundle\Exception\SerializationException
300
     *
301
     * @return string $content Json content
302
     */
303 4
    protected function serialize($result)
304
    {
305 4
        $response = $this->getResponse();
306
307
        try {
308
            // array is serialized as an object {"0":{...},"1":{...},...} when data contains an empty objects
309
            // we serialize each item because we can assume this bug affects only root array element
310 4
            if (is_array($result) && array_keys($result) === range(0, count($result) - 1)) {
311
                $result = array_map(
312
                    function ($item) {
313
                        return $this->getRestUtils()->serializeContent($item);
314
                    },
315
                    $result
316
                );
317
318
                /*
319
                 * clean up:
320
                 *
321
                 * - remove empty entries
322
                 */
323
                $result = array_filter($result);
324
325
                return '['.implode(',', $result).']';
326
            }
327
328 4
            return $this->getRestUtils()->serializeContent($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by parameter $result on line 303 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...
329
        } catch (\Exception $e) {
330
            $exception = new SerializationException($e);
331
            $exception->setResponse($response);
332
            throw $exception;
333
        }
334
    }
335
336
    /**
337
     * Get RestUtils service
338
     *
339
     * @return \Graviton\RestBundle\Service\RestUtils
340
     */
341 4
    public function getRestUtils()
342
    {
343 4
        return $this->restUtils;
344
    }
345
346
    /**
347
     * Returns all records
348
     *
349
     * @param Request $request Current http request
350
     *
351
     * @return \Symfony\Component\HttpFoundation\Response $response Response with result or error
352
     */
353
    public function allAction(Request $request)
354
    {
355
        $model = $this->getModel();
356
357
        list(, , , $modelName, ) = explode('.', $request->attributes->get('_route'));
358
359
        $schema = $this->schemaUtils->getModelSchema($modelName, $model);
360
361
        // Security is optional configured in Parameters
362
        try {
363
            /** @var SecurityUser $securityUser */
364
            $securityUser = $this->getSecurityUser();
365
        } catch (PreconditionRequiredHttpException $e) {
366
            $securityUser = null;
367
        }
368
369
        if ($model instanceof PaginatorAwareInterface && !$model->hasPaginator()) {
370
            $paginator = new Paginator();
371
            $model->setPaginator($paginator);
372
        }
373
374
        $response = $this->getResponse()
375
            ->setStatusCode(Response::HTTP_OK);
376
377
        return $this->render(
378
            'GravitonRestBundle:Main:index.json.twig',
379
            ['response' => $this->serialize($model->findAll($request, $securityUser, $schema))],
380
            $response
381
        );
382
    }
383
384
    /**
385
     * Writes a new Entry to the database
386
     *
387
     * @param Request $request Current http request
388
     *
389
     * @return \Symfony\Component\HttpFoundation\Response $response Result of action with data (if successful)
390
     */
391
    public function postAction(Request $request)
392
    {
393
        // Get the response object from container
394
        $response = $this->getResponse();
395
        $model = $this->getModel();
396
397
        $this->restUtils->checkJsonRequest($request, $response, $this->getModel());
398
399
        $record = $this->validateRequest($request->getContent(), $model);
0 ignored issues
show
Documentation introduced by
$request->getContent() is of type resource|string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
400
401
        // Insert the new record
402
        $record = $this->getModel()->insertRecord($record);
403
404
        // store id of new record so we dont need to reparse body later when needed
405
        $request->attributes->set('id', $record->getId());
406
407
        // Set status code
408
        $response->setStatusCode(Response::HTTP_CREATED);
409
410
        $response->headers->set(
411
            'Location',
412
            $this->getRouter()->generate($this->getRouteName($request), array('id' => $record->getId()))
413
        );
414
415
        return $response;
416
    }
417
418
    /**
419
     * Validates the current request on schema violations. If there are errors,
420
     * the exception is thrown. If not, the deserialized record is returned.
421
     *
422
     * @param object        $content \stdClass of the request content
423
     * @param DocumentModel $model   the model to check the schema for
424
     *
425
     * @return \Graviton\JsonSchemaBundle\Exception\ValidationExceptionError[]
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...
426
     * @throws \Exception
427
     */
428 4
    protected function validateRequest($content, DocumentModel $model)
429
    {
430 4
        $errors = $this->restUtils->validateContent($content, $model);
431 4
        if (!empty($errors)) {
432 2
            throw new ValidationException($errors);
433
        }
434 2
        return $this->deserialize($content, $model->getEntityClass());
0 ignored issues
show
Documentation introduced by
$content is of type object, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
435
    }
436
437
    /**
438
     * Deserialize the given content throw an exception if something went wrong
439
     *
440
     * @param string $content       Request content
441
     * @param string $documentClass Document class
442
     *
443
     * @throws DeserializationException
444
     *
445
     * @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...
446
     */
447 2
    protected function deserialize($content, $documentClass)
448
    {
449 2
        $response = $this->getResponse();
450
451
        try {
452 2
            $record = $this->getRestUtils()->deserializeContent(
453 1
                $content,
454
                $documentClass
455 1
            );
456 1
        } catch (\Exception $e) {
457
            // pass the previous exception in this case to get the error message in the handler
458
            // http://php.net/manual/de/exception.getprevious.php
459
            $exception = new DeserializationException("Deserialization failed", $e);
460
461
            // at the moment, the response has to be set on the exception object.
462
            // try to refactor this and return the graviton.rest.response if none is set...
463
            $exception->setResponse($response);
464
            throw $exception;
465
        }
466
467 2
        return $record;
468
    }
469
470
    /**
471
     * Get the router from the dic
472
     *
473
     * @return Router
474
     */
475
    public function getRouter()
476
    {
477
        return $this->router;
478
    }
479
480
    /**
481
     * Update a record
482
     *
483
     * @param Number  $id      ID of record
484
     * @param Request $request Current http request
485
     *
486
     * @throws MalformedInputException
487
     *
488
     * @return Response $response Result of action with data (if successful)
489
     */
490 4
    public function putAction($id, Request $request)
491
    {
492 4
        $response = $this->getResponse();
493 4
        $model = $this->getModel();
494
495 4
        $this->restUtils->checkJsonRequest($request, $response, $this->getModel());
496
497 4
        $record = $this->validateRequest($request->getContent(), $model);
0 ignored issues
show
Documentation introduced by
$request->getContent() is of type resource|string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
498
499
        // handle missing 'id' field in input to a PUT operation
500
        // if it is settable on the document, let's set it and move on.. if not, inform the user..
501 2
        if ($record->getId() != $id) {
502
            // try to set it..
503
            if (is_callable(array($record, 'setId'))) {
504
                $record->setId($id);
505
            } else {
506
                throw new MalformedInputException('No ID was supplied in the request payload.');
507
            }
508
        }
509
510
        // And update the record, if everything is ok
511 2
        if (!$this->getModel()->recordExists($id)) {
512
            $this->getModel()->insertRecord($record, false);
513
        } else {
514 2
            $this->getModel()->updateRecord($id, $record, false);
515
        }
516
517
        // Set status code
518 2
        $response->setStatusCode(Response::HTTP_NO_CONTENT);
519
520
        // store id of new record so we dont need to reparse body later when needed
521 2
        $request->attributes->set('id', $record->getId());
522
523 2
        return $response;
524
    }
525
526
    /**
527
     * Patch a record
528
     *
529
     * @param Number  $id      ID of record
530
     * @param Request $request Current http request
531
     *
532
     * @throws MalformedInputException
533
     *
534
     * @return Response $response Result of action with data (if successful)
535
     */
536
    public function patchAction($id, Request $request)
537
    {
538
        $response = $this->getResponse();
539
540
        // Check JSON Patch request
541
        $this->restUtils->checkJsonRequest($request, $response, $this->getModel());
542
        $this->restUtils->checkJsonPatchRequest(json_decode($request->getContent(), 1));
543
544
        // Find record && apply $ref converter
545
        $record = $this->findRecord($id);
546
        $jsonDocument = $this->serialize($record);
0 ignored issues
show
Bug introduced by
It seems like $record defined by $this->findRecord($id) on line 545 can also be of type null; however, Graviton\RestBundle\Cont...Controller::serialize() does only seem to accept object|array<integer,object>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
547
548
        // Check/validate JSON Patch
549
        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...
550
            throw new InvalidJsonPatchException($this->jsonPatchValidator->getException()->getMessage());
551
        }
552
553
        try {
554
            // Apply JSON patches
555
            $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...
556
            $patchedDocument = $patch->apply();
557
        } catch (InvalidPatchDocumentJsonException $e) {
558
            throw new InvalidJsonPatchException($e->getMessage());
559
        } catch (InvalidTargetDocumentJsonException $e) {
560
            throw new InvalidJsonPatchException($e->getMessage());
561
        } catch (InvalidOperationException $e) {
562
            throw new InvalidJsonPatchException($e->getMessage());
563
        } catch (FailedTestException $e) {
564
            throw new InvalidJsonPatchException($e->getMessage());
565
        }
566
567
        // Validate result object
568
        $model = $this->getModel();
569
        $record = $this->validateRequest($patchedDocument, $model);
0 ignored issues
show
Documentation introduced by
$patchedDocument is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
570
571
        // Update object
572
        $this->getModel()->updateRecord($id, $record);
573
574
        // Set status code
575
        $response->setStatusCode(Response::HTTP_OK);
576
577
        // Set Content-Location header
578
        $response->headers->set(
579
            'Content-Location',
580
            $this->getRouter()->generate($this->getRouteName($request), array('id' => $record->getId()))
581
        );
582
583
        return $response;
584
    }
585
586
    /**
587
     * Deletes a record
588
     *
589
     * @param Number $id ID of record
590
     *
591
     * @return Response $response Result of the action
592
     */
593
    public function deleteAction($id)
594
    {
595
        $response = $this->getResponse();
596
597
        // does this record exist?
598
        $this->findRecord($id);
599
600
        $this->getModel()->deleteRecord($id);
601
        $response->setStatusCode(Response::HTTP_NO_CONTENT);
602
603
        return $response;
604
    }
605
606
    /**
607
     * Return OPTIONS results.
608
     *
609
     * @param Request $request Current http request
610
     *
611
     * @throws SerializationException
612
     * @return \Symfony\Component\HttpFoundation\Response $response Result of the action
613
     */
614
    public function optionsAction(Request $request)
615
    {
616
        list($app, $module, , $modelName) = explode('.', $request->attributes->get('_route'));
617
618
        $response = $this->response;
619
        $response->setStatusCode(Response::HTTP_NO_CONTENT);
620
621
        // enabled methods for CorsListener
622
        $corsMethods = 'GET, POST, PUT, PATCH, DELETE, OPTIONS';
623
        try {
624
            $router = $this->getRouter();
625
            // if post route is available we assume everything is readable
626
            $router->generate(implode('.', array($app, $module, 'rest', $modelName, 'post')));
627
        } catch (RouteNotFoundException $exception) {
628
            // only allow read methods
629
            $corsMethods = 'GET, OPTIONS';
630
        }
631
        $request->attributes->set('corsMethods', $corsMethods);
632
633
        return $response;
634
    }
635
636
637
    /**
638
     * Return schema GET results.
639
     *
640
     * @param Request $request Current http request
641
     * @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...
642
     *
643
     * @throws SerializationException
644
     * @return \Symfony\Component\HttpFoundation\Response $response Result of the action
645
     */
646
    public function schemaAction(Request $request, $id = null)
647
    {
648
        $request->attributes->set('schemaRequest', true);
649
650
        list($app, $module, , $modelName, $schemaType) = explode('.', $request->attributes->get('_route'));
651
652
        $response = $this->response;
653
        $response->setStatusCode(Response::HTTP_OK);
654
        $response->setPublic();
655
656
        if (!$id && $schemaType != 'canonicalIdSchema') {
657
            $schema = $this->schemaUtils->getCollectionSchema($modelName, $this->getModel());
658
        } else {
659
            $schema = $this->schemaUtils->getModelSchema($modelName, $this->getModel());
660
        }
661
662
        // enabled methods for CorsListener
663
        $corsMethods = 'GET, POST, PUT, PATCH, DELETE, OPTIONS';
664
        try {
665
            $router = $this->getRouter();
666
            // if post route is available we assume everything is readable
667
            $router->generate(implode('.', array($app, $module, 'rest', $modelName, 'post')));
668
        } catch (RouteNotFoundException $exception) {
669
            // only allow read methods
670
            $corsMethods = 'GET, OPTIONS';
671
        }
672
        $request->attributes->set('corsMethods', $corsMethods);
673
674
675
        return $this->render(
676
            'GravitonRestBundle:Main:index.json.twig',
677
            ['response' => $this->serialize($schema)],
678
            $response
679
        );
680
    }
681
682
    /**
683
     * Get the validator
684
     *
685
     * @return ValidatorInterface
686
     */
687
    public function getValidator()
688
    {
689
        return $this->validator;
690
    }
691
692
    /**
693
     * Renders a view.
694
     *
695
     * @param string   $view       The view name
696
     * @param array    $parameters An array of parameters to pass to the view
697
     * @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...
698
     *
699
     * @return Response A Response instance
700
     */
701 4
    public function render($view, array $parameters = array(), Response $response = null)
702
    {
703 4
        return $this->templating->renderResponse($view, $parameters, $response);
704
    }
705
706
    /**
707
     * @param Request $request request
708
     * @return string
709
     */
710
    private function getRouteName(Request $request)
711
    {
712
        $routeName = $request->get('_route');
713
        $routeParts = explode('.', $routeName);
714
        $routeType = end($routeParts);
715
716
        if ($routeType == 'post') {
717
            $routeName = substr($routeName, 0, -4) . 'get';
718
        }
719
720
        return $routeName;
721
    }
722
723
    /**
724
     * Security needs to be enabled to get Object.
725
     *
726
     * @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...
727
     * @throws PreconditionRequiredHttpException
728
     */
729
    public function getSecurityUser()
730
    {
731
        /** @var PreAuthenticatedToken $token */
732
        if (($token = $this->tokenStorage->getToken())
733
            && ($user = $token->getUser()) instanceof UserInterface ) {
734
            return $user;
735
        }
736
737
        throw new PreconditionRequiredHttpException('Not allowed');
738
    }
739
}
740