Completed
Push — 2.0 ( ada449...a2425b )
by Vermeulen
01:55
created

Explain::analyzeUpdate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace BfwSql\Observers;
4
5
use \Exception;
6
use \BfwSql\Actions\AbstractActions;
7
use \BfwSql\Actions\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 \stdClass 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()
51
    {
52
        return $this->sql;
53
    }
54
    
55
    /**
56
     * Getter accessor to property explain
57
     * 
58
     * @return \stdClass
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\Actions\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 View Code Duplication
        if ($this->context instanceof AbstractActions === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
86
            throw new Exception(
87
                '"system query" event should have an AbstractActions 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 = (object) [
98
            'status' => self::EXPLAIN_OK,
99
            'datas'  => []
100
        ];
101
        
102
        $this->sql = $this->obtainSql();
103
        
104
        $this->runExplain();
105
        return parent::systemQuery();
106
    }
107
    
108
    /**
109
     * Obtain a \BfwSql\Sql instance.
110
     * 
111
     * @return \BfwSql\Sql
112
     */
113
    protected function obtainSql()
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->getPrepareDriversOptions()
133
        );
134
        $explainResult = $request->execute(
135
            $this->context->getPreparedRequestArgs()
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($query, $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