Test Failed
Push — 1.0.0-dev ( 76319a...aa9039 )
by nguereza
02:25
created

Database::getCacheTimeToLive()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
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 Database extends BaseClass {
32
	
33
        /**
34
         * The DatabaseConnection instance
35
         * @var object
36
         */
37
        private $connection = null;
38
    
39
        /**
40
         * The number of rows returned by the last query
41
         * @var int
42
         */
43
        private $numRows = 0;
44
	
45
        /**
46
         * The last insert id for the primary key column that have auto increment or sequence
47
         * @var mixed
48
         */
49
        private $insertId = null;
50
	
51
        /**
52
         * The full SQL query statment after build for each command
53
         * @var string
54
         */
55
        private $query = null;
56
	
57
        /**
58
         * The result returned for the last query
59
         * @var mixed
60
         */
61
        private $result = array();
62
	
63
        /**
64
         * The number of executed query for the current request
65
         * @var int
66
         */
67
        private $queryCount = 0;
68
	
69
        /**
70
         * The default data to be used in the statments query INSERT, UPDATE
71
         * @var array
72
         */
73
        private $data = array();
74
	
75
        /**
76
         * The cache default time to live in second. 0 means no need to use the cache feature
77
         * @var int
78
         */
79
        private $cacheTtl = 0;
80
81
        /**
82
         * The cache current time to live. 0 means no need to use the cache feature
83
         * @var int
84
         */
85
        private $temporaryCacheTtl = 0;
86
87
        /**
88
         * The DatabaseQueryBuilder instance
89
         * @var object
90
         */
91
        protected $queryBuilder = null;
92
    
93
        /**
94
         * The DatabaseQueryRunner instance
95
         * @var object
96
         */
97
        protected $queryRunner = null;
98
99
        /**
100
         * The DatabaseCache instance
101
         * @var object
102
         */
103
        protected $cache = null;
104
105
        /**
106
         * Construct new instance
107
         * 
108
         * @param object $connection the DatabaseConnection instance
109
         */
110
        public function __construct(DatabaseConnection $connection = null) {
111
            parent::__construct();
112
    		
113
            //Set DatabaseQueryBuilder instance to use
114
            $this->setDependencyInstanceFromParamOrCreate('queryBuilder', null, 'DatabaseQueryBuilder', 'classes/database');
115
           
116
            //Set DatabaseQueryRunner instance to use
117
            $this->setDependencyInstanceFromParamOrCreate('queryRunner', null, 'DatabaseQueryRunner', 'classes/database');
118
119
            //Set DatabaseCache instance to use
120
            $this->setDependencyInstanceFromParamOrCreate('cache', null, 'DatabaseCache', 'classes/database');
121
122
            if ($connection !== null) {
123
                $this->connection = $connection;
124
            } else {
125
                $this->setConnectionUsingConfigFile();
126
            }
127
            //Update some properties
128
            $this->updateProperties();
129
        }
130
131
        /**
132
         * Get the result of one record rows returned by the current query
133
         * @param  boolean|string $sqlOrResult if is boolean and true will return the SQL query string.
134
         * If is string will determine the result type "array" or "object"
135
         * @return mixed       the query SQL string or the record result
136
         */
137
        public function get($sqlOrResult = false) {
138
            $this->queryBuilder->limit(1);
139
            $query = $this->getAll($returnSql = true);
140
            if ($sqlOrResult === true) {
141
                return $query;
142
            } 
143
            return $this->query($query, false, $sqlOrResult == 'array');
144
        }
145
146
        /**
147
         * Get the result of record rows list returned by the current query
148
         * @param  boolean|string $sqlOrResult if is boolean and true will return the SQL query string.
149
         * If is string will determine the result type "array" or "object"
150
         * @return mixed       the query SQL string or the record result
151
         */
152
        public function getAll($sqlOrResult = false) {
153
            $query = $this->queryBuilder->getQuery();
154
            if ($sqlOrResult === true) {
155
                return $query;
156
            }
157
            return $this->query($query, true, $sqlOrResult == 'array');
158
        }
159
160
        /**
161
         * Insert new record in the database
162
         * @param  array   $data   the record data if is empty will use the $this->data array.
163
         * @param  boolean $escape  whether to escape or not the values
164
         * @return mixed          the insert id of the new record or null
165
         */
166
        public function insert($data = array(), $escape = true) {
167
            if (empty($data) && !empty($this->data)) {
168
                //as when using $this->setData() may be the data already escaped
169
                $escape = false;
170
                $data = $this->data;
171
            }
172
            $query = $this->queryBuilder->insert($data, $escape)->getQuery();
173
            $result = $this->query($query);
174
            if ($result) {
175
                $this->insertId = $this->connection->getPdo()->lastInsertId();
176
                //if the table doesn't have the auto increment field or sequence, the value of 0 will be returned 
177
                $id = $this->insertId;
178
                if (!$id) {
179
                    $id = true;
180
                }
181
                return $id;
182
            }
183
            return false;
184
        }
185
186
        /**
187
         * Update record in the database
188
         * @param  array   $data   the record data if is empty will use the $this->data array.
189
         * @param  boolean $escape  whether to escape or not the values
190
         * @return mixed          the update status
191
         */
192
        public function update($data = array(), $escape = true) {
193
            if (empty($data) && !empty($this->data)) {
194
                //as when using $this->setData() may be the data already escaped
195
                $escape = false;
196
                $data = $this->data;
197
            }
198
            $query = $this->queryBuilder->update($data, $escape)->getQuery();
199
            return $this->query($query);
200
        }
201
202
        /**
203
         * Delete the record in database
204
         * @return mixed the delete status
205
         */
206
        public function delete() {
207
            $query = $this->queryBuilder->delete()->getQuery();
208
            return $this->query($query);
209
        }
210
211
        /**
212
         * Set database cache time to live
213
         * @param integer $ttl the cache time to live in second
214
         * @return object        the current instance
215
         */
216
        public function setCacheTimeToLive($ttl = 0) {
217
            $this->cacheTtl = $ttl;
218
            $this->temporaryCacheTtl = $ttl;
219
            return $this;
220
        }
221
222
        /**
223
         * Get database cache time to live
224
         * @return integer        
225
         */
226
        public function getCacheTimeToLive() {
227
            return $this->cacheTtl;
228
        }
229
230
        /**
231
         * Get database current cache time to live
232
         * @return integer        
233
         */
234
        public function getTempCacheTimeToLive() {
235
            return $this->temporaryCacheTtl;
236
        }
237
	
238
        /**
239
         * Enabled cache temporary for the current query not globally   
240
         * @param  integer $ttl the cache time to live in second
241
         * @return object        the current instance
242
         */
243
        public function cached($ttl = 0) {
244
            $this->temporaryCacheTtl = $ttl;
245
            return $this;
246
        }
247
248
        /**
249
         * Return the number query executed count for the current request
250
         * @return int
251
         */
252
        public function queryCount() {
253
            return $this->queryCount;
254
        }
255
256
        /**
257
         * Return the current query SQL string
258
         * @return string
259
         */
260
        public function getQuery() {
261
            return $this->query;
262
        }
263
264
        /**
265
         * Return the DatabaseConnection instance
266
         * @return object DatabaseConnection
267
         */
268
        public function getConnection() {
269
            return $this->connection;
270
        }
271
272
        /**
273
         * Set the DatabaseConnection instance
274
         * @param object DatabaseConnection $connection the DatabaseConnection object
275
         *
276
         * @return object the current instance
277
         */
278
        public function setConnection(DatabaseConnection $connection = null) {
279
            $this->connection = $connection;
280
            return $this;
281
        }
282
283
        /**
284
         * Return the DatabaseQueryBuilder instance
285
         * @return object DatabaseQueryBuilder
286
         */
287
        public function getQueryBuilder() {
288
            return $this->queryBuilder;
289
        }
290
291
        /**
292
         * Set the DatabaseQueryBuilder instance
293
         * @param object DatabaseQueryBuilder $queryBuilder the DatabaseQueryBuilder object
294
         */
295
        public function setQueryBuilder(DatabaseQueryBuilder $queryBuilder = null) {
296
            $this->queryBuilder = $queryBuilder;
297
            return $this;
298
        }
299
300
        /**
301
         * Return the DatabaseCache instance
302
         * @return object DatabaseCache
303
         */
304
        public function getCache() {
305
            return $this->cache;
306
        }
307
308
        /**
309
         * Set the DatabaseCache instance
310
         * @param object DatabaseCache $cache the DatabaseCache object
311
         */
312
        public function setCache(DatabaseCache $cache = null) {
313
            $this->cache = $cache;
314
            return $this;
315
        }
316
    
317
        /**
318
         * Return the DatabaseQueryRunner instance
319
         * @return object DatabaseQueryRunner
320
         */
321
        public function getQueryRunner() {
322
            return $this->queryRunner;
323
        }
324
325
        /**
326
         * Set the DatabaseQueryRunner instance
327
         * @param object DatabaseQueryRunner $queryRunner the DatabaseQueryRunner object
328
         */
329
        public function setQueryRunner(DatabaseQueryRunner $queryRunner = null) {
330
            $this->queryRunner = $queryRunner;
331
            return $this;
332
        }
333
334
        /**
335
         * Return the data to be used for insert, update, etc.
336
         * @return array
337
         */
338
        public function getData() {
339
            return $this->data;
340
        }
341
342
        /**
343
         * Set the data to be used for insert, update, etc.
344
         * @param string|array $key the data key identified
345
         * @param mixed $value the data value
346
         * @param boolean $escape whether to escape or not the $value
347
         * @return object        the current Database instance
348
         */
349
        public function setData($key, $value = null, $escape = true) {
350
            if (is_array($key)) {
351
                foreach ($key as $k => $v) {
352
                    $this->setData($k, $v, $escape);
353
                }	
354
            } else {
355
                $this->data[$key] = $this->connection->escape($value, $escape);
356
            }
357
            return $this;
358
        }
359
360
        /**
361
         * Return the number of rows returned by the current query
362
         * @return int
363
         */
364
        public function numRows() {
365
            return $this->numRows;
366
        }
367
368
        /**
369
         * Return the last insert id value
370
         * @return mixed
371
         */
372
        public function insertId() {
373
            return $this->insertId;
374
        }
375
376
        /**
377
         * Execute an SQL query
378
         * @param  string  $query the query SQL string
379
         * @param  boolean $returnAsList  indicate whether to return all record or just one row 
380
         * @param  boolean $returnAsArray return the result as array or not
381
         * @return mixed         the query result
382
         */
383
        public function query($query, $returnAsList = true, $returnAsArray = false) {
384
            $this->reset();
385
            $this->query = preg_replace('/\s\s+|\t\t+/', ' ', trim($query));
386
            $this->logger->info('Execute SQL query [' . $this->query . ']');
387
388
            $cacheExpire = $this->temporaryCacheTtl;
389
390
            //return to the initial cache time
391
            $this->temporaryCacheTtl = $this->cacheTtl;
392
393
            //the database cache content
394
            $cacheContent = $this->cache->setQuery($query)
395
                                        ->setReturnType($returnAsList)
396
                                        ->setReturnAsArray($returnAsArray)
397
                                        ->setCacheTtl($cacheExpire)
398
                                        ->getCacheContent();
399
            if (!$cacheContent) {
400
                $this->logger->info('No cache data found for this query or is not a SELECT query, get result from real database');
401
                //count the number of query execution to server
402
                $this->queryCount++;
403
                
404
                $queryResult = $this->queryRunner->setQuery($query)
405
                                                 ->setReturnType($returnAsList)
406
                                                 ->setReturnAsArray($returnAsArray)
407
                                                 ->execute();
408
409
                if (is_object($queryResult)) {
410
                    $this->result  = $queryResult->getResult();
411
                    $this->numRows = $queryResult->getNumRows();
412
                    //save the result into cache
413
                    $this->cache->saveCacheContent($this->result);
414
                }
415
            } else {
416
                $this->logger->info('The result for query [' . $this->query . '] already cached use it');
417
                $this->result = $cacheContent;
418
                $this->numRows = count($this->result); //TODO check if is_array before use count
419
            }
420
            return $this->result;
421
        }
422
423
         /**
424
         * Set the connection instance using database configuration file
425
         *
426
         * @return object|void
427
         */
428
        protected function setConnectionUsingConfigFile(){
429
            $dbConfigFromFile = $this->getDatabaseConfigFromFile();
430
            $connection = &class_loader('DatabaseConnection', 'classes/database');
431
            $connection->setConfig($dbConfigFromFile);
432
            $connection->connect();
433
            $this->connection = $connection;
434
            return $this;
435
        }
436
437
438
        /**
439
         * Get the database configuration using the configuration file
440
         
441
         * @return array the database configuration from file
442
         */
443
        protected function getDatabaseConfigFromFile() {
444
            $db = array();
445
            if (file_exists(CONFIG_PATH . 'database.php')) {
446
                //here don't use require_once because somewhere user can create database instance directly
447
                require CONFIG_PATH . 'database.php';
448
            }
449
            return $db;
450
        }
451
452
        /**
453
         * Update the dependency for some properties
454
         * @return object the current instance
455
         */
456
        protected function updateProperties() {
457
            //update queryBuilder with some properties needed
458
            if (is_object($this->queryBuilder)) {
459
                $this->queryBuilder->setConnection($this->connection);
460
            }
461
462
            //update queryRunner with some properties needed
463
            if (is_object($this->queryRunner)) {
464
                $this->queryRunner->setConnection($this->connection);
465
            }
466
            return $this;
467
        }
468
	
469
        /**
470
         * Reset the database class attributs to the initail values before each query.
471
         */
472
        private function reset() {
473
            //query builder reset
474
            $this->queryBuilder->reset();
475
            $this->numRows  = 0;
476
            $this->insertId = null;
477
            $this->query    = null;
478
            $this->result   = array();
479
            $this->data     = array();
480
        }
481
    }
482