Common::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace BfwSql\Executers;
4
5
use \Exception;
6
7
class Common
8
{
9
    /**
10
     * @const ERR_EXECUTE_BAD_REQUEST Exception code if a request has fail
11
     * during execution
12
     */
13
    const ERR_EXECUTE_BAD_REQUEST = 2201001;
14
    
15
    /**
16
     * @const ERR_EXECUTED_UNKNOWN_ERROR Exception code if a request has fail
17
     * but when the error has not been returned by PDO::errorInfos()
18
     */
19
    const ERR_EXECUTED_UNKNOWN_ERROR = 2201002;
20
    
21
    /**
22
     * @const ERR_CLOSE_CURSOR_NOT_PDOSTATEMENT Exception code if the method
23
     * closeCursor is called for a request who have not returned a
24
     * PDOStatement object.
25
     */
26
    const ERR_CLOSE_CURSOR_NOT_PDOSTATEMENT = 2201003;
27
    
28
    /**
29
     * @var \BfwSql\Queries\AbstractQuery $query Query system object
30
     */
31
    protected $query;
32
    
33
    /**
34
     * @var \BfwSql\SqlConnect $sqlConnect SqlConnect object
35
     */
36
    protected $sqlConnect;
37
    
38
    /**
39
     * @var boolean $isPreparedRequest If is a prepared request
40
     */
41
    protected $isPreparedRequest = true;
42
    
43
    /**
44
     * @var array $lastErrorInfos The PDO::errorInfos return for the last
45
     * query executed. Empty if no request has been executed.
46
     */
47
    protected $lastErrorInfos = [];
48
    
49
    /**
50
     * @var \PDOStatement|integer|bool $lastRequestStatement The PDOStatement
51
     *  for the last request executed. Or integer if the request return the number
52
     *  of row impacted. Or a boolean (false) if request failed.
53
     */
54
    protected $lastRequestStatement;
55
    
56
    /**
57
     * @var boolean $noResult If request has sent no result.
58
     */
59
    protected $noResult = false;
60
    
61
    /**
62
     * @var array $prepareDriversOptions SGBD driver option used for
63
     *  prepared request
64
     * 
65
     * @link http://php.net/manual/en/pdo.prepare.php
66
     */
67
    protected $prepareDriversOptions = array();
68
    
69
    /**
70
     * Constructor
71
     * 
72
     * @param \BfwSql\Queries\AbstractQuery $query Instance of query
73
     * system
74
     */
75
    public function __construct(\BfwSql\Queries\AbstractQuery $query)
76
    {
77
        $this->query      = $query;
78
        $this->sqlConnect = $query->getSqlConnect();
79
    }
80
81
    /**
82
     * Getter to access to isPreparedRequest property
83
     * 
84
     * @return boolean
85
     */
86
    public function getIsPreparedRequest(): bool
87
    {
88
        return $this->isPreparedRequest;
89
    }
90
    
91
    /**
92
     * Setter to enable or disable prepared request
93
     * 
94
     * @param boolean $preparedRequestStatus The new status for prepared request
95
     * 
96
     * @return $this
97
     */
98
    public function setIsPreparedRequest(bool $preparedRequestStatus): self
99
    {
100
        $this->isPreparedRequest = (bool) $preparedRequestStatus;
101
        
102
        return $this;
103
    }
104
    
105
    /**
106
     * Getter to access to lastErrorInfos property
107
     * 
108
     * @return array
109
     */
110
    public function getLastErrorInfos(): array
111
    {
112
        return $this->lastErrorInfos;
113
    }
114
115
    /**
116
     * Getter to access to lastRequestStatement property
117
     * 
118
     * @return \PDOStatement|integer|bool|null
119
     */
120
    public function getLastRequestStatement()
121
    {
122
        return $this->lastRequestStatement;
123
    }
124
125
    /**
126
     * Getter to access to noResult property
127
     * 
128
     * @return boolean
129
     */
130
    public function getNoResult(): bool
131
    {
132
        return $this->noResult;
133
    }
134
    
135
    /**
136
     * Getter to access at prepareDriversOptions property
137
     * 
138
     * @return array
139
     */
140
    public function getPrepareDriversOptions(): array
141
    {
142
        return $this->prepareDriversOptions;
143
    }
144
    
145
    /**
146
     * Define driver options to prepared request
147
     * 
148
     * @link http://php.net/manual/fr/pdo.prepare.php
149
     * 
150
     * @param array $driverOptions Drivers options
151
     * 
152
     * @return $this
153
     */
154
    public function setPrepareDriversOptions(array $driverOptions): self
155
    {
156
        $this->prepareDriversOptions = $driverOptions;
157
        
158
        return $this;
159
    }
160
    
161
    /**
162
     * Getter accessor to property query
163
     * 
164
     * @return \BfwSql\Queries\AbstractQuery
165
     */
166
    public function getQuery(): \BfwSql\Queries\AbstractQuery
167
    {
168
        return $this->query;
169
    }
170
    
171
    /**
172
     * Getter to access at sqlConnect property
173
     * 
174
     * @return \BfwSql\SqlConnect
175
     */
176
    public function getSqlConnect(): \BfwSql\SqlConnect
177
    {
178
        return $this->sqlConnect;
179
    }
180
    
181
    /**
182
     * Execute the assembled request
183
     * 
184
     * @return array The pdo errorInfo array
185
     */
186
    protected function executeQuery(): array
187
    {
188
        $this->sqlConnect->upNbQuery();
189
        $this->query->assemble();
190
        
191
        try {
192
            if ($this->isPreparedRequest) {
193
                $req = $this->executePreparedQuery();
194
            } else {
195
                $req = $this->executeNotPreparedQuery();
196
            }
197
            
198
            $this->lastRequestStatement = $req;
199
        } catch (\Throwable $e) {
200
            \BFW\Application::getInstance()
201
                ->getModuleList()
202
                ->getModuleByName('bfw-sql')
203
                ->monolog
0 ignored issues
show
Bug introduced by
The property monolog does not seem to exist on BFW\Module.
Loading history...
204
                ->getLogger()
205
                ->warning(
206
                    'Exception while query execution : '.$e->getMessage()
207
                )
208
            ;
209
            
210
            throw new \Exception($e->getMessage(), (int) $e->getCode(), $e);
211
        } finally {
212
            $this->lastErrorInfos = $this->sqlConnect->getPDO()->errorInfo();
213
            $this->callObserver();
214
        }
215
        
216
        return $this->lastErrorInfos;
217
    }
218
    
219
    /**
220
     * Execute a prepared request
221
     * 
222
     * @return \PDOStatement|bool
223
     */
224
    protected function executePreparedQuery()
225
    {
226
        $pdo = $this->sqlConnect->getPDO();
227
        $req = $pdo->prepare(
228
            $this->query->getAssembledRequest(),
229
            $this->prepareDriversOptions
230
        );
231
232
        $req->execute($this->query->getPreparedParams());
233
        
234
        return $req;
235
    }
236
    
237
    /**
238
     * Execute a not prepared request
239
     * 
240
     * @return \PDOStatement|integer|bool
241
     */
242
    protected function executeNotPreparedQuery()
243
    {
244
        $pdoMethodToCall = 'exec';
245
        if ($this->query instanceof \BfwSql\Queries\Select) {
246
            $pdoMethodToCall = 'query';
247
        }
248
249
        $pdo = $this->sqlConnect->getPDO();
250
        return $pdo->{$pdoMethodToCall}($this->query->getAssembledRequest());
251
    }
252
    
253
    /**
254
     * Execute the assembled request and check if there are errors
255
     * Update property noResult
256
     * 
257
     * @throws \Exception If the request fail
258
     * 
259
     * @return \PDOStatement|integer
260
     */
261
    public function execute()
262
    {
263
        $error = $this->executeQuery();
264
        
265
        //Throw an exception if they are an error with the request
266
        if ($error[0] !== null && $error[0] !== '00000') {
267
            throw new Exception(
268
                $error[2],
269
                self::ERR_EXECUTE_BAD_REQUEST
270
            );
271
        }
272
        
273
        if ($this->lastRequestStatement === false) {
274
            throw new Exception(
275
                'An error occurred during the execution of the request',
276
                self::ERR_EXECUTED_UNKNOWN_ERROR
277
            );
278
        }
279
        
280
        $this->noResult = false;
281
        if ($this->obtainImpactedRows() === 0) {
282
            $this->noResult = true;
283
        }
284
285
        return $this->lastRequestStatement;
286
    }
287
    
288
    /**
289
     * Closes the cursor, enabling the statement to be executed again.
290
     * 
291
     * @link http://php.net/manual/fr/pdostatement.closecursor.php
292
     * 
293
     * @throws \Exception If the property $lastRequestStatement is not a
294
     * PDOStatement object.
295
     * 
296
     * @return bool
297
     */
298
    public function closeCursor(): bool
299
    {
300
        if ($this->lastRequestStatement instanceof \PDOStatement === false) {
301
            throw new Exception(
302
                'The cursor can\'t be close because the request '
303
                .'not have return a PDOStatement object.',
304
                self::ERR_CLOSE_CURSOR_NOT_PDOSTATEMENT
305
            );
306
        }
307
        
308
        return $this->lastRequestStatement->closeCursor();
309
    }
310
    
311
    /**
312
     * Return the number of impacted rows by the last request
313
     * 
314
     * @return int|bool
315
     */
316
    public function obtainImpactedRows()
317
    {
318
        if (is_object($this->lastRequestStatement)) {
319
            //If pdo::query or pdo::prepare
320
            return $this->lastRequestStatement->rowCount();
321
        } elseif (is_integer($this->lastRequestStatement)) {
322
            //If pdo::exec
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
323
            return $this->lastRequestStatement;
324
        }
325
        
326
        //Security if call without executed a request
327
        return false;
328
    }
329
    
330
    /**
331
     * Send a notify to application observers
332
     * 
333
     * @return void
334
     */
335
    protected function callObserver()
336
    {
337
        $app     = \BFW\Application::getInstance();
338
        $subject = $app->getSubjectList()->getSubjectByName('bfw-sql');
339
        $subject->addNotification('system query', clone $this);
340
    }
341
}
342