ExceptionListener::getAlternativeRoute()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 11
c 0
b 0
f 0
nc 6
nop 1
dl 0
loc 20
rs 9.9
ccs 11
cts 11
cp 1
crap 4
1
<?php
2
3
namespace Palmtree\CanonicalUrlBundle\EventListener;
4
5
use Symfony\Component\HttpFoundation\RedirectResponse;
6
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
7
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
8
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
9
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
10
use Symfony\Component\Routing\RouterInterface;
11
12
class ExceptionListener
13
{
14
    const CONTROLLER_PATTERN = '~^/app(?:_.+)*\.php~';
15
16
    /** @var RouterInterface */
17
    private $router;
18
    /** @var bool */
19
    private $redirect;
20
    /** @var int */
21
    private $redirectCode;
22
    /** @var bool */
23
    private $trailingSlash;
24
25
    /**
26
     * KernelEventListener constructor.
27
     *
28
     * @param RouterInterface $router
29
     * @param array           $config
30
     */
31 5
    public function __construct(RouterInterface $router, array $config = [])
32
    {
33 5
        $this->router = $router;
34
35 5
        $this->redirect      = $config['redirect'];
36 5
        $this->redirectCode  = $config['redirect_code'];
37 5
        $this->trailingSlash = $config['trailing_slash'];
38 5
    }
39
40
    /**
41
     * Listener for the 'kernel.exception' event.
42
     *
43
     * @param GetResponseForExceptionEvent $event
44
     *
45
     * @return bool
46
     */
47 5
    public function onKernelException(GetResponseForExceptionEvent $event)
48
    {
49 5
        $exception = $event->getException();
50
51 5
        if ($exception instanceof NotFoundHttpException) {
52
            // We're about to throw a 404 error, try to resolve it
53 5
            $request = $event->getRequest();
54
55 5
            $uri = \strtok($request->getRequestUri(), '?');
56
57
            // See if there's a matching route without a trailing slash
58 5
            $match = $this->getAlternativeRoute($uri);
59
60 5
            if ($match !== null) {
61 3
                if ($this->redirect) {
62 3
                    $params = $request->query->all();
63
64 3
                    foreach ($match as $key => $value) {
65 3
                        if ($key[0] !== '_') {
66 3
                            $params[$key] = $value;
67
                        }
68
                    }
69
70 3
                    $url = $this->router->generate($match['_route'], $params, UrlGeneratorInterface::ABSOLUTE_URL);
71
72 3
                    $response = new RedirectResponse($url, $this->redirectCode);
73 3
                    $event->setResponse($response);
74
75 3
                    return true;
76
                }
77
            }
78
        }
79
80 2
        return false;
81
    }
82
83
    /**
84
     * @param string $uri
85
     *
86
     * @return array|null
87
     */
88 5
    private function getAlternativeRoute($uri)
89
    {
90 5
        $alternativeUri = \rtrim($uri, '/');
91
92 5
        if ($this->trailingSlash) {
93 1
            $alternativeUri .= '/';
94
        }
95
96 5
        if ($alternativeUri === $uri) {
97 1
            return null;
98
        }
99
100 4
        $alternativeUri = \preg_replace(static::CONTROLLER_PATTERN, '', $alternativeUri);
101
102
        try {
103 4
            $match = $this->router->match($alternativeUri);
104
105 3
            return $match;
106 1
        } catch (ResourceNotFoundException $e) {
107 1
            return null;
108
        }
109
    }
110
}
111