Passed
Pull Request — master (#9)
by
unknown
01:53
created

getStartQueryContext()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 2
1
<?php
2
3
namespace Abacaphiliac\Doctrine;
4
5
use Doctrine\DBAL\Logging\SQLLogger;
6
use InvalidArgumentException;
7
use Psr\Log\LoggerInterface;
8
use Psr\Log\LogLevel;
9
use function array_keys;
10
use function array_merge;
11
use function array_values;
12
use function call_user_func;
13
use function is_array;
14
use function is_callable;
15
use function microtime;
16
use function uniqid;
17
18
class PsrSqlLoggerConfigurableLogLevels implements SQLLogger
19
{
20
    /** @var LoggerInterface */
21
    private $logger;
22
23
    /** @var float */
24
    private $start;
25
26
    /** @var callable */
27
    private $startQueryCallable;
28
29
    /** @var string */
30
    private $queryId;
31
32
    /** @var string */
33
    private $defaultLogLevel;
34
35
    /** @var array|null */
36
    private $logLevelMapping;
37
38
    public function __construct(LoggerInterface $logger, string $defaultLogLevel = LogLevel::INFO, array $logLevelMapping = null)
39
    {
40
        $this->logger = $logger;
41
        $this->defaultLogLevel = $defaultLogLevel;
42
        $this->logLevelMapping = $logLevelMapping;
43
        $this->startQueryCallable = $this->getStartQueryCallable($defaultLogLevel);
44
    }
45
46
    private function getStartQueryCallable(string $level) : callable
47
    {
48
        $callable = $this->getLoggerCallable($level);
49
50
        if (!is_callable($callable)) {
51
            throw new InvalidArgumentException(sprintf(
52
                '%s::%s" is not callable',
53
                LoggerInterface::class,
54
                $this->defaultLogLevel
55
            ));
56
        }
57
58
        return $callable;
59
    }
60
61
    private function getLoggerCallable(string $level) : array
62
    {
63
        return [$this->logger, $level];
64
    }
65
66 View Code Duplication
    public function startQuery($sql, array $params = null, array $types = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
67
    {
68
        $this->queryId = uniqid('', true);
69
70
        $this->start = microtime(true);
71
72
        call_user_func($this->startQueryCallable, 'Query started', array_merge(
73
            $this->getStartQueryContext($sql, $params, $types),
74
            [
75
                'query_id' => $this->queryId,
76
            ]
77
        ));
78
    }
79
80
    protected function getStartQueryContext($sql, array $params = null, array $types = null) : array
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
81
    {
82
        return [
83
            'sql' => $sql,
84
            'types' => $types,
85
        ];
86
    }
87
88
    public function stopQuery()
89
    {
90
        $stop = microtime(true);
91
        $durationInSeconds = $stop - $this->start;
92
93
        call_user_func($this->getStopQueryCallable($durationInSeconds), 'Query finished', [
94
            'query_id' => $this->queryId,
95
            'start' => $this->start,
96
            'stop' => $stop,
97
            'duration_s' => $durationInSeconds,
98
        ]);
99
    }
100
101
    private function getStopQueryCallable(float $durationInSeconds): callable
102
    {
103
        return $this->getLoggerCallable($this->getApplicableLogLevel($durationInSeconds));
104
    }
105
106
    private function getApplicableLogLevel(float $durationInSeconds): string
107
    {
108
        return is_array($this->logLevelMapping) ? $this->determineApplicableLogLevel($durationInSeconds) : $this->defaultLogLevel;
109
    }
110
111
    private function determineApplicableLogLevel(float $durationInSeconds) : string
112
    {
113
        $durationInMilliseconds = $durationInSeconds * 1000;
114
        $durations = array_values($this->logLevelMapping); //Acquire a common / non-associative array
115
        $durations[] = $durationInMilliseconds; //Append the incoming query duration in milliseconds to the array of duration thresholds
116
117
        asort($durations, SORT_NUMERIC); //Sort the array from low to high: the provided duration will end up somewhere between the thresholds
118
        $durations = array_values($durations); //A re-index is required after sorting
119
120
        $key = array_search($durationInMilliseconds, $durations, true); //Determine at which position the duration ended up after sorting
121
122
        $logLevels = array_keys($this->logLevelMapping);
123
124
        return $logLevels[$key - 1]; //Now take the "previous" key
125
    }
126
}
127