Completed
Push — feature/evo-2472-whoami ( 066c1c...01f6e4 )
by
unknown
09:00
created

RestController::getSecurityUser()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
641
            $schema = $this->schemaUtils->getCollectionSchema($modelName, $this->getModel());
642
        } else {
643
            $schema = $this->schemaUtils->getModelSchema($modelName, $this->getModel());
644
        }
645
646
        // enabled methods for CorsListener
647
        $corsMethods = 'GET, POST, PUT, PATCH, DELETE, OPTIONS';
648
        try {
649
            $router = $this->getRouter();
650
            // if post route is available we assume everything is readable
651
            $router->generate(implode('.', array($app, $module, 'rest', $modelName, 'post')));
652
        } catch (RouteNotFoundException $exception) {
653
            // only allow read methods
654
            $corsMethods = 'GET, OPTIONS';
655
        }
656
        $request->attributes->set('corsMethods', $corsMethods);
657
658
        return $this->render(
659
            'GravitonRestBundle:Main:index.json.twig',
660
            ['response' => $this->serialize($schema)],
661
            $response
662
        );
663
    }
664
665
    /**
666
     * Get the validator
667
     *
668
     * @return ValidatorInterface
669
     */
670
    public function getValidator()
671
    {
672
        return $this->validator;
673
    }
674
675
    /**
676
     * Renders a view.
677
     *
678
     * @param string   $view       The view name
679
     * @param array    $parameters An array of parameters to pass to the view
680 2
     * @param Response $response   A response instance
681
     *
682 2
     * @return Response A Response instance
683
     */
684
    public function render($view, array $parameters = array(), Response $response = null)
685
    {
686
        return $this->templating->renderResponse($view, $parameters, $response);
687
    }
688
689
    /**
690
     * @param Request $request request
691
     * @return string
692
     */
693
    private function getRouteName(Request $request)
694
    {
695
        $routeName = $request->get('_route');
696
        $routeParts = explode('.', $routeName);
697
        $routeType = end($routeParts);
698
699
        if ($routeType == 'post') {
700
            $routeName = substr($routeName, 0, -4) . 'get';
701
        }
702
703
        return $routeName;
704
    }
705
706
    /**
707 1
     * Security needs to be enabled to get Object.
708
     *
709 1
     * @return SecurityUser | false
710 1
     */
711
    public function getSecurityUser()
712
    {
713
        /** @var PreAuthenticatedToken $token */
714
        if ($token = $this->tokenStorage->getToken()) {
715
            return $token->getUser();
716
        }
717
718
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Graviton\RestBundle\Cont...roller::getSecurityUser of type Graviton\SecurityBundle\Entities\SecurityUser.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
719
    }
720
721
    /**
722
     * If security is enable.
723
     * Result will be User object defined in Config or Anonymous User
724
     *
725
     * @return Object | false
726
     */
727
    public function getUser()
728
    {
729
        $user = $this->getSecurityUser();
730
        if ( $user instanceof SecurityUser) {
731
            return $user->getUser();
732
        }
733
734
        return false;
735
    }
736
}
737