Completed
Branch 2.0 (acba87)
by Vermeulen
02:20
created

Explain::runExplain()

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 17
nc 4
nop 0
dl 0
loc 27
c 0
b 0
f 0
1
<?php
2
3
namespace BfwSql\Observers;
4
5
use \Exception;
6
use \BfwSql\Queries\AbstractQuery;
7
use \BfwSql\Queries\Select;
8
9
/**
10
 * Requests observer.
11
 * Create a log with SELECT requests executed and informations about it. Run an
12
 * EXPLAIN query on the request and add informations retured to log.
13
 * 
14
 * @package bfw-sql
15
 * @author Vermeulen Maxime <[email protected]>
16
 * @version 2.0
17
 */
18
class Explain extends Basic
19
{
20
    /**
21
     * @const EXPLAIN_OK Explain status when the request has succeeded
22
     */
23
    const EXPLAIN_OK = 'ok';
24
    
25
    /**
26
     * @const EXPLAIN_FAILED Explain status when the request has failed
27
     */
28
    const EXPLAIN_FAILED = 'failed';
29
    
30
    /**
31
     * @const EXPLAIN_EMPTY Explain status when the request has returned nothing
32
     */
33
    const EXPLAIN_EMPTY = 'empty';
34
    
35
    /**
36
     * @var \BfwSql\Sql The sql instanced used to run EXPLAIN request
37
     */
38
    protected $sql;
39
    
40
    /**
41
     * @var object An object with explain status and informations returned
42
     */
43
    protected $explain;
44
    
45
    /**
46
     * Getter accessor to property sql
47
     * 
48
     * @return \BfwSql\Sql
49
     */
50
    public function getSql(): \BfwSql\Sql
51
    {
52
        return $this->sql;
53
    }
54
    
55
    /**
56
     * Getter accessor to property explain
57
     * 
58
     * @return object
59
     */
60
    public function getExplain()
61
    {
62
        return $this->explain;
63
    }
64
    
65
    /**
66
     * {@inheritdoc}
67
     * Limited to "system query" event.
68
     */
69
    protected function analyzeUpdate()
70
    {
71
        if ($this->action === 'system query') {
72
            $this->systemQuery();
73
        }
74
    }
75
    
76
    /**
77
     * {@inheritdoc}
78
     * Limited to \BfwSql\Queries\Select object
79
     * We not run EXPLAIN automatically on other request type to not destroy db
80
     * 
81
     * @return void
82
     */
83
    protected function systemQuery()
84
    {
85
        if ($this->context instanceof AbstractQuery === false) {
86
            throw new Exception(
87
                '"system query" event should have an AbstractQuery class'
88
                .' into the context.',
89
                self::ERR_SYSTEM_QUERY_CONTEXT_CLASS
90
            );
91
        }
92
        
93
        if ($this->context instanceof Select === false) {
94
            return;
95
        }
96
        
97
        $this->explain = new class {
98
            public $status = \BfwSql\Observers\Explain::EXPLAIN_OK;
99
            public $datas  = [];
100
        };
101
        
102
        $this->sql = $this->obtainSql();
103
        
104
        $this->runExplain();
105
        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...
106
    }
107
    
108
    /**
109
     * Obtain a \BfwSql\Sql instance.
110
     * 
111
     * @return \BfwSql\Sql
112
     */
113
    protected function obtainSql(): \BfwSql\Sql
114
    {
115
        $sqlConnect = $this->context->getSqlConnect();
116
        return new \BfwSql\Sql($sqlConnect);
117
    }
118
    
119
    /**
120
     * Run the EXPLAIN request
121
     * 
122
     * @return void
123
     */
124
    protected function runExplain()
125
    {
126
        $this->sql->query('FLUSH STATUS;');
127
        $pdo = $this->sql->getSqlConnect()->getPDO();
128
        
129
        $explainQuery = 'EXPLAIN '.$this->context->assemble();
130
        $request      = $pdo->prepare(
131
            $explainQuery,
132
            $this->context->getExecuter()->getPrepareDriversOptions()
133
        );
134
        $explainResult = $request->execute(
135
            $this->context->getPreparedParams()
136
        );
137
        
138
        if ($explainResult === false) {
139
            $this->explain->status = self::EXPLAIN_FAILED;
140
            return;
141
        }
142
        
143
        $explainFetch = $request->fetch(\PDO::FETCH_ASSOC);
144
        if ($explainFetch === false) {
145
            $this->explain->status = self::EXPLAIN_EMPTY;
146
            return;
147
        }
148
        
149
        foreach ($explainFetch as $explainKey => $explainValue) {
150
            $this->explain->datas[$explainKey] = $explainValue;
151
        }
152
    }
153
    
154
    /**
155
     * {@inheritdoc}
156
     * Add explain informations to monolog too.
157
     */
158
    protected function addQueryToMonoLog(string $query, array $error)
159
    {
160
        $this->monolog->getLogger()->debug(
161
            'Type: '.$this->action.' ; '
162
            .'Query: '.$query. ' ; '
163
            .'Errors: '.print_r($error, true).' ; '
164
            .'Explain status: '.$this->explain->status.' ; '
165
            .'Explain datas: '.print_r($this->explain->datas, true)
166
        );
167
    }
168
}
169