├── .gitignore ├── README.md └── upload └── system └── library └── db └── querybuilder ├── common ├── conditions.php ├── limit.php ├── order.php └── schemaanalyzer.php ├── operations ├── aggregates.php ├── delete.php ├── insert.php ├── join.php ├── select.php └── update.php ├── query.php ├── querybuilder.php └── support └── autoloader_for_oc_1x.php /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything 2 | * 3 | upload/system/storage/* 4 | 5 | # But not these files... 6 | !.gitignore 7 | !upload/system/library/db/querybuilder/* 8 | 9 | # ...even if they are in subdirectories 10 | !* 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | - [Compatibility](#compatibility) 2 | - [Installation](#installation) 3 | - [General Info](#general) 4 | - [Selecting data](#select) 5 | - [Where conditions](#where) 6 | - [Limit conditions](#limit) 7 | - [Ordering results](#order) 8 | - [Joins](#join) 9 | - [First, last, and random conditions](#first-last-random) 10 | - [Inserting data](#insert) 11 | - [Updating data](#update) 12 | - [Deleting data](#delete) 13 | - [Conditions](#conditions) 14 | - [DB Logger](#logger) 15 | 16 | 17 | # opencart-query-builder 18 | Opencart Query Builder provides convenient interface to work with database. It is totally fast and secure. 19 | 20 | Features: 21 | - super simple interface (inspired by modern frameworks: laravel, yii, codeigniter...) 22 | - no more tons of `$this->db->escape('...')`, builder automaticaly makes secure sql 23 | - no more table prefixes, just table names 24 | - doesn't break your code (`$this->db->query()` and other default functions still work) 25 | - easy debug functionality 26 | 27 | Let see how it looks: 28 | 29 | ```php 30 | // somewhere above in controller 31 | $db = $this->db; 32 | 33 | // Take exact what you need: 34 | $email = $db->table('customer')->find(1)->get('email'); 35 | 36 | // How to set minimal price for your products? Easy: 37 | $db->table('product')->where('price <', 100)->set('price', 100); 38 | 39 | // Happy customer bought three products at a time? Don't forget to mark it: 40 | $db->table('product')->find(1)->decrement('quantity', 3); 41 | ``` 42 | 43 | Like it? More interesting features and code examples you will find bellow. 44 | 45 | ## Compatibility 46 | Compatible with OpenCart 1.*, OpenCart 2.* and OpenCart 3.* 47 | 48 | Tested only with: MySql, MariaDB 49 | 50 | 51 | ## Installation 52 | Upload the contents of the 'upload' folder to the root directory of your OpenCart installation. 53 | 54 | To start using QueryBuilder, we need tell our Registry to use it instead of our old DB class. To do it, after: 55 | ```php 56 | $registry->set('db', ...); 57 | ``` 58 | write this: 59 | ```php 60 | // QueryBuilder 61 | $registry->set('db', new DB\QueryBuilder\QueryBuilder($registry->get('db'))); 62 | ``` 63 | 64 | OpenCart 2.2.* or higher: 65 | 66 | ![alt text](https://askello.github.io/opencart-query-builder/installation-new.jpg) 67 | 68 | 69 | OpenCart 2.0.0 - 2.1.0.2: 70 | 71 | ![alt text](https://askello.github.io/opencart-query-builder/installation-old.jpg) 72 | 73 | OpenCart 1.* (first versions of OpenCart also need autoloader): 74 | 75 | ![alt text](https://askello.github.io/opencart-query-builder/installation-v1.jpg) 76 | 77 | 78 | ## General Info 79 | After installation, your old `$this->db` class has new method - `table`. Method `table` returns a fluent query builder instance for the given table, which allows you to chain more constraints onto the query and then run other commands to work with your data. 80 | ```php 81 | // somewhere in controller 82 | $db = $this->db; 83 | 84 | // Retriving instance of query working with oc_product table. 85 | $query = $db->table('product'); 86 | ``` 87 | Note that there is no need to prefix your table names with DB_PREFIX, query builder will do it automatically. 88 | 89 | If your query would work with two or more tables, usually you must use table prefixes for your fields: 90 | ```php 91 | // retrive products models and names (where few products left) 92 | $products = $db->table('product') 93 | ->join('product_description', 'product_id') 94 | ->where('product.quantity < ', 10) 95 | ->get(['product.model', 'product_description.name']); 96 | ``` 97 | To write less code, you always can add your own aliases for each table: 98 | ```php 99 | // Add alias `p` to `oc_product` table 100 | $products = $db->table('product p') 101 | ->join('product_description pd', 'product_id') 102 | ->where('p.quantity', 10); 103 | ->get(['p.model', 'pd.name']); 104 | ``` 105 | Also you could use `AS` keyword if you like (case insensitive): 106 | ```php 107 | $query = $db->table('product as p')->...; 108 | $query = $db->table('product AS p')->...; 109 | ``` 110 | 111 | 112 | ## Selecting data from DB 113 | Retrieving data from database can be done by `get` method. 114 | 115 | Select all data from a table: 116 | ```php 117 | // SELECT * FROM `oc_product` 118 | $products = $db->table('product')->get(); 119 | ``` 120 | Select only specific fields: 121 | ```php 122 | // SELECT `product_id`,`model` FROM `oc_product` 123 | $products = $db->table('product')->get(['product_id', 'model']); 124 | ``` 125 | Get fields as aliases: 126 | ```php 127 | // SELECT `product_id` AS `id` FROM `oc_product` 128 | $products = $db->table('product')->get(['product_id' => 'id']); 129 | ``` 130 | Select content of the specific field: 131 | ```php 132 | $name = $db->table('customer')->find(1)->get('firstname'); 133 | // $name => 'John'; 134 | ``` 135 | If database returns more than one row, result will be array of values: 136 | ```php 137 | $names = $db->table('customer')->get('firstname'); 138 | // $names => array('John', 'Leo', 'Michael', ...); 139 | ``` 140 | Check if record with specific primary key exists: 141 | ```php 142 | if ( $db->table('product')->has($id) ) { 143 | ... 144 | } else { 145 | exit('There is no product with id ' . $id . '!'); 146 | } 147 | ``` 148 | Aggregates: 149 | ```php 150 | $cnt = $db->table('product')->count(); 151 | 152 | $min = $db->table('product')->min('price'); 153 | 154 | $max = $db->table('product')->max('price'); 155 | 156 | $avg = $db->table('product')->avg('price'); 157 | 158 | $sum = $db->table('product')->sum('price'); 159 | ``` 160 | 161 | 162 | ## Where conditions 163 | You may use the `where` method on a query builder instance to add where clauses to the query. The most basic call to `where` requires two arguments. The first argument is the name of the column. Also after column name may be added condition operator. The second argument is the value to evaluate against the column. 164 | where(string field, mixed value) 165 | ```php 166 | // ... WHERE `product_id` = 1 ... 167 | $query->where('product_id', 1); 168 | 169 | // ... WHERE `price` > 200 ... 170 | $query->where('price >', 200); 171 | 172 | // ... WHERE `product_id` IN (1,2,3) ... 173 | $query->where('product_id', [1, 2, 3]); 174 | 175 | // ... WHERE `product_id` NOT IN (1,2,3) ... 176 | $query->where('product_id !=', [1, 2, 3]); 177 | 178 | // ... WHERE `name` IS NULL ... 179 | $query->where('name', null); 180 | 181 | // ... WHERE `ean` IS NOT NULL ... 182 | $query->where('ean !=', null); 183 | ``` 184 | If you wish to add multiple conditions, you are free to call `where` method a few times. All conditions will be divided by `AND` keyword: 185 | ```php 186 | // ... WHERE `firstname` = 'John' AND `lastname` = 'Dou' 187 | $query->where('firstname', 'John')->where('lastname', 'Dou'); 188 | ``` 189 | If you need to split your conditions by `OR` keyword, you may use `orWhere` method: 190 | ```php 191 | // ... WHERE `firstname` = 'John' OR `firstname` = 'Leo' 192 | $query->where('firstname', 'John')->orWhere('firstname', 'Leo'); 193 | ``` 194 | where(string rawSql) 195 | ```php 196 | // ... WHERE price BETWEN 100 AND 200 ... 197 | $query->where('price BETWEN 100 AND 200'); 198 | ``` 199 | where(array conditions) 200 | ```php 201 | // ... WHERE `price` = 100 ... 202 | $query->where(['price' => 100]); 203 | 204 | // ... WHERE (`firstname` = 'John' AND `age` > 20) 205 | $query->where([ 206 | 'firstname' => 'John', 207 | 'age >' => 20 208 | ]); 209 | ``` 210 | Use `OR` operator: 211 | ```php 212 | // ... WHERE (`firstname` = 'John' OR `age` > 20) 213 | $query->where([ 214 | 'firstname' => 'John', 215 | 'or', 216 | 'age >' => 20 217 | ]); 218 | ``` 219 | Find result by its primary key: 220 | ```php 221 | // ... WHERE `primary_key_field` = 1 ... 222 | $query->find(1); 223 | 224 | // ... WHERE `primary_key_field` IN (1,2,3) ... 225 | $query->find([1,2,3]); 226 | ``` 227 | 228 | 229 | ## Limit conditions 230 | To limit the number of results returned from the query, you may use `limit` method. 231 | ```php 232 | // ... LIMIT 10 ... 233 | $query->limit(10); 234 | ``` 235 | Also query builder provides `skip` and `page` methods for simle navigation through database records: 236 | ```php 237 | // ... LIMIT 5, 10 ... 238 | $query->limit(10)->skip(5); 239 | 240 | // ... LIMIT 20, 10 ... 241 | $query->limit(10)->page(3); 242 | ``` 243 | 244 | 245 | ## Ordering results 246 | ```php 247 | // ... ORDER BY `price` ... 248 | $query->sortBy('price'); 249 | 250 | // ... ORDER BY `price` DESC ... 251 | $query->sortBy('price', 'desc'); 252 | 253 | // ... ORDER BY `price` ASC, model DESC ... 254 | $query->sortBy([ 255 | 'price' => 'asc', 256 | 'model' => 'desc' 257 | ]); 258 | ``` 259 | Also it is possible to use raw expressions: 260 | ```php 261 | // ... ORDER BY RAND() ... 262 | $query->sortBy('RAND()'); 263 | ``` 264 | But note that example above has more convenient solution by using `random()` method. 265 | 266 | 267 | ## Joins 268 | `join`, `crossJoin`: 269 | ```php 270 | // ... INNER JOIN `oc_product_description` ... 271 | $db->table('product')->join('product_description'); 272 | 273 | // ... CROSS JOIN `oc_product_description` ... 274 | $db->table('product')->crossJoin('product_description'); 275 | ``` 276 | Other `join` variants: 277 | ```php 278 | // ... INNER JOIN `oc_manufacturer` USING(`manufacturer_id`) 279 | $db->table('product')->join('manufacturer', 'manufacturer_id'); 280 | 281 | // ... INNER JOIN `oc_manufacturer` AS `m` ON `p`.`manufacturer_id` = `m`.`manufacturer_id` 282 | $db->table('product p')->join('manufacturer m', 'p.manufacturer_id', 'm.manufacturer_id'); 283 | 284 | // ... INNER JOIN `oc_product_description` AS `pd` ON (p.product_id = pd.product_id AND `pd`.`language_id` = 1) 285 | $db->table('product p')->join('product_description pd', [ 286 | 'p.product_id = pd.product_id', 287 | 'pd.language_id' => 1 288 | ]); 289 | ``` 290 | Also there are `leftJoin` and `rightJoin` methods, which accept same type of input conditions. For example: 291 | ```php 292 | // ... LEFT OUTER JOIN `oc_manufacturer` AS `m` ON `p`.`manufacturer_id` = `m`.`manufacturer_id` 293 | $db->table('product p')->leftJoin('manufacturer m', 'p.manufacturer_id', 'm.manufacturer_id'); 294 | 295 | // ... RIGHT OUTER JOIN `oc_manufacturer` AS `m` ON `p`.`manufacturer_id` = `m`.`manufacturer_id` 296 | $db->table('product p')->rightJoin('manufacturer m', 'p.manufacturer_id', 'm.manufacturer_id'); 297 | ``` 298 | 299 | 300 | ## First, last, and random conditions 301 | Query Builder also provides `first`, `last` and `random` methods for easiest way to work with data in database. These methods have one optional parameter - limit of results. By default limit equals 1. 302 | ```php 303 | $query->first(); 304 | 305 | $query->first(10); 306 | 307 | $query->last(); 308 | 309 | $query->last(10); 310 | 311 | $query->random(); 312 | 313 | $query->random(10,.."'"); 314 | 315 | // Example (get email of last registered customer) 316 | $email = $db->table('customer')->last()->get('email'); 317 | ``` 318 | 319 | 320 | ## Inserting data 321 | To insert data into database use `add` method: 322 | ```php 323 | $id = $db->table('product')->add([ 324 | 'model' => 'm1', 325 | 'price' => 100, 326 | ... 327 | ]); 328 | ``` 329 | Insert multiple records: 330 | ```php 331 | $ids = $db->table('product')->add([ 332 | [ 333 | 'model' => 'm1', 334 | 'price' => 100, 335 | ... 336 | ], [ 337 | 'model' => 'm2', 338 | 'price' => 620, 339 | ... 340 | ], 341 | ... 342 | ]); 343 | ``` 344 | 345 | 346 | ## Updating data 347 | To update field in database use `set` method: 348 | ```php 349 | $db->table('product')->set('price', 200); 350 | 351 | $db->table('product')->find(1)->set('price', 200); 352 | ``` 353 | Update multiple fields: 354 | ```php 355 | $db->table('product')->find(1)->set([ 356 | 'model' => 'm2', 357 | 'price' => 200, 358 | ... 359 | ]); 360 | ``` 361 | The query builder also provides convenient methods for incrementing or decrementing the value of a given column: 362 | ```php 363 | $db->table('customer')->increment('followers'); 364 | 365 | $db->table('customer')->increment('followers', 3); 366 | 367 | $db->table('customer')->decrement('followers'); 368 | 369 | $db->table('customer')->decrement('followers', 3); 370 | ``` 371 | Also there is a `toggle` method for switching boolean values: 372 | ```php 373 | $db->table('product')->toggle('status'); 374 | ``` 375 | Notice, all methods above (`set`, `increment`, `decrement` and `toggle`) return count of updated rows: 376 | ```php 377 | $countUpdated = $db->table('product')->where('price <', 100)->set('status', 0); 378 | ``` 379 | 380 | 381 | ## Deleting data 382 | To delete records from database use `delete` method: 383 | ```php 384 | $db->table('product')->delete(); 385 | 386 | $db->table('product')->find(1)->delete(); 387 | ``` 388 | If you wish to truncate the entire table, which will remove all rows and reset the auto-incrementing ID to zero, you may use the `clear` method: 389 | ```php 390 | $db->table('product')->clear(); 391 | ``` 392 | Notice, `delete` and `clear` methods also return count of deleted rows: 393 | ```php 394 | $countDeleted = $db->table('product')->where('price <', 100)->delete(); 395 | ``` 396 | 397 | 398 | ## DB Logger 399 | Query builder provides some methods for debugging: 400 | ```php 401 | // Enable logger (by default it's disabled) 402 | $db->enableLog(); 403 | 404 | // Available methods 405 | $queries = $db->getExecutedQueries(); 406 | 407 | $db->printExecutedQueries(); 408 | ``` 409 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/common/conditions.php: -------------------------------------------------------------------------------- 1 | createWhereSql($args); 13 | 14 | $this->appendCondition($sql); 15 | 16 | return $this; 17 | } 18 | 19 | public function orWhere($conditions) { 20 | $args = func_get_args(); 21 | 22 | $sql = $this->createWhereSql($args); 23 | 24 | $this->appendCondition($sql, "OR"); 25 | 26 | return $this; 27 | } 28 | 29 | private function createWhereSql($args) { 30 | if (count($args) > 1) { 31 | $sql = $this->parseSingleCondition($args[0], $args[1]); 32 | } else if (is_array($args[0])) { 33 | $sql = $this->parseConditions($args[0]); 34 | } else { 35 | $sql = $args[0]; 36 | } 37 | 38 | return $sql; 39 | } 40 | 41 | public function find($keys) { 42 | if (!is_array($keys)) { 43 | $this->limit(1); 44 | } 45 | 46 | $this->where($this->getPrimaryKey(), $keys); 47 | 48 | return $this; 49 | } 50 | 51 | public function first($limit = 1) { 52 | $this->limit($limit); 53 | 54 | if ($this->_order() == "") { 55 | $this->sortBy($this->getPrimaryKey()); 56 | } 57 | 58 | return $this; 59 | } 60 | 61 | public function last($limit = 1) { 62 | $this->limit($limit); 63 | 64 | if ($this->_order() == "") { 65 | $this->sortBy($this->getPrimaryKey(), "DESC"); 66 | } else { 67 | $this->sortViceVersa(); 68 | } 69 | 70 | return $this; 71 | } 72 | 73 | public function random($limit = 1) { 74 | $this->limit($limit); 75 | 76 | $this->sortBy("RAND()"); 77 | 78 | return $this; 79 | } 80 | 81 | private function parseSingleCondition($field, $value) { 82 | $field = trim($field); 83 | 84 | $operator = $this->determineOperator($field, $value); 85 | $field = $this->getConditionField($field); 86 | $value = $this->parseConditionValue($value); 87 | 88 | return $field . " " . $operator . " " . $value; 89 | } 90 | 91 | private function getConditionField($field) { 92 | $data = explode(' ', $field, 2); 93 | return $this->_field($data[0]); 94 | } 95 | 96 | private function parseConditionValue($value) { 97 | if (is_int($value) or is_float($value)) { 98 | return $value; 99 | } 100 | 101 | if (is_array($value)) { 102 | $values = array(); 103 | 104 | foreach ($value as $val) { 105 | if (is_int($val) or is_float($val)) { 106 | $values[] = $val; 107 | } else { 108 | $values[] = "'" . $this->db->escape($val) . "'"; 109 | } 110 | } 111 | 112 | return "(" . implode(",", $values) . ")"; 113 | } 114 | 115 | if (is_null($value)) { 116 | return "NULL"; 117 | } 118 | 119 | return "'" . $this->db->escape($value) . "'"; 120 | } 121 | 122 | private function determineOperator($field, $value) { 123 | $operator = "="; 124 | 125 | if (strpos($field, ' ') !== false) { 126 | $data = explode(' ', $field, 2); 127 | $operator = trim($data[1]); 128 | } 129 | 130 | if (is_array($value)) { 131 | if ($operator == "!=") { 132 | return "NOT IN"; 133 | } else { 134 | return "IN"; 135 | } 136 | } 137 | 138 | if (is_null($value)) { 139 | if ($operator == "!=") { 140 | return "IS NOT"; 141 | } else { 142 | return "IS"; 143 | } 144 | } 145 | 146 | return $operator; 147 | } 148 | 149 | private function parseConditions($conditions) { 150 | $sql = ""; 151 | 152 | $delimiter = ""; 153 | 154 | foreach ($conditions as $field => $value) { 155 | if (is_int($field)) { 156 | if (trim(strtoupper($value)) == "OR") { 157 | $delimiter = " OR "; 158 | continue; 159 | } 160 | 161 | if (is_string($value)) { 162 | $sql .= $delimiter . $value; 163 | } 164 | } else { 165 | $sql .= $delimiter . $this->parseSingleCondition($field, $value); 166 | } 167 | 168 | $delimiter = " AND "; 169 | } 170 | 171 | if (count($conditions) > 1) { 172 | $sql = "(" . $sql . ")"; 173 | } 174 | 175 | return $sql; 176 | } 177 | 178 | private function appendCondition($condition, $operator = "AND") { 179 | if (!$this->conditions_sql and $condition) { 180 | $this->conditions_sql = PHP_EOL . "WHERE " . $condition; 181 | } else { 182 | $this->conditions_sql .= " " . $operator . " " . $condition; 183 | } 184 | } 185 | 186 | private function _where() { 187 | return $this->conditions_sql; 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/common/limit.php: -------------------------------------------------------------------------------- 1 | limitCount = intval($count); 12 | 13 | return $this; 14 | } 15 | 16 | public function skip($count) { 17 | $this->limitOffset = intval($count); 18 | 19 | return $this; 20 | } 21 | 22 | public function page($page) { 23 | $page = intval($page); 24 | $page = $page > 0 ? $page : 1; 25 | 26 | $this->limitOffset = ($page - 1) * $this->limitCount; 27 | 28 | return $this; 29 | } 30 | 31 | public function _limit() { 32 | if ($this->limitCount && $this->limitOffset) { 33 | return PHP_EOL . "LIMIT " . $this->limitOffset . "," . $this->limitCount; 34 | } 35 | 36 | if ($this->limitCount && !$this->limitOffset) { 37 | return PHP_EOL . "LIMIT " . $this->limitCount; 38 | } 39 | 40 | return ""; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/common/order.php: -------------------------------------------------------------------------------- 1 | $order) { 12 | $this->sortBy($field_name, $order); 13 | } 14 | } else { 15 | if ($this->isRawSql($field)) { 16 | $this->sortFields[] = $field; 17 | } else { 18 | $this->sortFields[$field] = $order; 19 | } 20 | } 21 | 22 | return $this; 23 | } 24 | 25 | private function sortOrder($order) { 26 | $order = strtoupper($order); 27 | 28 | if ($order != "DESC") { 29 | $order = "ASC"; 30 | } 31 | 32 | return $order; 33 | } 34 | 35 | private function sortViceVersa() { 36 | foreach (array_keys($this->sortFields) as $sort_field) { 37 | if (!is_int($sort_field)) { 38 | $sortOrder = $this->sortOrder($this->sortFields[$sort_field]) == "ASC" ? "DESC" : "ASC"; 39 | $this->sortBy($sort_field, $sortOrder); 40 | } 41 | } 42 | } 43 | 44 | private function _order() { 45 | if ($this->sortFields) { 46 | $fields = array(); 47 | 48 | foreach ($this->sortFields as $field => $order) { 49 | if (is_int($field)) { // if raw sql 50 | $fields[] = $order; 51 | } else { 52 | $fields[] = $this->_field($field) . " " . $this->sortOrder($order); 53 | } 54 | } 55 | 56 | return PHP_EOL . "ORDER BY " . implode(", ", $fields); 57 | } 58 | 59 | return ""; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/common/schemaanalyzer.php: -------------------------------------------------------------------------------- 1 | primaryKeys[$table])) { 12 | return $this->primaryKeys[$table]; 13 | } 14 | 15 | $result = $this->execute("SHOW KEYS FROM " . $this->_table($table) . " WHERE Key_name = 'PRIMARY'"); 16 | 17 | return $result->row['Column_name']; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/operations/aggregates.php: -------------------------------------------------------------------------------- 1 | selectAggregate("COUNT(*)"); 9 | } 10 | 11 | public function max($field) { 12 | return $this->selectAggregate("MAX(" . $this->_field($field) . ")"); 13 | } 14 | 15 | public function min($field) { 16 | return $this->selectAggregate("MIN(" . $this->_field($field) . ")"); 17 | } 18 | 19 | public function avg($field) { 20 | return $this->selectAggregate("AVG(" . $this->_field($field) . ")"); 21 | } 22 | 23 | public function sum($field) { 24 | return $this->selectAggregate("SUM(" . $this->_field($field) . ")"); 25 | } 26 | 27 | private function selectAggregate($aggregate) { 28 | $sql = "SELECT" . PHP_EOL . " " . $aggregate . " AS total" . PHP_EOL . "FROM " . $this->_tableAsAlias() . $this->_joins() . $this->_where(); 29 | $rows = $this->execute($sql)->rows; 30 | return $rows[0]['total']; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/operations/delete.php: -------------------------------------------------------------------------------- 1 | limit($limit); 10 | } 11 | 12 | $sql = "DELETE FROM " . $this->_table() . $this->_where() . $this->_order() . $this->_limit(); 13 | 14 | $this->execute($sql); 15 | 16 | return $this->db->countAffected(); 17 | } 18 | 19 | public function clear() { 20 | $this->execute("TRUNCATE TABLE " . $this->_table()); 21 | 22 | return $this->db->countAffected(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/operations/insert.php: -------------------------------------------------------------------------------- 1 | isArrayAssoc($data); 9 | 10 | if (!$isMultiple) $data = [$data]; 11 | 12 | $ids = $this->_insert($data); 13 | 14 | if ($isMultiple) return $ids; 15 | 16 | return $ids[0]; 17 | } 18 | 19 | private function _insert($data) { 20 | // prepare fields 21 | $fields = array_keys($data[0]); 22 | foreach ($fields as &$field) { 23 | $field = $this->_field($field); 24 | } 25 | $fields = implode(',', $fields); 26 | 27 | // prepare values 28 | $values = []; 29 | foreach ($data as $row) { 30 | $sql = PHP_EOL . " ("; 31 | 32 | $v = []; 33 | foreach($row as $key => $value) { 34 | $v[] = $this->_value($value); 35 | } 36 | $sql .= implode(',', $v); 37 | 38 | $sql .= ")"; 39 | 40 | $values[] = $sql; 41 | } 42 | 43 | $values = implode(',', $values); 44 | 45 | $this->execute("INSERT INTO " . $this->_table() . PHP_EOL . " (" . $fields . ")" . PHP_EOL . "VALUES" . $values); 46 | 47 | $lastId = $this->db->insertId(); 48 | 49 | return range($lastId, $lastId + count($data) - 1); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/operations/join.php: -------------------------------------------------------------------------------- 1 | addTable($table); 11 | 12 | $this->joins[] = $this->createJoinSql("INNER JOIN", $table, $key1, $key2); 13 | 14 | return $this; 15 | } 16 | 17 | public function leftJoin($table, $key1, $key2 = null) { 18 | $table = $this->addTable($table); 19 | 20 | $this->joins[] = $this->createJoinSql("LEFT OUTER JOIN", $table, $key1, $key2); 21 | 22 | return $this; 23 | } 24 | 25 | public function rightJoin($table, $key1, $key2 = null) { 26 | $table = $this->addTable($table); 27 | 28 | $this->joins[] = $this->createJoinSql("RIGHT OUTER JOIN", $table, $key1, $key2); 29 | 30 | return $this; 31 | } 32 | 33 | public function crossJoin($table) { 34 | $table = $this->addTable($table); 35 | 36 | $this->joins[] = $this->createJoinSql("CROSS JOIN", $table); 37 | 38 | return $this; 39 | } 40 | 41 | private function createJoinSql($type, $table, $key1 = null, $key2 = null) { 42 | return $type . " " . $this->_tableAsAlias($table) . $this->parseJoinConditions($key1, $key2); 43 | } 44 | 45 | private function parseJoinConditions($key1, $key2) { 46 | if (is_string($key1) and is_null($key2)) { 47 | if (strpos($key1, '.') !== false) { 48 | return " ON " . $key1; 49 | } else { 50 | return " USING (`" . $this->db->escape($key1) . "`)"; 51 | } 52 | } 53 | 54 | if (is_string($key1) and is_string($key2)) { 55 | return " ON " . $this->_field($key1) . " = " . $this->_field($key2); 56 | } 57 | 58 | if (is_array($key1)) { 59 | return " ON " . $this->parseConditions($key1); 60 | } 61 | 62 | return ""; 63 | } 64 | 65 | private function _joins() { 66 | if ($this->joins) { 67 | return PHP_EOL . implode(PHP_EOL, $this->joins); 68 | } else { 69 | return ""; 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/operations/select.php: -------------------------------------------------------------------------------- 1 | prepareFieldsToSelect($fields); 12 | 13 | $sql = "SELECT" . PHP_EOL . " " . $fields_sql . PHP_EOL . "FROM " . $this->_tableAsAlias() . $this->_joins() . $this->_where() . $this->_order() . $this->_limit(); 14 | 15 | $rows = $this->execute($sql)->rows; 16 | 17 | // return value 18 | if (is_string($fields)) { 19 | return $this->getFieldValue($this->getFieldName($fields), $rows); 20 | } 21 | 22 | // return rows 23 | if ($this->single()) { 24 | return isset($rows[0]) ? $rows[0] : []; 25 | } else { 26 | return $rows; 27 | } 28 | } 29 | 30 | public function has($id) { 31 | return (boolean)$this->find($id)->count(); 32 | } 33 | 34 | private function getFieldValue($field, $rows) { 35 | if ($this->single()) { 36 | return isset($rows[0][$field]) ? $rows[0][$field] : null; 37 | } else { 38 | $values = array(); 39 | 40 | foreach ($rows as $row) { 41 | $values[] = isset($row[$field]) ? $row[$field] : null; 42 | } 43 | 44 | return $values; 45 | } 46 | } 47 | 48 | private function getFieldName($field_sql) { 49 | if (strpos($field_sql, '.') !== false) { 50 | $field_sql = explode('.', $field_sql)[1]; 51 | } 52 | 53 | $parts = explode(' ', $field_sql); 54 | 55 | return end($parts); 56 | } 57 | 58 | private function single() { 59 | return $this->limitCount == 1; 60 | } 61 | 62 | private function prepareFieldsToSelect($fields) { 63 | $fields_sql = "*"; 64 | 65 | if (is_array($fields)) { 66 | $tmp = array(); 67 | 68 | foreach ($fields as $field => $alias) { 69 | if (is_int($field)) { 70 | $tmp[] = $this->_field($alias); 71 | } else { 72 | $tmp[] = $this->_field($field) . " AS `" . $alias . "`"; 73 | } 74 | } 75 | 76 | $fields_sql = implode("," . PHP_EOL . " ", $tmp); 77 | } else if (is_string($fields)) { 78 | $fields_sql = $this->_field($fields); 79 | } 80 | 81 | return $fields_sql; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/operations/update.php: -------------------------------------------------------------------------------- 1 | $value) { 14 | $fields[] = $this->fieldToValue($field, $value); 15 | } 16 | 17 | $fields_sql = implode(',' . PHP_EOL . ' ', $fields); 18 | } else { 19 | $fields_sql = $this->fieldToValue($field, $value); 20 | } 21 | 22 | return $this->_update($fields_sql); 23 | } 24 | 25 | public function increment($field, $count = 1) { 26 | $fields_sql = $this->_field($field) . "=(" . $this->_field($field) . " + " . (int)$count . ")"; 27 | 28 | return $this->_update($fields_sql); 29 | } 30 | 31 | public function decrement($field, $count = 1) { 32 | $fields_sql = $this->_field($field) . "=(" . $this->_field($field) . " - " . (int)$count . ")"; 33 | 34 | return $this->_update($fields_sql); 35 | } 36 | 37 | public function toggle($field) { 38 | $fields_sql = $this->_field($field) . "=(NOT " . $this->_field($field) . ")"; 39 | 40 | return $this->_update($fields_sql); 41 | } 42 | 43 | private function _update($fields_sql) { 44 | $sql = "UPDATE" . PHP_EOL . " " . $this->_table() . PHP_EOL . "SET" . PHP_EOL . " " . $fields_sql . $this->_where(); 45 | 46 | $this->execute($sql); 47 | 48 | return $this->db->countAffected(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/query.php: -------------------------------------------------------------------------------- 1 | db = $db; 24 | 25 | $table = $this->addTable($table); 26 | 27 | $this->setTable($table); 28 | } 29 | 30 | public function setTable($table) { 31 | $this->table = $this->db->escape($table); 32 | } 33 | 34 | public function addTable($table) { 35 | $table = trim($table); 36 | $table = preg_replace('/ {2,}/', ' ', $table); 37 | 38 | $tmp = explode(' ', $table); 39 | 40 | $table = DB_PREFIX . $tmp[0]; 41 | 42 | if(count($tmp) == 1) { 43 | $alias = $table; 44 | } else if(count($tmp) == 2) { 45 | $alias = $tmp[1]; 46 | } else if(count($tmp) == 3 and strtolower($tmp[1]) == 'as') { 47 | $alias = $tmp[2]; 48 | } 49 | 50 | $this->tableAliases[$table] = $alias; 51 | 52 | return $table; 53 | } 54 | 55 | private function _table($table = null) { 56 | if (is_null($table)) { 57 | $table = $this->table; 58 | } 59 | 60 | return "`" . $table . "`"; 61 | } 62 | 63 | private function _tableAlias($table = null) { 64 | if (is_null($table)) { 65 | $table = $this->table; 66 | } 67 | 68 | if (isset($this->tableAliases[$table])) { 69 | $alias = $this->tableAliases[$table]; 70 | } else { 71 | $alias = $table; 72 | } 73 | 74 | return "`" . $alias . "`"; 75 | } 76 | 77 | private function _tableAsAlias($table = null) { 78 | $alias = $this->_tableAlias($table); 79 | $table = $this->_table($table); 80 | 81 | if ($table != $alias) { 82 | return $table . " AS " . $alias; 83 | } 84 | 85 | return $table; 86 | } 87 | 88 | private function _field($field) { 89 | if ($this->isRawSql($field)) { 90 | return $field; 91 | } 92 | 93 | if (strpos($field, '.') !== false) { 94 | $tmp = explode('.', $field); 95 | $field = $tmp[1] == '*' ? '*' : "`" . $tmp[1] . "`"; 96 | return $this->_tableAlias($tmp[0]) . "." . $field; 97 | } 98 | 99 | if (count($this->tableAliases) > 1) { 100 | return $this->_tableAlias() . ".`" . $this->db->escape($field) . "`"; 101 | } else { 102 | return "`" . $this->db->escape($field) . "`"; 103 | } 104 | } 105 | 106 | private function fieldToValue($field, $operator, $value = null) { 107 | if (is_null($value)) { 108 | $value = $operator; 109 | $operator = "="; 110 | } 111 | 112 | return $this->_field($field) . $operator . $this->_value($value); 113 | } 114 | 115 | private function _value($value) { 116 | if (is_null($value)) return 'NULL'; 117 | 118 | return "'" . $this->db->escape($value) . "'"; 119 | } 120 | 121 | private function isRawSql($str) { 122 | return preg_match('/[()<>=`\'\ +*\-\/"]/', $str); 123 | } 124 | 125 | private function isArrayAssoc($arr) { 126 | if (array() === $arr) return false; 127 | return array_keys($arr) !== range(0, count($arr) - 1); 128 | } 129 | 130 | private function execute($sql) { 131 | return $this->db->query($sql); 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/querybuilder.php: -------------------------------------------------------------------------------- 1 | db = $db; 13 | } 14 | 15 | public function table($table) { 16 | return new Query($this, $table); 17 | } 18 | 19 | public function enableLog() { 20 | $this->logEnabled = true; 21 | } 22 | 23 | public function getExecutedQueries() { 24 | return $this->log; 25 | } 26 | 27 | public function printExecutedQueries() { 28 | foreach($this->log as $sql) { 29 | echo '
'.$sql.'
'; 30 | } 31 | } 32 | 33 | 34 | /* Overwriten functions */ 35 | 36 | public function query($sql) { 37 | if($this->logEnabled) { 38 | $this->log[] = $sql; 39 | } 40 | 41 | return $this->db->query($sql); 42 | } 43 | 44 | public function escape($value) { 45 | return $this->db->escape($value); 46 | } 47 | 48 | public function countAffected() { 49 | return $this->db->countAffected(); 50 | } 51 | 52 | public function insertId() { 53 | return $this->db->getLastId(); 54 | } 55 | 56 | public function getLastId() { 57 | return $this->db->getLastId(); 58 | } 59 | 60 | public function connected() { 61 | return $this->db->connected(); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /upload/system/library/db/querybuilder/support/autoloader_for_oc_1x.php: -------------------------------------------------------------------------------- 1 |