Passed
Push — 1.0.0-dev ( 29a38b...3f14f3 )
by nguereza
02:39
created

DatabaseQueryRunner::setResultForNonSelect()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
cc 2
eloc 10
c 2
b 1
f 1
nc 2
nop 0
dl 0
loc 14
rs 9.9332
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
         * @param string $query the SQL query to be executed
86
         * @param boolean $returnAsList if need return as list or just one row
87
         * @param boolean $returnAsArray whether to return the result as array or not
88
         */
89
        public function __construct(DatabaseConnection $connection = null, $query = null, $returnAsList = true, $returnAsArray = false) {
90
            parent::__construct();
91
            if ($connection !== null) {
92
                $this->connection = $connection;
93
            }
94
95
            //Set DatabaseQueryResult instance to use
96
            $this->setDependencyInstanceFromParamOrCreate('queryResult', null, 'DatabaseQueryResult', 'classes/database');
97
             
98
            //Set Benchmark instance to use
99
            $this->setDependencyInstanceFromParamOrCreate('benchmarkInstance', null, 'Benchmark', 'libraries');
100
       
101
            $this->query         = $query;
102
            $this->returnAsList  = $returnAsList;
103
            $this->returnAsArray = $returnAsArray;
104
        }
105
106
        /**
107
         * Return the DatabaseConnection instance
108
         * @return object DatabaseConnection
109
         */
110
        public function getConnection() {
111
            return $this->connection;
112
        }
113
114
        /**
115
         * Set the DatabaseConnection instance
116
         * @param object DatabaseConnection $connection the DatabaseConnection object
117
         *
118
         * @return object the current instance
119
         */
120
        public function setConnection(DatabaseConnection $connection) {
121
            $this->connection = $connection;
122
            return $this;
123
        }
124
        
125
        /**
126
         * Run the database SQL query and return the DatabaseQueryResult object
127
         * @see Database::query
128
         * 
129
         * @return object|void
130
         */
131
        public function execute() {
132
            //reset instance
133
            $this->reset();
134
           
135
            //for database query execution time
136
            $benchmarkMarkerKey = $this->getBenchmarkKey();
137
            
138
            $this->benchmarkInstance->mark('DATABASE_QUERY_START(' . $benchmarkMarkerKey . ')');                
139
            //Now execute the query
140
            $this->pdoStatment = $this->connection->getPdo()->query($this->query);
141
            
142
            //get response time for this query
143
            $responseTime = $this->benchmarkInstance->elapsedTime(
144
                                                                    'DATABASE_QUERY_START(' . $benchmarkMarkerKey . ')', 
145
                                                                    'DATABASE_QUERY_END(' . $benchmarkMarkerKey . ')'
146
                                                                    );
147
                //TODO use the configuration value for the high response time currently is 1 second
148
            if ($responseTime >= 1) {
149
                $this->logger->warning(
150
                                        'High response time while processing database query [' . $this->query . ']. 
151
                                         The response time is [' .$responseTime . '] sec.'
152
                                        );
153
            }
154
    		
155
            if ($this->pdoStatment !== false) {
156
                $isSelectQuery = stristr($this->query, 'SELECT') !== false;
157
                if ($isSelectQuery) {
158
                    $this->setResultForSelect();              
159
                } else {
160
                    $this->setResultForNonSelect();
161
                }
162
                return $this->queryResult;
163
            }
164
            $this->setQueryRunnerError();
165
        }
166
    	
167
        /**
168
         * Return the result for SELECT query
169
         * @see DatabaseQueryRunner::execute
170
         */
171
        protected function setResultForSelect() {
172
            //if need return all result like list of record
173
            $result = null;
174
            $numRows = 0;
175
            $fetchMode = PDO::FETCH_OBJ;
176
            if ($this->returnAsArray) {
177
                $fetchMode = PDO::FETCH_ASSOC;
178
            }
179
            if ($this->returnAsList) {
180
                $result = $this->pdoStatment->fetchAll($fetchMode);
181
            } else {
182
                $result = $this->pdoStatment->fetch($fetchMode);
183
            }
184
            //Sqlite and pgsql always return 0 when using rowCount()
185
            if (in_array($this->connection->getDriver(), array('sqlite', 'pgsql'))) {
186
                //by default count() return 1 if the parameter is not an array
187
                //object or object implements Countable.
188
                if (is_array($result) || is_object($result) || $result instanceof Countable) {
189
                     $numRows = count($result);  
190
                }
191
            } else {
192
                $numRows = $this->pdoStatment->rowCount(); 
193
            }
194
            $this->queryResult->setResult($result);
195
            $this->queryResult->setNumRows($numRows);
196
        }
197
198
        /**
199
         * Return the result for non SELECT query
200
         * @see DatabaseQueryRunner::execute
201
         */
202
        protected function setResultForNonSelect() {
203
            //Sqlite and pgsql always return 0 when using rowCount()
204
            $result = false;
205
            $numRows = 0;
206
            if (in_array($this->connection->getDriver(), array('sqlite', 'pgsql'))) {
207
                $result = true; //to test the result for the query like UPDATE, INSERT, DELETE
208
                $numRows = 1; //TODO use the correct method to get the exact affected row
209
            } else {
210
                //to test the result for the query like UPDATE, INSERT, DELETE
211
                $result  = $this->pdoStatment->rowCount() >= 0; 
212
                $numRows = $this->pdoStatment->rowCount(); 
213
            }
214
            $this->queryResult->setResult($result);
215
            $this->queryResult->setNumRows($numRows);
216
        }
217
218
219
        /**
220
         * Return the benchmark instance
221
         * @return Benchmark
222
         */
223
        public function getBenchmark() {
224
            return $this->benchmarkInstance;
225
        }
226
227
        /**
228
         * Set the benchmark instance
229
         * @param Benchmark $benchmark the benchmark object
230
         * @return object DatabaseQueryRunner
231
         */
232
        public function setBenchmark($benchmark) {
233
            $this->benchmarkInstance = $benchmark;
234
            return $this;
235
        }
236
        
237
        /**
238
         * Return the database query result
239
         *
240
         * @return object DatabaseQueryResult
241
         */
242
        public function getQueryResult() {
243
            return $this->queryResult;
244
        }
245
246
        /**
247
         * Set the database query result instance
248
         * @param object $queryResult the query result
249
         *
250
         * @return object DatabaseQueryRunner
251
         */
252
        public function setQueryResult(DatabaseQueryResult $queryResult) {
253
            $this->queryResult = $queryResult;
254
            return $this;
255
        }
256
        
257
        /**
258
         * Return the current query SQL string
259
         * @return string
260
         */
261
        public function getQuery() {
262
            return $this->query;
263
        }
264
        
265
        /**
266
         * Set the query SQL string
267
         * @param string $query the SQL query to set
268
         * @return object DatabaseQueryRunner
269
         */
270
        public function setQuery($query) {
271
            $this->query = $query;
272
            return $this;
273
        }
274
        
275
        /**
276
         * Set the query return type as list or not
277
         * @param boolean $returnType
278
         * @return object DatabaseQueryRunner
279
         */
280
        public function setReturnType($returnType) {
281
            $this->returnAsList = $returnType;
282
            return $this;
283
        }
284
        
285
        /**
286
         * Set the return as array or not
287
         * @param boolean $status the status if true will return as array
288
         * @return object DatabaseQueryRunner
289
         */
290
        public function setReturnAsArray($status = true) {
291
            $this->returnAsArray = $status;
292
            return $this;
293
        }
294
        
295
        /**
296
         * Return the error for last query execution
297
         * @return string
298
         */
299
        public function getQueryError() {
300
            return $this->error;
301
        }
302
        
303
        /**
304
         * Return the benchmark key for the current query
305
         * 
306
         *  @return string
307
         */
308
        protected function getBenchmarkKey() {
309
            return md5($this->query . $this->returnAsList . $this->returnAsArray);
310
        }
311
        
312
        /**
313
         * Set error for database query execution
314
         */
315
        protected function setQueryRunnerError() {
316
            $error = $this->connection->getPdo()->errorInfo();
317
            $this->error = isset($error[2]) ? $error[2] : '';
318
            $this->logger->error('The database query execution got an error: ' . stringfy_vars($error));
319
            //show error message
320
            show_error('Query: "' . $this->query . '" Error: ' . $this->error, 'Database Error');
321
        }
322
        
323
        
324
        /**
325
         * Reset the instance before run each query
326
         */
327
        private function reset() {
328
            $this->error = null;
329
            $this->pdoStatment = null;
330
        }
331
332
    }
333