Passed
Push — master ( 2524ae...5d0353 )
by Joel
08:46
created

RequestResponseListener::onKernelResponse()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 4
nop 1
dl 0
loc 18
ccs 0
cts 14
cp 0
crap 30
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
namespace RedirectionIO\Client\ProxySymfony\EventListener;
4
5
use RedirectionIO\Client\Sdk\Command\CommandInterface;
6
use RedirectionIO\Client\Sdk\Command\LogCommand;
7
use RedirectionIO\Client\Sdk\Command\MatchCommand;
8
use RedirectionIO\Client\Sdk\Command\MatchWithResponseCommand;
9
use RedirectionIO\Client\Sdk\Exception\ExceptionInterface;
10
use RedirectionIO\Client\Sdk\Client;
11
use RedirectionIO\Client\Sdk\HttpMessage\Request;
12
use RedirectionIO\Client\Sdk\HttpMessage\Response;
13
use Symfony\Component\HttpFoundation\RedirectResponse as SymfonyRedirectResponse;
14
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
15
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
16
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
17
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
18
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
19
20
class RequestResponseListener
21
{
22
    private $client;
23
    private $excludedPrefixes;
24
    private $allowMatchOnResponse;
25
26
    public function __construct(Client $client, array $excludedPrefixes = [], bool $allowMatchOnResponse = false)
27
    {
28
        $this->client = $client;
29
        $this->excludedPrefixes = $excludedPrefixes;
30
        $this->allowMatchOnResponse = $allowMatchOnResponse;
31
    }
32
33
    public function onKernelRequest(GetResponseEvent $event)
34
    {
35
        if (!$event->isMasterRequest()) {
36
            return;
37
        }
38
39
        $request = $event->getRequest();
40
41
        if ($this->isExcludedPrefix($request->getPathInfo())) {
42
            return;
43
        }
44
45
        /** @var Response $response */
46
        $response = $this->client->request($this->createMatchCommand($request));
47
        $request->attributes->set('redirectionio_response', $response);
48
49
        if (!$response) {
0 ignored issues
show
introduced by
$response is of type RedirectionIO\Client\Sdk\HttpMessage\Response, thus it always evaluated to true.
Loading history...
50
            return;
51
        }
52
53
        if ($response->getMatchOnResponseStatus() > 0) {
54
            return;
55
        }
56
57
        410 === $response->getStatusCode()
58
            ? $event->setResponse((new SymfonyResponse())->setStatusCode(410))
59
            : $event->setResponse(new SymfonyRedirectResponse($response->getLocation(), $response->getStatusCode()));
60
    }
61
62
    public function onKernelResponse(FilterResponseEvent $event)
63
    {
64
        /** @var Response $rioResponse */
65
        $rioResponse = $event->getRequest()->attributes->get('redirectionio_response');
66
67
        if (null === $rioResponse) {
68
            return;
69
        }
70
71
        $symfonyResponse = $event->getResponse();
72
73
        if ($rioResponse->getMatchOnResponseStatus() === 0 || $rioResponse->getMatchOnResponseStatus() !== $symfonyResponse->getStatusCode()) {
74
            return;
75
        }
76
77
        410 === $rioResponse->getStatusCode()
78
            ? $event->setResponse((new SymfonyResponse())->setStatusCode(410))
79
            : $event->setResponse(new SymfonyRedirectResponse($rioResponse->getLocation(), $rioResponse->getStatusCode()));
80
    }
81
82
    public function onKernelTerminate(PostResponseEvent $event)
83
    {
84
        if ($this->isExcludedPrefix($event->getRequest()->getPathInfo())) {
85
            return;
86
        }
87
88
        $response = $event->getRequest()->attributes->get('redirectionio_response');
89
90
        if (!$response) {
91
            $symfonyResponse = $event->getResponse();
92
            $location = $symfonyResponse->headers->get('location', null);
93
94
            $response = new Response($event->getResponse()->getStatusCode(), null, $location);
95
        }
96
97
        $request = $this->createSdkRequest($event->getRequest());
98
99
        try {
100
            $this->client->request(new LogCommand($request, $response));
101
        } catch (ExceptionInterface $exception) {
102
            // do nothing
103
        }
104
    }
105
106
    private function createMatchCommand(SymfonyRequest $symfonyRequest): CommandInterface
107
    {
108
        $request = $this->createSdkRequest($symfonyRequest);
109
110
        if ($this->allowMatchOnResponse) {
111
            return new MatchWithResponseCommand($request);
112
        }
113
114
        return new MatchCommand($request);
115
    }
116
117
    private function createSdkRequest(SymfonyRequest $symfonyRequest)
118
    {
119
        return new Request(
120
            $symfonyRequest->getHttpHost(),
121
            $this->getFullPath($symfonyRequest),
122
            $symfonyRequest->headers->get('User-Agent'),
123
            $symfonyRequest->headers->get('Referer'),
124
            $symfonyRequest->getScheme()
125
        );
126
    }
127
128
    private function getFullPath(SymfonyRequest $symfonyRequest)
129
    {
130
        if (null === ($requestUri = $symfonyRequest->getRequestUri())) {
0 ignored issues
show
introduced by
The condition null === $requestUri = $...equest->getRequestUri() is always false.
Loading history...
131
            return '/';
132
        }
133
134
        if ('' !== $requestUri && '/' !== $requestUri[0]) {
135
            $requestUri = '/'.$requestUri;
136
        }
137
138
        if (null === ($baseUrl = $symfonyRequest->getBaseUrl())) {
0 ignored issues
show
introduced by
The condition null === $baseUrl = $symfonyRequest->getBaseUrl() is always false.
Loading history...
139
            return $requestUri;
140
        }
141
142
        $pathInfo = substr($requestUri, \strlen($baseUrl));
143
144
        if (false === $pathInfo || '' === $pathInfo) {
145
            return '/';
146
        }
147
148
        return (string) $pathInfo;
149
    }
150
151
    private function isExcludedPrefix($url): bool
152
    {
153
        foreach ($this->excludedPrefixes as $excludedPrefix) {
154
            if (0 === strpos($url, $excludedPrefix)) {
155
                return true;
156
            }
157
        }
158
159
        return false;
160
    }
161
}
162