Passed
Push — 1.0.0-dev ( 024223...5d8234 )
by nguereza
02:46
created

DatabaseQueryRunner::getQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
cc 1
eloc 1
c 1
b 1
f 1
nc 1
nop 0
dl 0
loc 2
rs 10
1
<?php
2
    defined('ROOT_PATH') || exit('Access denied');
3
    /**
4
     * TNH Framework
5
     *
6
     * A simple PHP framework using HMVC architecture
7
     *
8
     * This content is released under the MIT License (MIT)
9
     *
10
     * Copyright (c) 2017 TNH Framework
11
     *
12
     * Permission is hereby granted, free of charge, to any person obtaining a copy
13
     * of this software and associated documentation files (the "Software"), to deal
14
     * in the Software without restriction, including without limitation the rights
15
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
     * copies of the Software, and to permit persons to whom the Software is
17
     * furnished to do so, subject to the following conditions:
18
     *
19
     * The above copyright notice and this permission notice shall be included in all
20
     * copies or substantial portions of the Software.
21
     *
22
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
     * SOFTWARE.
29
     */
30
    
31
    class DatabaseQueryRunner extends BaseClass {
32
33
         /**
34
         * The DatabaseConnection instance
35
         * @var object
36
         */
37
        private $connection = null;
38
39
        /**
40
         * The last query result
41
         * @var object
42
         */
43
        protected $queryResult = null;
44
  	
45
        /**
46
         * The benchmark instance
47
         * @var object
48
         */
49
        protected $benchmarkInstance = null;
50
        
51
        /**
52
         * The SQL query statment to execute
53
         * @var string
54
         */
55
        private $query = null;
56
    
57
        /**
58
         * Indicate if we need return result as list
59
         * @var boolean
60
         */
61
        private $returnAsList = true;
62
     
63
     
64
        /**
65
         * Indicate if we need return result as array or not
66
         * @var boolean
67
         */
68
        private $returnAsArray = true;
69
     
70
        /**
71
         * The last PDOStatment instance
72
         * @var object
73
         */
74
        private $pdoStatment = null;
75
     
76
        /**
77
         * The error returned for the last query
78
         * @var string
79
         */
80
        private $error = null;
81
	
82
        /**
83
         * Construct new DatabaseQueryRunner
84
         * @param object $connection the DatabaseConnection object
85
         */
86
        public function __construct(DatabaseConnection $connection = null) {
87
            parent::__construct();
88
            if ($connection !== null) {
89
                $this->connection = $connection;
90
            }
91
92
            //Set DatabaseQueryResult instance to use
93
            $this->setDependencyInstanceFromParamOrCreate('queryResult', null, 'DatabaseQueryResult', 'classes/database');
94
             
95
            //Set Benchmark instance to use
96
            $this->setDependencyInstanceFromParamOrCreate('benchmarkInstance', null, 'Benchmark', 'libraries');
97
        }
98
        
99
        /**
100
         * Run the database SQL query and return the DatabaseQueryResult object
101
         * @see Database::query
102
         * 
103
         * @return object|void
104
         */
105
        public function execute() {
106
            //reset instance
107
            $this->reset();
108
           
109
            //for database query execution time
110
            $benchmarkMarkerKey = $this->getBenchmarkKey();
111
            
112
            $this->benchmarkInstance->mark('DATABASE_QUERY_START(' . $benchmarkMarkerKey . ')');                
113
            //Now execute the query
114
            $this->pdoStatment = $this->connection->getPdo()->query($this->query);
115
            //get response time for this query
116
            $responseTime = $this->benchmarkInstance->elapsedTime(
117
                                                                    'DATABASE_QUERY_START(' . $benchmarkMarkerKey . ')', 
118
                                                                    'DATABASE_QUERY_END(' . $benchmarkMarkerKey . ')'
119
                                                                    );
120
                //TODO use the configuration value for the high response time currently is 1 second
121
            if ((double) $responseTime >= 1.000000) {
122
                $this->logger->warning(
123
                                        'High response time while processing database query [' . $this->query . '].' 
124
                                        . 'The response time is [' .$responseTime . '] sec.'
125
                                        );
126
            }
127
    		
128
            if ($this->pdoStatment !== false) {
129
                $isSelectQuery = stristr($this->query, 'SELECT') !== false;
130
                if ($isSelectQuery) {
131
                    $this->setResultForSelect();              
132
                } else {
133
                    $this->setResultForNonSelect();
134
                }
135
                //close cursor
136
                $this->pdoStatment->closeCursor();
137
                return $this->queryResult;
138
            }
139
            $this->setQueryRunnerError();
140
        }
141
    	
142
        /**
143
         * Return the DatabaseConnection instance
144
         * @return object DatabaseConnection
145
         */
146
        public function getConnection() {
147
            return $this->connection;
148
        }
149
150
        /**
151
         * Set the DatabaseConnection instance
152
         * @param object DatabaseConnection $connection the DatabaseConnection object
153
         *
154
         * @return object the current instance
155
         */
156
        public function setConnection(DatabaseConnection $connection) {
157
            $this->connection = $connection;
158
            return $this;
159
        }
160
161
162
        /**
163
         * Return the benchmark instance
164
         * @return Benchmark
165
         */
166
        public function getBenchmark() {
167
            return $this->benchmarkInstance;
168
        }
169
170
        /**
171
         * Set the benchmark instance
172
         * @param Benchmark $benchmark the benchmark object
173
         * @return object DatabaseQueryRunner
174
         */
175
        public function setBenchmark($benchmark) {
176
            $this->benchmarkInstance = $benchmark;
177
            return $this;
178
        }
179
        
180
        /**
181
         * Return the database query result
182
         *
183
         * @return object DatabaseQueryResult
184
         */
185
        public function getQueryResult() {
186
            return $this->queryResult;
187
        }
188
189
        /**
190
         * Set the database query result instance
191
         * @param object $queryResult the query result
192
         *
193
         * @return object DatabaseQueryRunner
194
         */
195
        public function setQueryResult(DatabaseQueryResult $queryResult = null) {
196
            $this->queryResult = $queryResult;
197
            return $this;
198
        }
199
        
200
        /**
201
         * Return the current query SQL string
202
         * @return string
203
         */
204
        public function getQuery() {
205
            return $this->query;
206
        }
207
        
208
        /**
209
         * Set the query SQL string
210
         * @param string $query the SQL query to set
211
         * @return object DatabaseQueryRunner
212
         */
213
        public function setQuery($query) {
214
            $this->query = $query;
215
            return $this;
216
        }
217
        
218
        /**
219
         * Set the query return type as list or not
220
         * @param boolean $returnType
221
         * @return object DatabaseQueryRunner
222
         */
223
        public function setReturnType($returnType) {
224
            $this->returnAsList = $returnType;
225
            return $this;
226
        }
227
        
228
        /**
229
         * Set the return as array or not
230
         * @param boolean $status the status if true will return as array
231
         * @return object DatabaseQueryRunner
232
         */
233
        public function setReturnAsArray($status = true) {
234
            $this->returnAsArray = $status;
235
            return $this;
236
        }
237
        
238
        /**
239
         * Return the error for last query execution
240
         * @return string
241
         */
242
        public function getQueryError() {
243
            return $this->error;
244
        }
245
        
246
        /**
247
         * Return the benchmark key for the current query
248
         * 
249
         *  @return string
250
         */
251
        protected function getBenchmarkKey() {
252
            return md5($this->query . $this->returnAsList . $this->returnAsArray);
253
        }
254
        
255
        /**
256
         * Set error for database query execution
257
         */
258
        protected function setQueryRunnerError() {
259
            $error = $this->connection->getPdo()->errorInfo();
260
            $this->error = isset($error[2]) ? $error[2] : '';
261
            $this->logger->error('The database query execution got an error: ' . stringfy_vars($error));
262
            //show error message
263
            show_error('Query: "' . $this->query . '" Error: ' . $this->error, 'Database Error');
264
        }
265
266
        /**
267
         * Return the result for SELECT query
268
         * @see DatabaseQueryRunner::execute
269
         */
270
        protected function setResultForSelect() {
271
            //if need return all result like list of record
272
            $result = null;
273
            $numRows = 0;
274
            $fetchMode = PDO::FETCH_OBJ;
275
            if ($this->returnAsArray) {
276
                $fetchMode = PDO::FETCH_ASSOC;
277
            }
278
            if ($this->returnAsList) {
279
                $result = $this->pdoStatment->fetchAll($fetchMode);
280
            } else {
281
                $result = $this->pdoStatment->fetch($fetchMode);
282
            }
283
            //Sqlite and pgsql always return 0 when using rowCount()
284
            if (in_array($this->connection->getDriver(), array('sqlite', 'pgsql'))) {
285
                //by default count() return 1 if the parameter is not an array
286
                //or object implements Countable.
287
                if ($result) {
288
                    if ($this->returnAsList) {
289
                        $numRows = count($result);
290
                    } else {
291
                        //if object only one row will be returned
292
                        $numRows = 1;
293
                    }
294
                }
295
            } else {
296
                $numRows = $this->pdoStatment->rowCount(); 
297
            }
298
            $this->queryResult->setResult($result);
299
            $this->queryResult->setNumRows($numRows);
300
        }
301
302
        /**
303
         * Return the result for non SELECT query
304
         * @see DatabaseQueryRunner::execute
305
         */
306
        protected function setResultForNonSelect() {
307
            //Sqlite and pgsql always return 0 when using rowCount()
308
            $result = false;
309
            $numRows = 0;
310
            if (in_array($this->connection->getDriver(), array('sqlite', 'pgsql'))) {
311
                $result = true; //to test the result for the query like UPDATE, INSERT, DELETE
312
                $numRows = 1; //TODO use the correct method to get the exact affected row
313
            } else {
314
                //to test the result for the query like UPDATE, INSERT, DELETE
315
                $result  = $this->pdoStatment->rowCount() >= 0; 
316
                $numRows = $this->pdoStatment->rowCount(); 
317
            }
318
            $this->queryResult->setResult($result);
319
            $this->queryResult->setNumRows($numRows);
320
        }
321
322
        /**
323
         * Reset the instance before run each query
324
         */
325
        private function reset() {
326
            $this->error = null;
327
            $this->pdoStatment = null;
328
        }
329
330
    }
331