Explain::analyzeUpdate()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace BfwSql\Observers;
4
5
use \Exception;
6
use \BfwSql\Queries\Select;
7
8
/**
9
 * Requests observer.
10
 * Create a log with SELECT requests executed and informations about it. Run an
11
 * EXPLAIN query on the request and add informations retured to log.
12
 * 
13
 * @package bfw-sql
14
 * @author Vermeulen Maxime <[email protected]>
15
 * @version 2.0
16
 */
17
class Explain extends Basic
18
{
19
    /**
20
     * @const EXPLAIN_OK Explain status when the request has succeeded
21
     */
22
    const EXPLAIN_OK = 'ok';
23
    
24
    /**
25
     * @const EXPLAIN_FAILED Explain status when the request has failed
26
     */
27
    const EXPLAIN_FAILED = 'failed';
28
    
29
    /**
30
     * @const EXPLAIN_EMPTY Explain status when the request has returned nothing
31
     */
32
    const EXPLAIN_EMPTY = 'empty';
33
    
34
    /**
35
     * @var \BfwSql\Sql The sql instanced used to run EXPLAIN request
36
     */
37
    protected $sql;
38
    
39
    /**
40
     * @var object An object with explain status and informations returned
41
     */
42
    protected $explain;
43
    
44
    /**
45
     * Getter accessor to property sql
46
     * 
47
     * @return \BfwSql\Sql
48
     */
49
    public function getSql(): \BfwSql\Sql
50
    {
51
        return $this->sql;
52
    }
53
    
54
    /**
55
     * Getter accessor to property explain
56
     * 
57
     * @return object
58
     */
59
    public function getExplain()
60
    {
61
        return $this->explain;
62
    }
63
    
64
    /**
65
     * {@inheritdoc}
66
     * Limited to "system query" event.
67
     */
68
    protected function analyzeUpdate()
69
    {
70
        if ($this->action === 'system query') {
71
            $this->systemQuery();
72
        }
73
    }
74
    
75
    /**
76
     * {@inheritdoc}
77
     * Limited to \BfwSql\Queries\Select object
78
     * We not run EXPLAIN automatically on other request type to not destroy db
79
     * 
80
     * @return void
81
     */
82
    protected function systemQuery()
83
    {
84
        if ($this->context instanceof \BfwSql\Executers\Common === false) {
85
            throw new Exception(
86
                '"system query" event should have an Executers\Common class'
87
                .' into the context.',
88
                self::ERR_SYSTEM_QUERY_CONTEXT_CLASS
89
            );
90
        }
91
        
92
        if ($this->context->getQuery() instanceof Select === false) {
93
            return;
94
        }
95
        
96
        $this->explain = new class {
97
            public $status = \BfwSql\Observers\Explain::EXPLAIN_OK;
98
            public $datas  = [];
99
        };
100
        
101
        $this->sql = $this->obtainSql();
102
        
103
        $this->runExplain();
104
        return parent::systemQuery();
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::systemQuery() targeting BfwSql\Observers\Basic::systemQuery() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
105
    }
106
    
107
    /**
108
     * Obtain a \BfwSql\Sql instance.
109
     * 
110
     * @return \BfwSql\Sql
111
     */
112
    protected function obtainSql(): \BfwSql\Sql
113
    {
114
        $sqlConnect = $this->context->getSqlConnect();
115
        return new \BfwSql\Sql($sqlConnect);
116
    }
117
    
118
    /**
119
     * Run the EXPLAIN request
120
     * 
121
     * @return void
122
     */
123
    protected function runExplain()
124
    {
125
        $this->sql->query('FLUSH STATUS;');
126
        $pdo = $this->sql->getSqlConnect()->getPDO();
127
        
128
        $explainQuery = 'EXPLAIN '.$this->context->getQuery()->assemble();
129
        $request      = $pdo->prepare(
130
            $explainQuery,
131
            $this->context->getPrepareDriversOptions()
132
        );
133
        $explainResult = $request->execute(
134
            $this->context->getQuery()->getPreparedParams()
135
        );
136
        
137
        if ($explainResult === false) {
138
            $this->explain->status = self::EXPLAIN_FAILED;
139
            return;
140
        }
141
        
142
        $explainFetch = $request->fetch(\PDO::FETCH_ASSOC);
143
        if ($explainFetch === false) {
144
            $this->explain->status = self::EXPLAIN_EMPTY;
145
            return;
146
        }
147
        
148
        foreach ($explainFetch as $explainKey => $explainValue) {
149
            $this->explain->datas[$explainKey] = $explainValue;
150
        }
151
    }
152
    
153
    /**
154
     * {@inheritdoc}
155
     * Add explain informations to monolog too.
156
     */
157
    protected function addQueryToMonoLog(
158
        string $query,
159
        array $error,
160
        array $preparedArgs
161
    ) {
162
        $logTxt = 'Type: '.$this->action.' ; '
163
            .'Query: '.$query. ' ; '
164
            .'Errors: '.print_r($error, true).' ; '
165
            .'Explain status: '.$this->explain->status.' ; '
166
            .'Explain datas: '.print_r($this->explain->datas, true). ';'
167
        ;
168
        
169
        $this->monolog->getLogger()->debug($logTxt, $preparedArgs);
170
    }
171
}
172