Completed
Push — master ( ad6910...d77fda )
by Tarmo
18s queued 12s
created

RequestLogSubscriber   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 30
c 2
b 0
f 0
dl 0
loc 88
ccs 32
cts 32
cp 1
rs 10
wmc 12

4 Methods

Rating   Name   Duplication   Size   Complexity  
A onTerminateEvent() 0 18 6
A __construct() 0 7 1
A getSubscribedEvents() 0 6 1
A process() 0 27 4
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * /src/EventSubscriber/RequestLogSubscriber.php
5
 *
6
 * @author TLe, Tarmo Leppänen <[email protected]>
7
 */
8
9
namespace App\EventSubscriber;
10
11
use App\Entity\User as UserEntity;
12
use App\Repository\UserRepository;
13
use App\Security\ApiKeyUser;
14
use App\Security\SecurityUser;
15
use App\Security\UserTypeIdentification;
16
use App\Utils\RequestLogger;
17
use Psr\Log\LoggerInterface;
18
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpKernel\Event\TerminateEvent;
21
use Throwable;
22
use function array_filter;
23
use function count;
24
use function in_array;
25
use function str_contains;
26
use function substr;
27
28
/**
29
 * Class RequestLogSubscriber
30
 *
31
 * @package App\EventSubscriber
32
 * @author TLe, Tarmo Leppänen <[email protected]>
33
 *
34
 * @property array<int, string> $ignoredRoutes
35
 */
36
class RequestLogSubscriber implements EventSubscriberInterface
37
{
38
    /**
39
     * RequestLogSubscriber constructor.
40
     *
41
     * @param array<int, string> $ignoredRoutes
42
     */
43 488
    public function __construct(
44
        private RequestLogger $requestLogger,
45
        private UserRepository $userRepository,
46
        private LoggerInterface $logger,
47
        private UserTypeIdentification $userService,
48
        private array $ignoredRoutes,
49
    ) {
50 488
    }
51
52
    /**
53
     * {@inheritdoc}
54
     *
55
     * @return array<string, array<int, string|int>>
56
     */
57 3
    public static function getSubscribedEvents(): array
58
    {
59
        return [
60
            TerminateEvent::class => [
61 3
                'onTerminateEvent',
62
                15,
63
            ],
64
        ];
65
    }
66
67
    /**
68
     * Subscriber method to log every request / response.
69
     *
70
     * @throws Throwable
71
     */
72 488
    public function onTerminateEvent(TerminateEvent $event): void
73
    {
74 488
        $request = $event->getRequest();
75 488
        $path = $request->getPathInfo();
76
77 488
        $filter = static fn (string $route): bool =>
78 445
            str_contains($route, '/*') && str_contains($path, substr($route, 0, -2));
79
80
        // We don't want to log OPTIONS requests, /_profiler* -path, ignored routes and wildcard ignored routes
81 488
        if ($request->getRealMethod() === Request::METHOD_OPTIONS
82 459
            || str_contains($path, '/_profiler')
83 459
            || in_array($path, $this->ignoredRoutes, true)
84 488
            || count(array_filter($this->ignoredRoutes, $filter)) !== 0
85
        ) {
86 42
            return;
87
        }
88
89 446
        $this->process($event);
90 446
    }
91
92
    /**
93
     * Method to process current request event.
94
     *
95
     * @throws Throwable
96
     */
97 446
    private function process(TerminateEvent $event): void
98
    {
99 446
        $request = $event->getRequest();
100
101
        // Set needed data to logger and handle actual log
102 446
        $this->requestLogger->setRequest($request);
103 446
        $this->requestLogger->setResponse($event->getResponse());
104
105 446
        $identify = $this->userService->getIdentity();
106
107 446
        if ($identify instanceof SecurityUser) {
108 249
            $userEntity = $this->userRepository->getReference($identify->getUsername());
109
110 249
            if ($userEntity instanceof UserEntity) {
111 248
                $this->requestLogger->setUser($userEntity);
112
            } else {
113 1
                $this->logger->error(
114 1
                    sprintf('User not found for UUID: "%s".', $identify->getUsername()),
115 249
                    self::getSubscribedEvents()
116
                );
117
            }
118 197
        } elseif ($identify instanceof ApiKeyUser) {
0 ignored issues
show
introduced by
$identify is always a sub-type of App\Security\ApiKeyUser.
Loading history...
119 21
            $this->requestLogger->setApiKey($identify->getApiKey());
120
        }
121
122 446
        $this->requestLogger->setMasterRequest($event->isMasterRequest());
123 446
        $this->requestLogger->handle();
124 446
    }
125
}
126