AccessLogger   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 105
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 47
c 5
b 0
f 0
dl 0
loc 105
ccs 0
cts 46
cp 0
rs 10
wmc 8

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getDeviceDetector() 0 8 2
A getBrowserInfo() 0 20 2
A log() 0 15 3
A __construct() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Infra\Log;
6
7
use App\Entity\AccessLog;
8
use DeviceDetector\DeviceDetector;
9
use Doctrine\ORM\EntityManager;
10
use Webmozart\Assert\Assert;
11
12
class AccessLogger
13
{
14
    public const TYPE_LOGIN_SUCCESS               = 'success';
15
    public const TYPE_LOGIN_FAILURE               = 'fail';
16
    public const TYPE_LOGIN_FAILURE_EXPIRY        = 'fail.expiry';
17
    public const TYPE_LOGIN_FAILURE_PAYMENT_ISSUE = 'fail.payment';
18
    public const TYPE_LOGIN_FAILURE_CREDENTIALS   = 'fail.credentials';
19
    public const TYPE_LOGIN_FAILURE_NO_ACCESS     = 'fail.no_access';
20
21
    public const SUPPORTED_TYPES = [
22
        self::TYPE_LOGIN_SUCCESS,
23
        self::TYPE_LOGIN_FAILURE,
24
        self::TYPE_LOGIN_FAILURE_CREDENTIALS,
25
        self::TYPE_LOGIN_FAILURE_EXPIRY,
26
        self::TYPE_LOGIN_FAILURE_PAYMENT_ISSUE,
27
        self::TYPE_LOGIN_FAILURE_NO_ACCESS,
28
    ];
29
30
    /**
31
     * @var EntityManager
32
     */
33
    private $em;
34
35
    /**
36
     * Device detector caches.
37
     *
38
     * @var array<string, DeviceDetector>
39
     */
40
    private $ddCache;
41
42
    /**
43
     * Whether user agent detection is enabled.
44
     *
45
     * @var bool
46
     */
47
    private $uaDetectionEnabled;
48
49
    /**
50
     * @param bool $uaDetectionEnabled Whether user agent detection is enabled
51
     */
52
    public function __construct(EntityManager $entityManager, $uaDetectionEnabled = true)
53
    {
54
        $this->em                 = $entityManager;
55
        $this->uaDetectionEnabled = $uaDetectionEnabled;
56
        $this->ddCache            = [];
57
    }
58
59
    /**
60
     * @throws \Throwable
61
     */
62
    public function log(string $type, string $email, ?string $language, ?string $ip, ?string $userAgent): void
63
    {
64
        Assert::oneOf($type, self::SUPPORTED_TYPES);
65
66
        $browserInfo = $this->getBrowserInfo($this->uaDetectionEnabled ? $userAgent : null);
67
68
        ['os' => $os, 'browser' => $browser, 'version' => $browserVersion, 'type' => $deviceType] = $browserInfo;
69
70
        $accessLog = new AccessLog($type, $email, $language, $ip, $userAgent, $browser, $browserVersion, $os, $deviceType);
71
72
        try {
73
            $this->em->persist($accessLog);
74
            $this->em->flush();
75
        } catch (\Throwable $e) {
76
            throw $e;
77
        }
78
    }
79
80
    /**
81
     * @return array<string, mixed>
82
     */
83
    public function getBrowserInfo(?string $userAgent): array
84
    {
85
        if ($userAgent === null) {
86
            return [
87
                'os'              => null,
88
                'browser'         => null,
89
                'version' 		      => null,
90
                'type'			         => null,
91
            ];
92
        }
93
94
        $dd = $this->getDeviceDetector($userAgent);
95
        $dd->skipBotDetection();
96
        $dd->parse();
97
98
        return [
99
            'os'      	 => $dd->getOs('short_name'),
100
            'browser'   => $dd->getClient('name'),
101
            'version'   => $dd->getClient('version'),
102
            'type'      => $dd->getDeviceName(),
103
        ];
104
    }
105
106
    /**
107
     * Basic in-memory caching, should be fine for AccessLogger in context.
108
     */
109
    private function getDeviceDetector(string $userAgent): DeviceDetector
110
    {
111
        $agentKey = md5($userAgent);
112
        if (!isset($this->ddCache[$agentKey])) {
113
            $this->ddCache[$agentKey] = new DeviceDetector($userAgent);
114
        }
115
116
        return $this->ddCache[$agentKey];
117
    }
118
}
119