From bb382131cc0d34c5ef725a27b7133c595d11825e Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Wed, 7 Sep 2016 13:10:03 -0400 Subject: [PATCH] Code Style fixes --- .travis.yml | 3 +- LICENSE.md | 28 ++---- README.md | 4 +- src/Query/AbstractDriver.php | 26 +++--- src/Query/AbstractQueryBuilder.php | 48 +++++----- src/Query/AbstractUtil.php | 8 +- src/Query/BadDBDriverException.php | 3 +- src/Query/ConnectionManager.php | 30 ++++--- src/Query/DriverInterface.php | 4 +- src/Query/Drivers/Firebird/Driver.php | 14 +-- src/Query/Drivers/Firebird/Result.php | 10 +-- src/Query/Drivers/Firebird/Util.php | 8 +- src/Query/Drivers/Mysql/Driver.php | 6 +- src/Query/Drivers/Mysql/Util.php | 6 +- src/Query/Drivers/Pgsql/Driver.php | 8 +- src/Query/Drivers/Pgsql/Util.php | 6 +- src/Query/Drivers/Sqlite/Driver.php | 18 ++-- src/Query/Drivers/Sqlite/SQL.php | 4 +- src/Query/Drivers/Sqlite/Util.php | 6 +- src/Query/QueryBuilder.php | 48 +++++----- src/Query/QueryBuilderInterface.php | 121 +++++++++++++++++--------- src/Query/QueryParser.php | 20 ++--- 22 files changed, 225 insertions(+), 204 deletions(-) diff --git a/.travis.yml b/.travis.yml index e06e81a..d85618a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,11 +3,11 @@ sudo: false language: php php: - - 5.3 - 5.4 - 5.5 - 5.6 - 7 + - 7.1 - hhvm - nightly @@ -28,7 +28,6 @@ after_script: matrix: allow_failures: - - php: 5.3 - php: 5.4 - php: 5.5 - php: nightly \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md index 2836728..6316987 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,27 +1,9 @@ -# DON'T BE A DICK PUBLIC LICENSE +The MIT License (MIT) -> Version 1, December 2009 +Copyright (c) 2016 Timothy J. Warren -> Copyright (C) 2012 Timothy J. Warren +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -> DON'T BE A DICK PUBLIC LICENSE -> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 1. Do whatever you like with the original work, just don't be a dick. - - Being a dick includes - but is not limited to - the following instances: - - 1a. Outright copyright infringement - Don't just copy this and change the name. - 1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick. - 1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick. - - 2. If you become rich through modifications, related works/services, or supporting the original work, - share the love. Only a dick would make loads off this work and not buy the original work's - creator(s) a pint. - - 3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes - you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 7eb2ab6..6e45031 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,6 @@ A query builder/database abstraction layer, using prepared statements for securi ## Including Query in your application * Install via composer and include `vendor/autoload.php` -or -* Just include the `autoload.php` file. This will automatically load the classes that are supported by the current PHP installation. - ## Connecting @@ -83,6 +80,7 @@ Query('old')->query($sql); ### Running Queries Query uses the same interface as CodeIgniter's [Query Builder](http://www.codeigniter.com/user_guide/database/query_builder.html) class. However, it does not implement the `update_batch` or caching methods. For specific query builder methods, see the [class documentation](https://gitdev.timshomepage.net/Query/docs/classes/Query_QueryBuilder.html#methods). +Underscored methods are also aliased to camel case methods. #### You can also run queries manually. diff --git a/src/Query/AbstractDriver.php b/src/Query/AbstractDriver.php index 3746b1e..0da097c 100644 --- a/src/Query/AbstractDriver.php +++ b/src/Query/AbstractDriver.php @@ -65,7 +65,7 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { /** * Whether the driver supports 'TRUNCATE' - * @var bool + * @var boolean */ protected $has_truncate = TRUE; @@ -77,7 +77,7 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { * @param string $password * @param array $driver_options */ - public function __construct($dsn, $username=NULL, $password=NULL, array $driver_options=array()) + public function __construct($dsn, $username=NULL, $password=NULL, array $driver_options=[]) { // Set PDO to display errors as exceptions, and apply driver options $driver_options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_EXCEPTION; @@ -117,7 +117,7 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { * @param array $args * @return mixed */ - public function __call($name, $args = array()) + public function __call($name, $args = []) { if ( isset($this->$name) @@ -125,7 +125,7 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { && method_exists($this->$name, '__invoke') ) { - return call_user_func_array(array($this->$name, '__invoke'), $args); + return call_user_func_array([$this->$name, '__invoke'], $args); } } @@ -319,14 +319,14 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { { if (is_array($ident)) { - return array_map(array($this, __METHOD__), $ident); + return array_map([$this, __METHOD__], $ident); } // Handle comma-separated identifiers if (strpos($ident, ',') !== FALSE) { $parts = array_map('mb_trim', explode(',', $ident)); - $parts = array_map(array($this, __METHOD__), $parts); + $parts = array_map([$this, __METHOD__], $parts); $ident = implode(',', $parts); } @@ -335,10 +335,10 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { $hiers = array_map('mb_trim', $hiers); // Re-compile the string - $raw = implode('.', array_map(array($this, '_quote'), $hiers)); + $raw = implode('.', array_map([$this, '_quote'], $hiers)); // Fix functions - $funcs = array(); + $funcs = []; preg_match_all("#{$this->escape_char}([a-zA-Z0-9_]+(\((.*?)\))){$this->escape_char}#iu", $raw, $funcs, PREG_SET_ORDER); foreach($funcs as $f) { @@ -561,7 +561,7 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { public function num_rows() { $regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/i'; - $output = array(); + $output = []; if (preg_match($regex, $this->last_query, $output) > 0) { @@ -581,7 +581,7 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { * @param array $data * @return null|array */ - public function insert_batch($table, $data=array()) + public function insert_batch($table, $data=[]) { $first_row = current($data); if ( ! is_array($first_row)) @@ -590,7 +590,7 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { } // Values for insertion - $vals = array(); + $vals = []; foreach($data as $group) { $vals = array_merge($vals, array_values($group)); @@ -610,7 +610,7 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { // Append the placeholder groups to the query $sql .= implode(',', $param_list); - return array($sql, $vals); + return [$sql, $vals]; } // -------------------------------------------------------------------------- @@ -666,7 +666,7 @@ abstract class AbstractDriver extends \PDO implements DriverInterface { public function truncate($table) { $sql = ($this->has_truncate) - ? 'TRUNCATE ' + ? 'TRUNCATE TABLE ' : 'DELETE FROM '; $sql .= $this->quote_table($table); diff --git a/src/Query/AbstractQueryBuilder.php b/src/Query/AbstractQueryBuilder.php index 555df93..bcfa7b2 100644 --- a/src/Query/AbstractQueryBuilder.php +++ b/src/Query/AbstractQueryBuilder.php @@ -74,19 +74,19 @@ abstract class AbstractQueryBuilder { * Keys for insert/update statement * @var array */ - protected $set_array_keys = array(); + protected $set_array_keys = []; /** * Key/val pairs for order by clause * @var array */ - protected $order_array = array(); + protected $order_array = []; /** * Key/val pairs for group by clause * @var array */ - protected $group_array = array(); + protected $group_array = []; // -------------------------------------------------------------------------- // ! Other Class vars @@ -96,13 +96,13 @@ abstract class AbstractQueryBuilder { * Values to apply to prepared statements * @var array */ - protected $values = array(); + protected $values = []; /** * Values to apply to where clauses in prepared statements * @var array */ - protected $where_values = array(); + protected $where_values = []; /** * Value for limit string @@ -112,7 +112,7 @@ abstract class AbstractQueryBuilder { /** * Value for offset in limit string - * @var int + * @var integer */ protected $offset; @@ -129,7 +129,7 @@ abstract class AbstractQueryBuilder { * * @var array */ - protected $query_map = array(); + protected $query_map = []; /** * Map for having clause @@ -151,7 +151,7 @@ abstract class AbstractQueryBuilder { /** * Whether to do only an explain on the query - * @var bool + * @var boolean */ protected $explain; @@ -195,12 +195,12 @@ abstract class AbstractQueryBuilder { protected function _mixed_set(&$var, $key, $val=NULL, $val_type=self::BOTH) { $arg = (is_scalar($key) && is_scalar($val)) - ? array($key => $val) + ? [$key => $val] : $key; foreach($arg as $k => $v) { - if (in_array($val_type, array(self::KEY, self::VALUE))) + if (in_array($val_type, [self::KEY, self::VALUE])) { $var[] = ($val_type === self::KEY) ? $k @@ -313,7 +313,7 @@ abstract class AbstractQueryBuilder { * @param string $conj * @return Query_Builder */ - protected function _having($key, $val=array(), $conj='AND') + protected function _having($key, $val=[], $conj='AND') { $where = $this->_where($key, $val); @@ -330,10 +330,10 @@ abstract class AbstractQueryBuilder { $item .= (count($f_array) === 1) ? '=?' : " {$f_array[1]} ?"; // Put in the having map - $this->having_map[] = array( + $this->having_map[] = [ 'conjunction' => ( ! empty($this->having_map)) ? " {$conj} " : ' HAVING ', 'string' => $item - ); + ]; } return $this; @@ -348,9 +348,9 @@ abstract class AbstractQueryBuilder { * @param mixed $val * @return array */ - protected function _where($key, $val=array()) + protected function _where($key, $val=[]) { - $where = array(); + $where = []; $this->_mixed_set($where, $key, $val, self::BOTH); $this->_mixed_set($this->where_values, $key, $val, self::VALUE); return $where; @@ -366,7 +366,7 @@ abstract class AbstractQueryBuilder { * @param string $defaultConj * @return Query_Builder */ - protected function _where_string($key, $val=array(), $defaultConj='AND') + protected function _where_string($key, $val=[], $defaultConj='AND') { // Create key/value placeholders foreach($this->_where($key, $val) as $f => $val) @@ -413,7 +413,7 @@ abstract class AbstractQueryBuilder { * @param string $conj - The where in conjunction * @return Query_Builder */ - protected function _where_in($key, $val=array(), $in='IN', $conj='AND') + protected function _where_in($key, $val=[], $in='IN', $conj='AND') { $key = $this->db->quote_ident($key); $params = array_fill(0, count($val), '?'); @@ -484,11 +484,11 @@ abstract class AbstractQueryBuilder { */ protected function _append_map($conjunction = '', $string = '', $type = '') { - array_push($this->query_map, array( + array_push($this->query_map, [ 'type' => $type, 'conjunction' => $conjunction, 'string' => $string - )); + ]); } // -------------------------------------------------------------------------- @@ -503,7 +503,7 @@ abstract class AbstractQueryBuilder { */ protected function _append_query($vals, $sql, $total_time) { - $evals = (is_array($vals)) ? $vals : array(); + $evals = (is_array($vals)) ? $vals : []; $esql = str_replace('?', "%s", $sql); // Quote string values @@ -517,10 +517,10 @@ abstract class AbstractQueryBuilder { array_unshift($evals, $esql); // Add the interpreted query to the list of executed queries - $this->queries[] = array( + $this->queries[] = [ 'time' => $total_time, 'sql' => call_user_func_array('sprintf', $evals), - ); + ]; $this->queries['total_time'] += $total_time; @@ -584,12 +584,12 @@ abstract class AbstractQueryBuilder { // Get the base clause for the query $sql = $this->_compile_type($type, $this->db->quote_table($table)); - $clauses = array( + $clauses = [ 'query_map', 'group_string', 'order_string', 'having_map', - ); + ]; // Set each type of subclause foreach($clauses as $clause) diff --git a/src/Query/AbstractUtil.php b/src/Query/AbstractUtil.php index 5d07911..a6c9c68 100644 --- a/src/Query/AbstractUtil.php +++ b/src/Query/AbstractUtil.php @@ -65,7 +65,7 @@ abstract class AbstractUtil { * @param bool $if_not_exists * @return string */ - public function create_table($name, $fields, array $constraints=array(), $if_not_exists=TRUE) + public function create_table($name, $fields, array $constraints=[], $if_not_exists=TRUE) { $exists_str = ($if_not_exists) ? ' IF NOT EXISTS ' : ' '; @@ -75,13 +75,13 @@ abstract class AbstractUtil { // 'constraint' => ..., // 'index' => ..., // ) - $column_array = \array_zipper(array( + $column_array = \array_zipper([ 'type' => $fields, 'constraint' => $constraints - )); + ]); // Join column definitions together - $columns = array(); + $columns = []; foreach($column_array as $n => $props) { $str = $this->get_driver()->quote_ident($n); diff --git a/src/Query/BadDBDriverException.php b/src/Query/BadDBDriverException.php index 5355787..57d1fde 100644 --- a/src/Query/BadDBDriverException.php +++ b/src/Query/BadDBDriverException.php @@ -21,6 +21,7 @@ namespace Query; * @package Query * @subpackage Core */ -class BadDBDriverException extends \InvalidArgumentException {} +class BadDBDriverException extends \InvalidArgumentException { +} // End of BadDBDriverException.php \ No newline at end of file diff --git a/src/Query/ConnectionManager.php b/src/Query/ConnectionManager.php index a305179..ede48ee 100644 --- a/src/Query/ConnectionManager.php +++ b/src/Query/ConnectionManager.php @@ -28,13 +28,13 @@ final class ConnectionManager { * Map of named database connections * @var array */ - private $connections = array(); + private $connections = []; /** * Class instance variable - * @var Connection_Manager + * @var ConnectionManager */ - private static $instance = null; + private static $instance = NULL; // -------------------------------------------------------------------------- @@ -42,7 +42,9 @@ final class ConnectionManager { * Private constructor to prevent multiple instances * @codeCoverageIgnore */ - private function __construct() {} + private function __construct() + { + } // -------------------------------------------------------------------------- @@ -87,7 +89,7 @@ final class ConnectionManager { */ public static function get_instance() { - if (self::$instance === null) + if (self::$instance === NULL) { self::$instance = new self(); } @@ -185,7 +187,7 @@ final class ConnectionManager { } // Set additional PDO options - $options = array(); + $options = []; if (isset($params->options)) { @@ -201,13 +203,17 @@ final class ConnectionManager { { $dsn = $params->file; } + else if(strtolower($dbtype) === 'oci') + { + $dsn = "dbname=//{$params->host}:{$params->port}/{$params->database}"; + } else { $dsn = $this->create_dsn($dbtype, $params); } - return array($dsn, $dbtype, $params, $options); + return [$dsn, $dbtype, $params, $options]; } // -------------------------------------------------------------------------- @@ -226,14 +232,14 @@ final class ConnectionManager { $dbtype = 'firebird'; } - $pairs = array(); + $pairs = []; if ( ! empty($params->database)) { - $pairs[] = implode('=', array('dbname', $params->database)); + $pairs[] = implode('=', ['dbname', $params->database]); } - $skip = array( + $skip = [ 'name' => 'name', 'pass' => 'pass', 'user' => 'user', @@ -242,13 +248,13 @@ final class ConnectionManager { 'options' => 'options', 'database' => 'database', 'alias' => 'alias' - ); + ]; foreach($params as $key => $val) { if (( ! array_key_exists($key, $skip)) && ( ! empty($val))) { - $pairs[] = implode('=', array($key, $val)); + $pairs[] = implode('=', [$key, $val]); } } diff --git a/src/Query/DriverInterface.php b/src/Query/DriverInterface.php index c9ed803..086e0b9 100644 --- a/src/Query/DriverInterface.php +++ b/src/Query/DriverInterface.php @@ -31,7 +31,7 @@ interface DriverInterface { * @param string $password * @param array $driver_options */ - public function __construct($dsn, $username=NULL, $password=NULL, array $driver_options = array()); + public function __construct($dsn, $username=NULL, $password=NULL, array $driver_options = []); /** * Simplifies prepared statements for database queries @@ -268,6 +268,6 @@ interface DriverInterface { * @param array $data * @return array */ - public function insert_batch($table, $data=array()); + public function insert_batch($table, $data=[]); } // End of driver_interface.php \ No newline at end of file diff --git a/src/Query/Drivers/Firebird/Driver.php b/src/Query/Drivers/Firebird/Driver.php index 9e6b605..0f48d7d 100644 --- a/src/Query/Drivers/Firebird/Driver.php +++ b/src/Query/Drivers/Firebird/Driver.php @@ -64,7 +64,7 @@ class Driver extends \Query\AbstractDriver { /** * Firebird doesn't have the truncate keyword * - * @var bool + * @var boolean */ protected $has_truncate = FALSE; @@ -77,7 +77,7 @@ class Driver extends \Query\AbstractDriver { * @param array $options * @throws \PDOException */ - public function __construct($dbpath, $user='SYSDBA', $pass='masterkey', array $options = array()) + public function __construct($dbpath, $user='SYSDBA', $pass='masterkey', array $options = []) { $connect_function = (isset($options[\PDO::ATTR_PERSISTENT]) && $options[\PDO::ATTR_PERSISTENT]) ? '\\fbird_pconnect' @@ -217,7 +217,7 @@ class Driver extends \Query\AbstractDriver { * @return Result * @throws \PDOException */ - public function prepare($query, $options=array()) + public function prepare($query, $options=[]) { $this->statement_link = \fbird_prepare($this->conn, $query); @@ -335,7 +335,7 @@ class Driver extends \Query\AbstractDriver { $code = \fbird_errcode(); $msg = \fbird_errmsg(); - return array(0, $code, $msg); + return [0, $code, $msg]; } // -------------------------------------------------------------------------- @@ -375,7 +375,7 @@ class Driver extends \Query\AbstractDriver { * @param array $data * @return array */ - public function insert_batch($table, $data=array()) + public function insert_batch($table, $data=[]) { // Each member of the data array needs to be an array if ( ! is_array(current($data))) @@ -396,7 +396,7 @@ class Driver extends \Query\AbstractDriver { foreach($data as $item) { // Quote string values - $vals = array_map(array($this, 'quote'), $item); + $vals = array_map([$this, 'quote'], $item); // Add the values in the sql $sql .= $insert_template . implode(', ', $vals) . ");\n"; @@ -408,7 +408,7 @@ class Driver extends \Query\AbstractDriver { // Return a null array value so the query is run as it is, // not as a prepared statement, because a prepared statement // doesn't work for this type of query in Firebird. - return array($sql, NULL); + return [$sql, NULL]; } } // End of firebird_driver.php \ No newline at end of file diff --git a/src/Query/Drivers/Firebird/Result.php b/src/Query/Drivers/Firebird/Result.php index 3a86fb3..23b2928 100644 --- a/src/Query/Drivers/Firebird/Result.php +++ b/src/Query/Drivers/Firebird/Result.php @@ -34,7 +34,7 @@ class Result extends \PDOStatement { /** * Current row in result array * - * @var int + * @var integer */ private $row; @@ -43,7 +43,7 @@ class Result extends \PDOStatement { * * @param mixed */ - private $result = array(); + private $result = []; /** * Reference to the db drive to de-duplicate error functions @@ -68,7 +68,7 @@ class Result extends \PDOStatement { $this->statement = $link; $this->setFetchMode(\PDO::FETCH_ASSOC); $this->row = -1; - $this->result = array(); + $this->result = []; // Create the result array, so that we can get row counts // Check the resource type, because prepared statements are "interbase query" @@ -212,7 +212,7 @@ class Result extends \PDOStatement { */ public function fetchAll($fetch_style=\PDO::FETCH_ASSOC, $statement=NULL, $ctor_args=NULL) { - $all = array(); + $all = []; while($row = $this->fetch($fetch_style, $statement)) { @@ -247,7 +247,7 @@ class Result extends \PDOStatement { * @param array $ctor_args * @return stdClass */ - public function fetchObject($class_name='stdClass', $ctor_args=array()) + public function fetchObject($class_name='stdClass', $ctor_args=[]) { return $this->fetch(\PDO::FETCH_OBJ); } diff --git a/src/Query/Drivers/Firebird/Util.php b/src/Query/Drivers/Firebird/Util.php index b72ecc7..85e903c 100644 --- a/src/Query/Drivers/Firebird/Util.php +++ b/src/Query/Drivers/Firebird/Util.php @@ -33,7 +33,7 @@ class Util extends \Query\AbstractUtil { * @param bool $if_not_exists * @return string */ - public function create_table($name, $fields, array $constraints=array(), $if_not_exists=FALSE) + public function create_table($name, $fields, array $constraints=[], $if_not_exists=FALSE) { return parent::create_table($name, $fields, $constraints, FALSE); } @@ -73,7 +73,7 @@ class Util extends \Query\AbstractUtil { * @param bool $system_tables * @return string */ - public function backup_data($exclude=array(), $system_tables=FALSE) + public function backup_data($exclude=[], $system_tables=FALSE) { // Determine which tables to use $tables = $this->get_driver()->get_tables(); @@ -106,7 +106,7 @@ class Util extends \Query\AbstractUtil { // Nab the column names by getting the keys of the first row $columns = @array_keys($obj_res[0]); - $insert_rows = array(); + $insert_rows = []; // Create the insert statements foreach($obj_res as $row) @@ -116,7 +116,7 @@ class Util extends \Query\AbstractUtil { // Quote values as needed by type if(stripos($t, 'RDB$') === FALSE) { - $row = array_map(array($this->get_driver(), 'quote'), $row); + $row = array_map([$this->get_driver(), 'quote'], $row); $row = array_map('trim', $row); } diff --git a/src/Query/Drivers/Mysql/Driver.php b/src/Query/Drivers/Mysql/Driver.php index ab35620..1786d0d 100644 --- a/src/Query/Drivers/Mysql/Driver.php +++ b/src/Query/Drivers/Mysql/Driver.php @@ -39,14 +39,14 @@ class Driver extends \Query\AbstractDriver { * @param string $password * @param array $options */ - public function __construct($dsn, $username=null, $password=null, array $options=array()) + public function __construct($dsn, $username=NULL, $password=NULL, array $options=[]) { // Set the charset to UTF-8 if (defined('\\PDO::MYSQL_ATTR_INIT_COMMAND')) { - $options = array_merge($options, array( + $options = array_merge($options, [ \PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF-8 COLLATE 'UTF-8'", - )); + ]); } if (strpos($dsn, 'mysql') === FALSE) diff --git a/src/Query/Drivers/Mysql/Util.php b/src/Query/Drivers/Mysql/Util.php index 2c9cfd8..ce74441 100644 --- a/src/Query/Drivers/Mysql/Util.php +++ b/src/Query/Drivers/Mysql/Util.php @@ -30,7 +30,7 @@ class Util extends \Query\AbstractUtil { */ public function backup_structure() { - $string = array(); + $string = []; // Get databases $dbs = $this->get_driver()->get_dbs(); @@ -72,7 +72,7 @@ class Util extends \Query\AbstractUtil { * @param array $exclude * @return string */ - public function backup_data($exclude=array()) + public function backup_data($exclude=[]) { $tables = $this->get_driver()->get_tables(); @@ -100,7 +100,7 @@ class Util extends \Query\AbstractUtil { // Nab the column names by getting the keys of the first row $columns = @array_keys($rows[0]); - $insert_rows = array(); + $insert_rows = []; // Create the insert statements foreach($rows as $row) diff --git a/src/Query/Drivers/Pgsql/Driver.php b/src/Query/Drivers/Pgsql/Driver.php index ec9ed01..51c3a05 100644 --- a/src/Query/Drivers/Pgsql/Driver.php +++ b/src/Query/Drivers/Pgsql/Driver.php @@ -32,7 +32,7 @@ class Driver extends \Query\AbstractDriver { * @param string $password * @param array $options */ - public function __construct($dsn, $username=null, $password=null, array $options=array()) + public function __construct($dsn, $username=NULL, $password=NULL, array $options=[]) { if (strpos($dsn, 'pgsql') === FALSE) { @@ -70,16 +70,16 @@ SQL; */ public function get_fks($table) { - $value_map = array( + $value_map = [ 'c' => 'CASCADE', 'r' => 'RESTRICT', - ); + ]; $keys = parent::get_fks($table); foreach($keys as &$key) { - foreach(array('update', 'delete') AS $type) + foreach(['update', 'delete'] AS $type) { if ( ! isset($value_map[$key[$type]])) { diff --git a/src/Query/Drivers/Pgsql/Util.php b/src/Query/Drivers/Pgsql/Util.php index e5cc9f5..a569263 100644 --- a/src/Query/Drivers/Pgsql/Util.php +++ b/src/Query/Drivers/Pgsql/Util.php @@ -42,7 +42,7 @@ class Util extends \Query\AbstractUtil { * @param array $exclude * @return string */ - public function backup_data($exclude=array()) + public function backup_data($exclude=[]) { $tables = $this->get_driver()->get_tables(); @@ -72,7 +72,7 @@ class Util extends \Query\AbstractUtil { // Nab the column names by getting the keys of the first row $columns = @array_keys($obj_res[0]); - $insert_rows = array(); + $insert_rows = []; // Create the insert statements foreach($obj_res as $row) @@ -80,7 +80,7 @@ class Util extends \Query\AbstractUtil { $row = array_values($row); // Quote values as needed by type - $row = array_map(array($this->get_driver(), 'quote'), $row); + $row = array_map([$this->get_driver(), 'quote'], $row); $row = array_map('trim', $row); diff --git a/src/Query/Drivers/Sqlite/Driver.php b/src/Query/Drivers/Sqlite/Driver.php index 2cf276c..dd0a145 100644 --- a/src/Query/Drivers/Sqlite/Driver.php +++ b/src/Query/Drivers/Sqlite/Driver.php @@ -33,7 +33,7 @@ class Driver extends \Query\AbstractDriver { /** * SQLite has a truncate optimization, * but no support for the actual keyword - * @var bool + * @var boolean */ protected $has_truncate = FALSE; @@ -45,7 +45,7 @@ class Driver extends \Query\AbstractDriver { * @param string $pass * @param array $driver_options */ - public function __construct($dsn, $user=NULL, $pass=NULL, array $driver_options=array()) + public function __construct($dsn, $user=NULL, $pass=NULL, array $driver_options=[]) { if (strpos($dsn, 'sqlite:') === FALSE) { @@ -80,17 +80,17 @@ class Driver extends \Query\AbstractDriver { */ public function get_fks($table) { - $return_rows = array(); + $return_rows = []; foreach(parent::get_fks($table) as $row) { - $return_rows[] = array( + $return_rows[] = [ 'child_column' => $row['from'], 'parent_table' => $row['table'], 'parent_column' => $row['to'], 'update' => $row['on_update'], 'delete' => $row['on_delete'] - ); + ]; } return $return_rows; @@ -106,7 +106,7 @@ class Driver extends \Query\AbstractDriver { * @param array $data * @return string */ - public function insert_batch($table, $data=array()) + public function insert_batch($table, $data=[]) { // If greater than version 3.7.11, supports the same syntax as // MySQL and Postgres @@ -131,7 +131,7 @@ class Driver extends \Query\AbstractDriver { // Create a key-value mapping for each field $first = array_shift($data); - $cols = array(); + $cols = []; foreach($first as $colname => $datum) { $cols[] = $this->_quote($datum) . ' AS ' . $this->quote_ident($colname); @@ -140,11 +140,11 @@ class Driver extends \Query\AbstractDriver { foreach($data as $union) { - $vals = array_map(array($this, 'quote'), $union); + $vals = array_map([$this, 'quote'], $union); $sql .= "UNION SELECT " . implode(',', $vals) . "\n"; } - return array($sql, NULL); + return [$sql, NULL]; } } //End of sqlite_driver.php \ No newline at end of file diff --git a/src/Query/Drivers/Sqlite/SQL.php b/src/Query/Drivers/Sqlite/SQL.php index ee1dd9d..7fff6d7 100644 --- a/src/Query/Drivers/Sqlite/SQL.php +++ b/src/Query/Drivers/Sqlite/SQL.php @@ -85,7 +85,7 @@ SQL; */ public function system_table_list() { - return array('sqlite_master', 'sqlite_temp_master', 'sqlite_sequence'); + return ['sqlite_master', 'sqlite_temp_master', 'sqlite_sequence']; } // -------------------------------------------------------------------------- @@ -159,7 +159,7 @@ SQL; */ public function type_list() { - return array('INTEGER', 'REAL', 'TEXT', 'BLOB'); + return ['INTEGER', 'REAL', 'TEXT', 'BLOB']; } // -------------------------------------------------------------------------- diff --git a/src/Query/Drivers/Sqlite/Util.php b/src/Query/Drivers/Sqlite/Util.php index 65a80d3..b6174a2 100644 --- a/src/Query/Drivers/Sqlite/Util.php +++ b/src/Query/Drivers/Sqlite/Util.php @@ -31,7 +31,7 @@ class Util extends \Query\AbstractUtil { * @param array $excluded * @return string */ - public function backup_data($excluded=array()) + public function backup_data($excluded=[]) { // Get a list of all the objects $sql = 'SELECT DISTINCT "name" @@ -68,7 +68,7 @@ class Util extends \Query\AbstractUtil { // Nab the column names by getting the keys of the first row $columns = array_keys(current($obj_res)); - $insert_rows = array(); + $insert_rows = []; // Create the insert statements foreach($obj_res as $row) @@ -110,7 +110,7 @@ class Util extends \Query\AbstractUtil { $res = $this->get_driver()->query($sql); $result = $res->fetchAll(\PDO::FETCH_ASSOC); - $sql_array = array(); + $sql_array = []; foreach($result as $r) { diff --git a/src/Query/QueryBuilder.php b/src/Query/QueryBuilder.php index 0b0e3b1..171e758 100644 --- a/src/Query/QueryBuilder.php +++ b/src/Query/QueryBuilder.php @@ -24,14 +24,14 @@ namespace Query; * @package Query * @subpackage Query_Builder */ -class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface { +class QueryBuilder extends AbstractQueryBuilder /*implements QueryBuilderInterface*/ { /** * String class values to be reset * * @var array */ - private $string_vars = array( + private $string_vars = [ 'select_string', 'from_string', 'set_string', @@ -40,14 +40,14 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface 'limit', 'offset', 'explain', - ); + ]; /** * Array class variables to be reset * * @var array */ - private $array_vars = array( + private $array_vars = [ 'set_array_keys', 'order_array', 'group_array', @@ -55,7 +55,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface 'where_values', 'query_map', 'having_map' - ); + ]; // -------------------------------------------------------------------------- // ! Methods @@ -106,13 +106,13 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface // Allow camel-case method calls $snake_name = \from_camel_case($name); - foreach(array($this, $this->db) as $object) + foreach([$this, $this->db] as $object) { - foreach(array($name, $snake_name) as $method_name) + foreach([$name, $snake_name] as $method_name) { if (method_exists($object, $method_name)) { - return call_user_func_array(array($object, $method_name), $params); + return call_user_func_array([$object, $method_name], $params); } } @@ -356,7 +356,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param mixed $val * @return QueryBuilder */ - public function having($key, $val=array()) + public function having($key, $val=[]) { return $this->_having($key, $val, 'AND'); } @@ -370,7 +370,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param mixed $val * @return QueryBuilder */ - public function or_having($key, $val=array()) + public function or_having($key, $val=[]) { return $this->_having($key, $val, 'OR'); } @@ -389,7 +389,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param mixed $escape * @return QueryBuilder */ - public function where($key, $val=array(), $escape=NULL) + public function where($key, $val=[], $escape=NULL) { return $this->_where_string($key, $val, 'AND'); } @@ -403,7 +403,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param mixed $val * @return QueryBuilder */ - public function or_where($key, $val=array()) + public function or_where($key, $val=[]) { return $this->_where_string($key, $val, 'OR'); } @@ -417,7 +417,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param mixed $val * @return QueryBuilder */ - public function where_in($field, $val=array()) + public function where_in($field, $val=[]) { return $this->_where_in($field, $val); } @@ -431,7 +431,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param mixed $val * @return QueryBuilder */ - public function or_where_in($field, $val=array()) + public function or_where_in($field, $val=[]) { return $this->_where_in($field, $val, 'IN', 'OR'); } @@ -445,7 +445,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param mixed $val * @return QueryBuilder */ - public function where_not_in($field, $val=array()) + public function where_not_in($field, $val=[]) { return $this->_where_in($field, $val, 'NOT IN', 'AND'); } @@ -459,7 +459,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param mixed $val * @return QueryBuilder */ - public function or_where_not_in($field, $val=array()) + public function or_where_not_in($field, $val=[]) { return $this->_where_in($field, $val, 'NOT IN', 'OR'); } @@ -482,7 +482,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface // Use the keys of the array to make the insert/update string // Escape the field names - $this->set_array_keys = array_map(array($this->db, '_quote'), $this->set_array_keys); + $this->set_array_keys = array_map([$this->db, '_quote'], $this->set_array_keys); // Generate the "set" string $this->set_string = implode('=?,', $this->set_array_keys); @@ -530,7 +530,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface { if ( ! is_scalar($field)) { - $new_group_array = array_map(array($this->db, 'quote_ident'), $field); + $new_group_array = array_map([$this->db, 'quote_ident'], $field); $this->group_array = array_merge($this->group_array, $new_group_array); } else @@ -566,7 +566,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface $field = $this->db->quote_ident($field); $this->order_array[$field] = $type; - $order_clauses = array(); + $order_clauses = []; // Flatten key/val pairs into an array of space-separated pairs foreach($this->order_array as $k => $v) @@ -702,7 +702,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param int|bool $offset * @return \PDOStatement */ - public function get_where($table, $where=array(), $limit=FALSE, $offset=FALSE) + public function get_where($table, $where=[], $limit=FALSE, $offset=FALSE) { // Create the where clause $this->where($where); @@ -758,7 +758,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param mixed $data * @return \PDOStatement */ - public function insert($table, $data=array()) + public function insert($table, $data=[]) { if ( ! empty($data)) { @@ -777,7 +777,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param array $data * @return \PDOStatement */ - public function insert_batch($table, $data=array()) + public function insert_batch($table, $data=[]) { // Get the generated values and sql string list($sql, $data) = $this->db->insert_batch($table, $data); @@ -796,7 +796,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface * @param mixed $data * @return \PDOStatement */ - public function update($table, $data=array()) + public function update($table, $data=[]) { if ( ! empty($data)) { @@ -913,7 +913,7 @@ class QueryBuilder extends AbstractQueryBuilder implements QueryBuilderInterface // Reset arrays foreach($this->array_vars as $var) { - $this->$var = array(); + $this->$var = []; } } } diff --git a/src/Query/QueryBuilderInterface.php b/src/Query/QueryBuilderInterface.php index ab0d58c..cb1cee7 100644 --- a/src/Query/QueryBuilderInterface.php +++ b/src/Query/QueryBuilderInterface.php @@ -31,7 +31,7 @@ interface QueryBuilderInterface { * Specifies rows to select in a query * * @param string $fields - * @return QueryBuilder + * @return QueryBuilderInterface */ public function select($fields); @@ -42,7 +42,7 @@ interface QueryBuilderInterface { * * @param string $field * @param string|bool $as - * @return QueryBuilder + * @return QueryBuilderInterface */ public function select_max($field, $as=FALSE); @@ -53,7 +53,7 @@ interface QueryBuilderInterface { * * @param string $field * @param string|bool $as - * @return QueryBuilder + * @return QueryBuilderInterface */ public function select_min($field, $as=FALSE); @@ -64,7 +64,7 @@ interface QueryBuilderInterface { * * @param string $field * @param string|bool $as - * @return QueryBuilder + * @return QueryBuilderInterface */ public function select_avg($field, $as=FALSE); @@ -75,7 +75,7 @@ interface QueryBuilderInterface { * * @param string $field * @param string|bool $as - * @return QueryBuilder + * @return QueryBuilderInterface */ public function select_sum($field, $as=FALSE); @@ -84,7 +84,7 @@ interface QueryBuilderInterface { /** * Adds the 'distinct' keyword to a query * - * @return QueryBuilder + * @return QueryBuilderInterface */ public function distinct(); @@ -93,7 +93,7 @@ interface QueryBuilderInterface { /** * Shows the query plan for the query * - * @return QueryBuilder + * @return QueryBuilderInterface */ public function explain(); @@ -103,7 +103,7 @@ interface QueryBuilderInterface { * Specify the database table to select from * * @param string $tblname - * @return QueryBuilder + * @return QueryBuilderInterface */ public function from($tblname); @@ -117,7 +117,7 @@ interface QueryBuilderInterface { * @param string $field * @param mixed $val * @param string $pos - * @return QueryBuilder + * @return QueryBuilderInterface */ public function like($field, $val, $pos='both'); @@ -129,7 +129,7 @@ interface QueryBuilderInterface { * @param string $field * @param mixed $val * @param string $pos - * @return QueryBuilder + * @return QueryBuilderInterface */ public function or_like($field, $val, $pos='both'); @@ -141,7 +141,7 @@ interface QueryBuilderInterface { * @param string $field * @param mixed $val * @param string $pos - * @return QueryBuilder + * @return QueryBuilderInterface */ public function not_like($field, $val, $pos='both'); @@ -153,7 +153,7 @@ interface QueryBuilderInterface { * @param string $field * @param mixed $val * @param string $pos - * @return QueryBuilder + * @return QueryBuilderInterface */ public function or_not_like($field, $val, $pos='both'); @@ -166,9 +166,9 @@ interface QueryBuilderInterface { * * @param mixed $key * @param mixed $val - * @return QueryBuilder + * @return QueryBuilderInterface */ - public function having($key, $val=array()); + public function having($key, $val=[]); // -------------------------------------------------------------------------- @@ -177,9 +177,9 @@ interface QueryBuilderInterface { * * @param mixed $key * @param mixed $val - * @return QueryBuilder + * @return QueryBuilderInterface */ - public function or_having($key, $val=array()); + public function or_having($key, $val=[]); // -------------------------------------------------------------------------- // ! 'Where' methods @@ -193,9 +193,9 @@ interface QueryBuilderInterface { * @param mixed $key * @param mixed $val * @param bool $escape - * @return QueryBuilder + * @return QueryBuilderInterface */ - public function where($key, $val=array(), $escape = NULL); + public function where($key, $val=[], $escape = NULL); // -------------------------------------------------------------------------- @@ -204,9 +204,9 @@ interface QueryBuilderInterface { * * @param string $key * @param mixed $val - * @return QueryBuilder + * @return QueryBuilderInterface */ - public function or_where($key, $val=array()); + public function or_where($key, $val=[]); // -------------------------------------------------------------------------- @@ -215,9 +215,9 @@ interface QueryBuilderInterface { * * @param mixed $field * @param mixed $val - * @return QueryBuilder + * @return QueryBuilderInterface */ - public function where_in($field, $val=array()); + public function where_in($field, $val=[]); // -------------------------------------------------------------------------- @@ -226,9 +226,9 @@ interface QueryBuilderInterface { * * @param string $field * @param mixed $val - * @return QueryBuilder + * @return QueryBuilderInterface */ - public function or_where_in($field, $val=array()); + public function or_where_in($field, $val=[]); // -------------------------------------------------------------------------- @@ -237,9 +237,9 @@ interface QueryBuilderInterface { * * @param string $field * @param mixed $val - * @return QueryBuilder + * @return QueryBuilderInterface */ - public function where_not_in($field, $val=array()); + public function where_not_in($field, $val=[]); // -------------------------------------------------------------------------- @@ -248,9 +248,9 @@ interface QueryBuilderInterface { * * @param string $field * @param mixed $val - * @return QueryBuilder + * @return QueryBuilderInterface */ - public function or_where_not_in($field, $val=array()); + public function or_where_not_in($field, $val=[]); // -------------------------------------------------------------------------- // ! Other Query Modifier methods @@ -261,7 +261,7 @@ interface QueryBuilderInterface { * * @param mixed $key * @param mixed $val - * @return QueryBuilder + * @return QueryBuilderInterface */ public function set($key, $val = NULL); @@ -273,7 +273,7 @@ interface QueryBuilderInterface { * @param string $table * @param string $condition * @param string $type - * @return QueryBuilder + * @return QueryBuilderInterface */ public function join($table, $condition, $type=''); @@ -283,7 +283,7 @@ interface QueryBuilderInterface { * Group the results by the selected field(s) * * @param mixed $field - * @return QueryBuilder + * @return QueryBuilderInterface */ public function group_by($field); @@ -294,7 +294,7 @@ interface QueryBuilderInterface { * * @param string $field * @param string $type - * @return QueryBuilder + * @return QueryBuilderInterface */ public function order_by($field, $type=""); @@ -305,7 +305,7 @@ interface QueryBuilderInterface { * * @param int $limit * @param int|bool $offset - * @return QueryBuilder + * @return QueryBuilderInterface */ public function limit($limit, $offset=FALSE); @@ -316,17 +316,27 @@ interface QueryBuilderInterface { /** * Adds a paren to the current query for query grouping * - * @return QueryBuilder + * @return QueryBuilderInterface */ public function group_start(); // -------------------------------------------------------------------------- + /** + * Adds a paren to the current query for query grouping, + * prefixed with 'NOT' + * + * @return QueryBuilderInterface + */ + public function not_group_start(); + + // -------------------------------------------------------------------------- + /** * Adds a paren to the current query for query grouping, * prefixed with 'OR' * - * @return QueryBuilder + * @return QueryBuilderInterface */ public function or_group_start(); @@ -336,7 +346,7 @@ interface QueryBuilderInterface { * Adds a paren to the current query for query grouping, * prefixed with 'OR NOT' * - * @return QueryBuilder + * @return QueryBuilderInterface */ public function or_not_group_start(); @@ -345,7 +355,7 @@ interface QueryBuilderInterface { /** * Ends a query group * - * @return QueryBuilder + * @return QueryBuilderInterface */ public function group_end(); @@ -375,7 +385,7 @@ interface QueryBuilderInterface { * @param int|bool $offset * @return \PDOStatement */ - public function get_where($table, $where=array(), $limit=FALSE, $offset=FALSE); + public function get_where($table, $where=[], $limit=FALSE, $offset=FALSE); // -------------------------------------------------------------------------- @@ -394,9 +404,10 @@ interface QueryBuilderInterface { * in place of the get() method * * @param string $table + * @param bool $reset - Whether to keep the query after counting the results * @return int */ - public function count_all_results($table=''); + public function count_all_results($table='', $reset=TRUE); // -------------------------------------------------------------------------- @@ -407,7 +418,7 @@ interface QueryBuilderInterface { * @param mixed $data * @return \PDOStatement */ - public function insert($table, $data=array()); + public function insert($table, $data=[]); // -------------------------------------------------------------------------- @@ -418,7 +429,18 @@ interface QueryBuilderInterface { * @param array $data * @return \PDOStatement|null */ - public function insert_batch($table, $data=array()); + public function insert_batch($table, $data=[]); + + // -------------------------------------------------------------------------- + + /** + * Insertion with automatic overwrite, rather than attempted duplication + * + * @param string $table + * @param array $data + * @return \PDOStatement|null + */ + public function replace($table, $data=[]); // -------------------------------------------------------------------------- @@ -429,7 +451,20 @@ interface QueryBuilderInterface { * @param mixed $data * @return \PDOStatement */ - public function update($table, $data=array()); + public function update($table, $data=[]); + + // -------------------------------------------------------------------------- + + /** + * Creates a batch update, and executes it. + * Returns the number of affected rows + * + * @param string $table + * @param array|object $data + * @param string $where + * @return int + */ + public function update_batch($table, $data, $where); // -------------------------------------------------------------------------- @@ -500,4 +535,4 @@ interface QueryBuilderInterface { public function reset_query(); } -// End of QueryBuilder_interface.php +// End of QueryBuilderInterface.php diff --git a/src/Query/QueryParser.php b/src/Query/QueryParser.php index bcc3c58..9d0d028 100644 --- a/src/Query/QueryParser.php +++ b/src/Query/QueryParser.php @@ -35,23 +35,23 @@ class QueryParser { * * @var array */ - private $match_patterns = array( + private $match_patterns = [ 'function' => '([a-zA-Z0-9_]+\((.*?)\))', 'identifier' => '([a-zA-Z0-9_-]+\.?)+', 'operator' => '=|AND|&&?|~|\|\|?|\^|/|>=?|<=?|-|%|OR|\+|NOT|\!=?|<>|XOR' - ); + ]; /** * Regex matches * * @var array */ - public $matches = array( - 'functions' => array(), - 'identifiers' => array(), - 'operators' => array(), - 'combined' => array(), - ); + public $matches = [ + 'functions' => [], + 'identifiers' => [], + 'operators' => [], + 'combined' => [], + ]; /** * Constructor/entry point into parser @@ -83,7 +83,7 @@ class QueryParser { preg_match_all($full_pattern, $sql, $this->matches['combined'], PREG_SET_ORDER); // Go through the matches, and get the most relevant matches - $this->matches = array_map(array($this, 'filter_array'), $this->matches); + $this->matches = array_map([$this, 'filter_array'], $this->matches); return $this->matches; } @@ -123,7 +123,7 @@ class QueryParser { */ protected function filter_array($array) { - $new_array = array(); + $new_array = []; foreach($array as $row) {