Database::fields()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.7085

Importance

Changes 0
Metric Value
dl 0
loc 15
c 0
b 0
f 0
rs 9.7666
ccs 4
cts 7
cp 0.5714
cc 3
nc 3
nop 2
crap 3.7085
1
<?php
2
namespace DBAL;
3
4
use PDO;
5
use DBAL\Modifiers\SafeString;
6
use DBAL\Modifiers\Operators;
7
8
/**
9
 * PDO Database connection class
10
 *
11
 * @author Adam Binnersley <[email protected]>
12
 * @version PDO Database Class
13
 */
14
class Database implements DBInterface
15
{
16
    protected $db;
17
    public $sql;
18
    private $key;
19
    
20
    protected $logLocation;
21
    public $logErrors = true;
22
    public $logQueries = false;
23
    public $displayErrors = false;
24
    
25
    protected $database;
26
    protected $cacheEnabled = false;
27
    protected $cacheObj;
28
    protected $cacheValue;
29
    protected $modified = false;
30
31
    private $query;
32
    public $values = [];
33
    private $prepare = [];
34
    
35
    private static $connectors = array(
36
        'cubrid' => 'cubrid:host=%s;port=%d;dbname=%s',
37
        'dblib' => 'dblib:host=%s:%d;dbname=%s',
38
        'mssql' => 'sqlsrv:Server=%s,%d;Database=%s',
39
        'mysql' => 'mysql:host=%s;port=%d;dbname=%s',
40
        'pgsql' => 'pgsql:host=%s;port=%d;dbname=%s',
41
        'sqlite' => 'sqlite::memory:'
42
    );
43
44
    /**
45
     * Connect to database using PDO connection
46
     * @param string $hostname This should be the host of the database e.g. 'localhost'
47
     * @param string $username This should be the username for the chosen database
48
     * @param string $password This should be the password for the chosen database
49
     * @param string $database This should be the database that you wish to connect to
50
     * @param string|false $backuphost If you have a replication server set up put the hostname or IP address to use if the primary server goes down
51
     * @param object|false $cache If you want to cache the queries with Memcache(d)/Redis/APC/XCache This should be the object else set to false
52
     * @param boolean $persistent If you want a persistent database connection set to true
53
     * @param string $type The type of connection that you wish to make can be 'mysql', 'cubrid', 'dblib', 'mssql', 'odbc', 'pgsql, or 'sqlite'
54
     * @param int $port This should be the port number of the MySQL database connection
55 1
     * @param string|false $logLocation  This should be where you wish the logs to be stored leave as false if default location is adequate
56 1
     * @param array $options Add any additional PDO connection options here
57
     */
58 1
    public function __construct($hostname, $username, $password, $database, $backuphost = false, $cache = false, $persistent = false, $type = 'mysql', $port = 3306, $logLocation = false, $options = [])
59
    {
60 1
        $this->setLogLocation($logLocation);
61 1
        try {
62
            $this->connectToServer($username, $password, $database, $hostname, $persistent, $type, $port, $options);
63
        } catch (\Exception $e) {
64 1
            if ($backuphost !== false) {
65
                $this->connectToServer($username, $password, $database, $backuphost, $persistent, $type, $port, $options);
66 1
            }
67
            $this->error($e);
68
        }
69 1
        if (is_object($cache)) {
70
            $this->setCaching($cache);
71
        }
72
    }
73
    
74 1
    /**
75 1
     * Closes the PDO database connection when Database object unset
76 1
     */
77
    public function __destruct()
78
    {
79
        $this->closeDatabase();
80
    }
81
    
82
    /**
83
     * Connect to the database using PDO connection
84
     * @param string $username This should be the username for the chosen database
85
     * @param string $password This should be the password for the chosen database
86
     * @param string $database This should be the database that you wish to connect to
87
     * @param string $hostname The host for the database
88 2
     * @param boolean $persistent If you want a persistent database connection set to true
89 2
     * @param string $type The type of connection that you wish to make can be 'mysql', 'cubrid', 'dblib', 'mssql', 'pgsql, or 'sqlite'
90 2
     * @param int $port The port number to connect to the MySQL server
91 2
     * @param array $options Add any additional PDO connection options here
92 2
     */
93 2
    protected function connectToServer($username, $password, $database, $hostname, $persistent = false, $type = 'mysql', $port = 3306, $options = [])
94 2
    {
95
        if (!$this->db) {
96
            $this->database = $database;
97 2
            $this->db = new PDO(
98
                sprintf(self::$connectors[$type], $hostname, $port, $database),
99 2
                $username,
100
                $password,
101
                array_merge(
102
                    ($persistent !== false ? array(PDO::ATTR_PERSISTENT => true) : []),
103
                    ($type === 'mysql' ? array(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, PDO::ATTR_EMULATE_PREPARES => true) : []),
104
                    (is_array($options) ? $options : [])
105 1
                )
106 1
            );
107 1
            $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
108 1
        }
109
    }
110 1
    
111
    /**
112
     * Enables the caching and set the caching object to the one provided
113
     * @param object $caching This should be class of the type of caching you are using
114
     */
115
    public function setCaching($caching)
116
    {
117
        if (is_object($caching)) {
118
            $this->cacheObj = $caching;
119 1
            $this->cacheEnabled = true;
120 1
        }
121
        return $this;
122 1
    }
123 1
    
124 1
    /**
125 1
     * This query function is used for more advanced SQL queries for which non of the other methods fit
126 1
     * @param string $sql This should be the SQL query which you wish to run
127
     * @param array $variables This should be an array of values to execute as the values in a prepared statement
128
     * @return array|boolean Returns array of results for the query that has just been run if select or returns true and false if executed successfully or not
129
     */
130
    public function query($sql, $variables = [], $cache = true)
131
    {
132
        if (!empty(trim($sql))) {
133 1
            $this->sql = $sql;
134
            $this->key = md5($this->sql.serialize($variables));
135
            if ($this->logQueries) {
136
                $this->writeQueryToLog();
137
            }
138
            if ($cache && $this->cacheEnabled && $this->getCache($this->key)) {
139
                return $this->cacheValue;
140
            }
141
            try {
142
                $this->query = $this->db->prepare($this->sql);
143
                $result = $this->query->execute($variables);
144 1
                $this->values = [];
145 1
                if (strpos($this->sql, 'SELECT') !== false) {
146
                    $result = $this->query->fetchAll(PDO::FETCH_ASSOC);
147
                    if ($cache && $this->cacheEnabled) {
148
                        $this->setCache($this->key, $result);
149
                    }
150
                }
151
                return $result;
152
            } catch (\Exception $e) {
153
                $this->error($e);
154
            }
155
        }
156
    }
157
    
158 3
    /**
159 3
     * Returns a single record for a select query for the chosen table
160 3
     * @param string $table This should be the table you wish to select the values from
161 3
     * @param array $where Should be the field names and values you wish to use as the where query e.g. array('fieldname' => 'value', 'fieldname2' => 'value2', etc).
162 3
     * @param string|array $fields This should be the records you wish to select from the table. It should be either set as '*' which is the default or set as an array in the following format array('field', 'field2', 'field3', etc).
163 2
     * @param array|string $order This is the order you wish the results to be ordered in should be formatted as follows array('fieldname' => 'ASC') or array("'fieldname', 'fieldname2'" => 'DESC')
164 3
     * @param boolean $cache If the query should be cached or loaded from cache set to true else set to false
165
     * @return array Returns a single table record as the standard array when running SQL queries
166 3
     */
167
    public function select($table, $where = [], $fields = '*', $order = [], $cache = true)
168
    {
169
        return $this->selectAll($table, $where, $fields, $order, 1, $cache);
170
    }
171
    
172
    /**
173
     * Returns a multidimensional array of the results from the selected table given the given parameters
174
     * @param string $table This should be the table you wish to select the values from
175
     * @param array $where Should be the field names and values you wish to use as the where query e.g. array('fieldname' => 'value', 'fieldname2' => 'value2', etc).
176
     * @param string|array $fields This should be the records you wish to select from the table. It should be either set as '*' which is the default or set as an array in the following format array('field', 'field2', 'field3', etc).
177
     * @param array|string $order This is the order you wish the results to be ordered in should be formatted as follows array('fieldname' => 'ASC') or array("'fieldname', 'fieldname2'" => 'DESC')
178
     * @param integer|array $limit The number of results you want to return 0 is default and returns all results, else should be formatted either as a standard integer or as an array as the start and end values e.g. array(0 => 150)
179 2
     * @param boolean $cache If the query should be cached or loaded from cache set to true else set to false
180 2
     * @return array Returns a multidimensional array with the chosen fields from the table
181 2
     */
182 2
    public function selectAll($table, $where = [], $fields = '*', $order = [], $limit = 0, $cache = true)
183 2
    {
184 2
        $this->buildSelectQuery(SafeString::makeSafe($table), $where, $fields, $order, $limit);
185 2
        $result = $this->executeQuery($cache);
186
        if (!$result) {
187
            if ($limit === 1) {
188
                $result = $this->query->fetch(PDO::FETCH_ASSOC); // Reduce the memory usage if only one record and increase performance
189
            } else {
190
                $result = $this->query->fetchAll(PDO::FETCH_ASSOC);
191
            }
192
            if ($cache && $this->cacheEnabled) {
193
                $this->setCache($this->key, $result);
194
            }
195
        }
196 2
        return $result ? $result : false;
197 2
    }
198
    
199 2
    /**
200 2
     * Returns a single column value for a given query
201 2
     * @param string $table This should be the table you wish to select the values from
202
     * @param array $where Should be the field names and values you wish to use as the where query e.g. array('fieldname' => 'value', 'fieldname2' => 'value2', etc).
203
     * @param array $fields This should be the records you wish to select from the table. It should be either set as '*' which is the default or set as an array in the following format array('field', 'field2', 'field3', etc).
204
     * @param int $colNum This should be the column number you wish to get (starts at 0)
205
     * @param array $order This is the order you wish the results to be ordered in should be formatted as follows array('fieldname' => 'ASC') or array("'fieldname', 'fieldname2'" => 'DESC') so it can be done in both directions
206
     * @param boolean $cache If the query should be cached or loaded from cache set to true else set to false
207
     * @return mixed If a result is found will return the value of the column given else will return false
208
     */
209
    public function fetchColumn($table, $where = [], $fields = '*', $colNum = 0, $order = [], $cache = true)
210
    {
211
        $this->buildSelectQuery(SafeString::makeSafe($table), $where, $fields, $order, 1);
212 2
        $result = $this->executeQuery($cache);
213 2
        if (!$result) {
214 2
            $column = $this->query->fetchColumn(intval($colNum));
215 2
            if ($cache && $this->cacheEnabled) {
216
                $this->setCache($this->key, $column);
217
            }
218
            return ($column ? $column : false);
219
        }
220
        return false;
221
    }
222
    
223
    /**
224 2
     * Inserts into database using the prepared PDO statements
225 2
     * @param string $table This should be the table you wish to insert the values into
226 2
     * @param array $records This should be the field names and values in the format of array('fieldname' => 'value', 'fieldname2' => 'value2', etc.)
227 2
     * @return boolean If data is inserted returns true else returns false
228
     */
229
    public function insert($table, $records)
230
    {
231
        unset($this->prepare);
232
        
233
        $this->sql = sprintf("INSERT INTO `%s` (%s) VALUES (%s);", SafeString::makeSafe($table), $this->fields($records, true), implode(', ', $this->prepare));
234
        $this->executeQuery(false);
235
        return $this->numRows() ? true : false;
236
    }
237 1
    
238 1
    /**
239 1
     * Updates values in a database using the provide variables
240
     * @param string $table This should be the table you wish to update the values for
241 1
     * @param array $records This should be the field names and new values in the format of array('fieldname' => 'newvalue', 'fieldname2' => 'newvalue2', etc.)
242 1
     * @param array $where Should be the field names and values you wish to update in the form of an array e.g. array('fieldname' => 'value', 'fieldname2' => 'value2', etc).
243 1
     * @param int $limit The number of results you want to return 0 is default and will update all results that match the query, else should be formatted as a standard integer
244 1
     * @return boolean Returns true if update is successful else returns false
245
     */
246 1
    public function update($table, $records, $where = [], $limit = 0)
247
    {
248
        $this->sql = sprintf("UPDATE `%s` SET %s %s%s;", SafeString::makeSafe($table), $this->fields($records), $this->where($where), $this->limit($limit));
249
        $this->executeQuery(false);
250
        return $this->numRows() ? true : false;
251
    }
252
    
253
    /**
254 1
     * Deletes records from the given table based on the variables given
255
     * @param string $table This should be the table you wish to delete the records from
256 1
     * @param array $where This should be an array of for the where statement
257 1
     * @param int $limit The number of results you want to return 0 is default and will delete all results that match the query, else should be formatted as a standard integer
258
     */
259
    public function delete($table, $where, $limit = 0)
260
    {
261
        $this->sql = sprintf("DELETE FROM `%s` %s%s;", SafeString::makeSafe($table), $this->where($where), $this->limit($limit));
262 1
        $this->executeQuery(false);
263
        return $this->numRows() ? true : false;
264
    }
265
    
266
    /**
267
     * Count the number of return results
268
     * @param string $table The table you wish to count the result of
269 8
     * @param array $where Should be the field names and values you wish to use as the where query e.g. array('fieldname' => 'value', 'fieldname2' => 'value2', etc).
270 8
     * @param boolean $cache If the query should be cached or loaded from cache set to true else set to false
271 8
     * @return int Returns the number of results
272
     */
273
    public function count($table, $where = [], $cache = true)
274
    {
275
        $this->sql = sprintf("SELECT count(*) FROM `%s`%s;", SafeString::makeSafe($table), $this->where($where));
276
        $this->key = md5($this->database.$this->sql.serialize($this->values));
277
        
278
        $result = $this->executeQuery($cache);
279
        if (!$result) {
280 1
            $result = $this->query->fetchColumn();
281 1
            if ($cache && $this->cacheEnabled) {
282
                $this->setCache($this->key, $result);
283
            }
284
        }
285
        return $result;
286
    }
287
    
288
    /**
289 1
     * Truncates a given table from the selected database so there are no values in the table
290 1
     * @param string $table This should be the table you wish to truncate
291
     * @return boolean If the table is emptied returns true else returns false
292
     */
293
    public function truncate($table)
294
    {
295
        try {
296
            $this->sql = sprintf("TRUNCATE TABLE `%s`", SafeString::makeSafe($table));
297 2
            $this->executeQuery(false);
298 2
        } catch (\Exception $e) {
299
            $this->error($e);
300
        }
301
        return $this->numRows() ? true : false;
302
    }
303
    
304 1
    /**
305 1
     * Returns the number of rows for the last query sent
306
     * @return int Returns the number of rows for the last query
307
     */
308
    public function numRows()
309
    {
310
        if (isset($this->query)) {
311
            return $this->query->rowCount();
312
        }
313 1
        return 0;
314 1
    }
315 1
    
316
    /**
317 1
     * Returns the number of rows for the last query sent (Looks a the numRows() function just added incase of habbit)
318 1
     * @return int Returns the number of rows for the last query
319 1
     */
320
    public function rowCount()
321 1
    {
322
        return $this->numRows();
323
    }
324
    
325
    /**
326
     * Returns the ID of the last record last inserted
327
     * @param string $name This should be the name of the sequence object you wish to retrieve
328 4
     * @return int|string Returns the last inserted ID of the last insert item if $name is null else returns string with sequenced object
329 4
     */
330 4
    public function lastInsertId($name = null)
331 4
    {
332 4
        return $this->db->lastInsertId($name);
333 4
    }
334
    
335 4
    /**
336
     * Checks to see if a connection has been made to the server
337
     * @return boolean
338 4
     */
339
    public function isConnected()
340
    {
341
        return is_object($this->db) ? true : false;
342
    }
343
    
344
    /**
345
     * Returns the server version information
346
     */
347
    public function serverVersion()
348
    {
349
        return $this->db->getAttribute(PDO::ATTR_SERVER_VERSION);
350
    }
351
    
352
    /**
353 1
     * Sets the location of the log files
354 1
     * @param string $location This should be where you wish the logs to be stored
355 1
     * @return $this
356
     */
357
    public function setLogLocation($location = false)
358
    {
359
        if ($location === false) {
360
            $location = dirname(__FILE__).DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR;
361
        }
362
        $this->logLocation = $location;
363
        if (!file_exists($location)) {
364
            mkdir($location, 0777, true);
365 5
        }
366 5
        return $this;
367 1
    }
368 1
    
369 1
    /**
370
     * Displays the error massage which occurs
371 1
     * @param \Exception $error This should be an instance of Exception
372
     */
373 5
    private function error($error)
374
    {
375 5
        if ($this->logErrors) {
376 5
            $file = $this->logLocation.'db-errors.txt';
377 5
            $current = file_get_contents($file);
378
            $current .= date('d/m/Y H:i:s')." ERROR: ".$error->getMessage()." on ".$this->sql."\n";
379
            file_put_contents($file, $current);
380
        }
381
        die($this->displayErrors ? 'ERROR: '.$error->getMessage().' on '.$this->sql : 0);
382
    }
383
    
384 13
    /**
385 13
     * Writes all queries to a log file
386 13
     */
387
    public function writeQueryToLog()
388
    {
389
        $file = $this->logLocation.'queries.txt';
390 13
        $current = file_get_contents($file);
391 13
        $current .= "SQL: ".$this->sql.":".serialize($this->values)."\n";
392 13
        file_put_contents($file, $current);
393 13
    }
394 13
    
395
    /**
396 3
     * Closes the PDO database connection by setting the connection to NULL
397 3
     */
398 3
    public function closeDatabase()
399 3
    {
400
        $this->db = null;
401 13
    }
402
    
403
    /**
404
     * Build the SQL query but doesn't execute it
405
     * @param string $table This should be the table you wish to select the values from
406
     * @param array $where Should be the field names and values you wish to use as the where query e.g. array('fieldname' => 'value', 'fieldname2' => 'value2', etc).
407
     * @param string|array $fields This should be the records you wish to select from the table. It should be either set as '*' which is the default or set as an array in the following format array('field', 'field2', 'field3', etc).
408 9
     * @param array|string $order This is the order you wish the results to be ordered in should be formatted as follows array('fieldname' => 'ASC') or array("'fieldname', 'fieldname2'" => 'DESC') so it can be done in both directions
409 9
     * @param integer|array $limit The number of results you want to return 0 is default and returns all results, else should be formatted either as a standard integer or as an array as the start and end values e.g. array(0 => 150)
410 8
     */
411 8
    protected function buildSelectQuery($table, $where = [], $fields = '*', $order = [], $limit = 0)
412 8
    {
413
        if (is_array($fields)) {
414 8
            $selectfields = [];
415 8
            foreach ($fields as $field => $value) {
416
                $selectfields[] = sprintf("`%s`", SafeString::makeSafe($value));
417
            }
418 2
            $fieldList = implode(', ', $selectfields);
419
        } else {
420
            $fieldList = '*';
421
        }
422
        
423
        $this->sql = sprintf("SELECT %s FROM `%s`%s%s%s;", $fieldList, SafeString::makeSafe($table), $this->where($where), $this->orderBy($order), $this->limit($limit));
424
        $this->key = md5($this->database.$this->sql.serialize($this->values));
425
    }
426 1
    
427 1
    /**
428 1
     * Execute the current query if no cache value is available
429 1
     * @param boolean $cache If the cache should be checked for the checked for the values of the query set to true else set to false
430 1
     * @return mixed If a cached value exists will be returned else if cache is not checked and query is executed will not return anything
431 1
     */
432
    protected function executeQuery($cache = true)
433
    {
434 1
        if ($this->logQueries) {
435
            $this->writeQueryToLog();
436
        }
437 1
        if ($cache && $this->cacheEnabled && $this->getCache($this->key)) {
438
            $this->values = [];
439
            return $this->cacheValue;
440
        }
441
        try {
442
            $this->query = $this->db->prepare($this->sql);
443
            $this->bindValues($this->values);
444
            $this->query->execute();
445
            $this->values = [];
446
        } catch (\Exception $e) {
447
            $this->values = [];
448
            $this->error($e);
449
        }
450
    }
451 4
    
452 4
    /**
453
     * This outputs the SQL where query based on a given array
454 4
     * @param array $where This should be an array that you wish to create the where query for in the for array('field1' => 'test') or array('field1' => array('>=', 0))
455 4
     * @return string|false If the where query is an array will return the where string and set the values else returns false if no array sent
456 4
     */
457 4
    public function where($where)
458
    {
459
        if (is_array($where) && !empty($where)) {
460 2
            $wherefields = [];
461
            foreach ($where as $field => $value) {
462 4
                $wherefields[] = $this->formatValues($field, $value);
463
            }
464 4
            if (!empty($wherefields)) {
465
                return " WHERE ".implode(' AND ', $wherefields);
466
            }
467
        }
468
        return false;
469
    }
470
    
471
    /**
472 1
     * Sets the order sting for the SQL query based on an array or string
473 1
     * @param array|string $order This should be either set to array('fieldname' => 'ASC/DESC') or RAND()
474 1
     * @return string|false If the SQL query has an valid order by will return a string else returns false
475 1
     */
476
    public function orderBy($order)
477
    {
478 1
        if (is_array($order) && !empty(array_filter($order))) {
479 1
            $string = [];
480
            foreach ($order as $fieldorder => $fieldvalue) {
481 1
                if (!empty($fieldorder) && !empty($fieldvalue)) {
482
                    $string[] = sprintf("`%s` %s", SafeString::makeSafe($fieldorder), strtoupper(SafeString::makeSafe($fieldvalue)));
483
                } elseif ($fieldvalue === 'RAND()') {
484
                    $string[] = $fieldvalue;
485
                }
486
            }
487
            return sprintf(" ORDER BY %s", implode(", ", $string));
488
        } elseif ($order == 'RAND()') {
489
            return " ORDER BY RAND()";
490 2
        }
491 2
        return false;
492 2
    }
493
    
494 2
    /**
495
     * Build the field list for the query
496
     * @param array $records This should be an array listing all of the fields
497
     * @param boolean $insert If this is an insert statement should be set to true to create the correct amount of queries for the prepared statement
498
     * @return string The fields list will be returned as a string to insert into the SQL query
499
     */
500
    public function fields($records, $insert = false)
501 2
    {
502 2
        $fields = [];
503
        
504 2
        foreach ($records as $field => $value) {
505 2
            if ($insert === true) {
506
                $fields[] = sprintf("`%s`", SafeString::makeSafe($field));
507
                $this->prepare[] = '?';
508
            } else {
509
                $fields[] = sprintf("`%s` = ?", SafeString::makeSafe($field));
510
            }
511
            $this->values[] = $value;
512
        }
513
        return implode(', ', $fields);
514
    }
515
    
516
    /**
517
     * Returns the limit SQL for the current query as a string
518
     * @param integer|array $limit This should either be set as an integer or should be set as an array with a start and end value
519
     * @return string|false Will return the LIMIT string for the current query if it is valid else returns false
520
     */
521
    public function limit($limit = 0)
522 8
    {
523 8
        if (is_array($limit) && !empty(array_filter($limit))) {
524 1
            foreach ($limit as $start => $end) {
525
                 return " LIMIT ".max(intval($start), 0).", ".max(intval($end), 0);
526 8
            }
527 2
        } elseif ((int)$limit > 0) {
528 2
            return " LIMIT ".intval($limit);
529 2
        }
530 2
        return false;
531
    }
532
    
533 1
    
534 1
    /**
535 1
     * Set the cache with a key and value
536
     * @param string $key The unique key to store the value against
537 1
     * @param mixed $value The value of the MYSQL query
538
     */
539 2
    public function setCache($key, $value)
540
    {
541
        if ($this->cacheEnabled) {
542 6
            $this->cacheObj->save($key, $value);
543 6
        }
544
    }
545
    
546
    /**
547
     * Get the results for a given key
548
     * @param string $key The unique key to check for stored variables
549
     * @return mixed Returned the cached results from
550 12
     */
551 12
    public function getCache($key)
552 12
    {
553 12
        if ($this->modified === true || !$this->cacheEnabled) {
554 12
            return false;
555 12
        }
556 12
        $this->cacheValue = $this->cacheObj->fetch($key);
557 12
        return $this->cacheValue;
558
    }
559
    
560 12
    /**
561
     * Clears the cache
562
     */
563
    public function flushDB()
564
    {
565
        $this->cacheObj->deleteAll();
566
    }
567
    
568
    /**
569
     * Format the where queries and set the prepared values
570
     * @param string $field This should be the field name in the database
571
     * @param mixed $value This should be the value which should either be a string or an array if it contains an operator
572
     * @return string This should be the string to add to the SQL query
573
     */
574
    protected function formatValues($field, $value)
575
    {
576
        if (!is_array($value) && Operators::isOperatorValid($value) && !Operators::isOperatorPrepared($value)) {
577
            return sprintf("`%s` %s", SafeString::makeSafe($field), Operators::getOperatorFormat($value));
578
        } elseif (is_array($value)) {
579
            $keys = [];
580
            if (!is_array(array_values($value)[0])) {
581
                $this->values[] = (isset($value[1]) ? $value[1] : array_values($value)[0]);
582
                $operator = (isset($value[0]) ? $value[0] : key($value));
583
            } else {
584
                foreach (array_values($value)[0] as $op => $array_value) {
585
                    $this->values[] = $array_value;
586
                    $keys[] = '?';
587
                }
588
                $operator = key($value);
589
            }
590
            return sprintf("`%s` %s", SafeString::makeSafe($field), sprintf(Operators::getOperatorFormat($operator), implode(', ', $keys)));
591
        }
592
        $this->values[] = $value;
593
        return sprintf("`%s` = ?", SafeString::makeSafe($field));
594
    }
595
    
596
    /**
597
     * Band values to use in the query
598
     * @param array $values This should be the values being used in the query
599
     */
600
    protected function bindValues($values)
601
    {
602
        if (is_array($values)) {
603
            foreach ($values as $i => $value) {
604
                if (is_numeric($value) && intval($value) == $value && (isset($value[0]) && $value[0] != 0 || !isset($value[0]))) {
605
                    $type = PDO::PARAM_INT;
606
                    $value = intval($value);
607
                } elseif (is_null($value) || $value === 'NULL') {
608
                    $type = PDO::PARAM_NULL;
609
                    $value = null;
610
                } elseif (is_bool($value)) {
611
                    $type = PDO::PARAM_BOOL;
612
                } else {
613
                    $type = PDO::PARAM_STR;
614
                }
615
                $this->query->bindValue(intval($i + 1), $value, $type);
616
            }
617
        }
618
    }
619
}
620