ExceptionController::showAction()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 8.439
c 0
b 0
f 0
cc 6
eloc 20
nc 6
nop 4
1
<?php
2
3
namespace Victoire\Bundle\TwigBundle\Controller;
4
5
use Doctrine\ORM\EntityManager;
6
use Symfony\Bundle\TwigBundle\Controller\ExceptionController as BaseExceptionController;
7
use Symfony\Component\HttpFoundation\Request;
8
use Symfony\Component\HttpFoundation\RequestStack;
9
use Symfony\Component\HttpFoundation\Response;
10
use Symfony\Component\HttpKernel\Exception\FlattenException;
11
use Symfony\Component\HttpKernel\HttpKernelInterface;
12
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
13
use Symfony\Component\Routing\Router;
14
15
/**
16
 * Redirects to a victoire error page when facing a Flatted Exception.
17
 */
18
class ExceptionController extends BaseExceptionController
19
{
20
    private $em;
21
22
    /**
23
     * @var array Available locales for the Victoire website
24
     */
25
    private $availableLocales;
26
    /**
27
     * @var string the fallback locale
28
     */
29
    private $defaultLocale;
30
31
    /**
32
     * ExceptionController constructor.
33
     *
34
     * @param \Twig_Environment   $twig
35
     * @param bool                $debug
36
     * @param EntityManager       $em
37
     * @param HttpKernelInterface $httpKernel
38
     * @param RequestStack        $requestStack
39
     * @param Router              $router
40
     * @param array               $availableLocales
41
     * @param string              $defaultLocale
42
     */
43
    public function __construct(\Twig_Environment $twig, $debug, EntityManager $em, HttpKernelInterface $httpKernel, RequestStack $requestStack, Router $router, array $availableLocales, $defaultLocale)
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $em. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
44
    {
45
        parent::__construct($twig, $debug);
46
        $this->twig = $twig;
47
        $this->debug = $debug;
48
        $this->em = $em;
49
        $this->kernel = $httpKernel;
0 ignored issues
show
Bug introduced by
The property kernel does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
50
        $this->request = $requestStack->getCurrentRequest();
0 ignored issues
show
Bug introduced by
The property request does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
51
        $this->router = $router;
0 ignored issues
show
Bug introduced by
The property router does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
52
        $this->availableLocales = $availableLocales;
53
        $this->defaultLocale = $defaultLocale;
54
    }
55
56
    /**
57
     * Converts an Exception to a Response to be able to render a Victoire view.
58
     *
59
     * @param Request              $request   The request
60
     * @param FlattenException     $exception A FlattenException instance
61
     * @param DebugLoggerInterface $logger    A DebugLoggerInterface instance
62
     * @param string               $_format   The format to use for rendering (html, xml, ...)
63
     *
64
     * @throws \InvalidArgumentException When the exception template does not exist
65
     *
66
     * @return Response
67
     */
68
    public function showAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null, $_format = 'html')
69
    {
70
        $currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1));
0 ignored issues
show
Documentation introduced by
$request->headers->get('X-Php-Ob-Level', -1) is of type string|array, but the function expects a integer.

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...
71
        $code = $exception->getStatusCode();
72
73
        //get request extension
74
        $uriArray = explode('/', rtrim($request->getRequestUri(), '/'));
75
76
        $matches = preg_match('/^.*(\..*)$/', array_pop($uriArray), $matches);
77
78
        $locale = $request->getLocale();
79
        if (!in_array($locale, $this->availableLocales, true)) {
80
            $request->setLocale($this->defaultLocale);
81
        }
82
        //if in production environment and the query is not a file
83
        if ($this->debug === false && 0 === $matches) {
84
            $page = $this->em->getRepository('VictoireTwigBundle:ErrorPage')->findOneByCode($code);
85
            if ($page) {
86
                return $this->forward('VictoireTwigBundle:ErrorPage:show', [
87
                        'code'    => $page->getCode(),
88
                ]);
89
            }
90
        }
91
92
        return new Response($this->twig->render(
93
            $this->findTemplate($request, $_format, $code, $this->debug),
94
            [
95
                'status_code'    => $code,
96
                'status_text'    => isset(Response::$statusTexts[$code]) ? Response::$statusTexts[$code] : '',
97
                'exception'      => $exception,
98
                'logger'         => $logger,
99
                'currentContent' => $currentContent,
100
            ]
101
        ));
102
    }
103
104
    /**
105
     * Forwards the request to another controller.
106
     *
107
     * @param string $controller The controller name (a string like BlogBundle:Post:index)
108
     * @param array  $path       An array of path parameters
109
     * @param array  $query      An array of query parameters
110
     *
111
     * @return Response A Response instance
112
     */
113
    protected function forward($controller, array $path = [], array $query = [])
114
    {
115
        $path['_controller'] = $controller;
116
        $subRequest = $this->request->duplicate($query, null, $path);
117
118
        return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
119
    }
120
}
121