supernova-ws /
SuperNova
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Class DbQueryConstructor |
||
| 5 | * |
||
| 6 | * @method DbQueryConstructor fields(mixed $value, int $mergeStrategy = HelperArray::MERGE_PHP) |
||
| 7 | * @method DbQueryConstructor join(mixed $value, int $mergeStrategy = HelperArray::MERGE_PHP) |
||
| 8 | * @method DbQueryConstructor where(array $value, int $mergeStrategy = HelperArray::MERGE_PHP) |
||
| 9 | * @method DbQueryConstructor groupBy(array $value, int $mergeStrategy = HelperArray::MERGE_PHP) |
||
| 10 | * @method DbQueryConstructor orderBy(array $value, int $mergeStrategy = HelperArray::MERGE_PHP) |
||
| 11 | * @method DbQueryConstructor having(mixed $value, int $mergeStrategy = HelperArray::MERGE_PHP) |
||
| 12 | * @method DbQueryConstructor setFetchOne(bool $fetchOne = true) |
||
| 13 | * @method DbQueryConstructor setForUpdate(bool $forUpdate = true) |
||
| 14 | * @method DbQueryConstructor setSkipLock(bool $skipLock = true) |
||
| 15 | * |
||
| 16 | */ |
||
| 17 | class DbQueryConstructor extends DbSqlAware { |
||
| 18 | |||
| 19 | const SELECT = 'SELECT'; |
||
| 20 | const INSERT = 'INSERT'; |
||
| 21 | const UPDATE = 'UPDATE'; |
||
| 22 | const DELETE = 'DELETE'; |
||
| 23 | const REPLACE = 'REPLACE'; |
||
| 24 | |||
| 25 | protected static $allowedOperations = array( |
||
| 26 | self::SELECT, |
||
| 27 | ); |
||
| 28 | |||
| 29 | /** |
||
| 30 | * List of array properties names that should be merged on each call of setter |
||
| 31 | * |
||
| 32 | * @var string[] $propListArrayMerge |
||
| 33 | */ |
||
| 34 | protected static $propListArrayMerge = array('fields', 'join', 'where', 'groupBy', 'orderBy', 'having'); |
||
| 35 | /** |
||
| 36 | * List of setters that will simple set property with default value TRUE |
||
| 37 | * |
||
| 38 | * @var string[] $propListSetDefaultTrue |
||
| 39 | */ |
||
| 40 | protected static $propListSetDefaultTrue = array('setFetchOne', 'setForUpdate', 'setSkipLock'); |
||
| 41 | |||
| 42 | public $operation = ''; |
||
| 43 | |||
| 44 | public $table = ''; |
||
| 45 | public $alias = ''; |
||
| 46 | |||
| 47 | public $idField = ''; |
||
| 48 | |||
| 49 | /** |
||
| 50 | * @var array |
||
| 51 | */ |
||
| 52 | public $fields = array(); |
||
| 53 | |||
| 54 | public $join = array(); |
||
| 55 | |||
| 56 | public $where = array(); |
||
| 57 | public $groupBy = array(); |
||
| 58 | public $orderBy = array(); |
||
| 59 | public $having = array(); |
||
| 60 | |||
| 61 | public $limit = 0; |
||
| 62 | public $offset = 0; |
||
| 63 | |||
| 64 | public $fetchOne = false; |
||
| 65 | public $forUpdate = false; |
||
| 66 | public $skipLock = false; |
||
| 67 | |||
| 68 | public $variables = array(); |
||
| 69 | |||
| 70 | protected $_compiledQuery = array(); |
||
| 71 | |||
| 72 | /** |
||
| 73 | * @param string $fieldName |
||
| 74 | * |
||
| 75 | * @return $this |
||
| 76 | */ |
||
| 77 | 2 | public function setIdField($fieldName) { |
|
| 78 | 2 | $this->idField = $fieldName; |
|
| 79 | |||
| 80 | 2 | return $this; |
|
| 81 | } |
||
| 82 | |||
| 83 | /** |
||
| 84 | * Sets internal variables |
||
| 85 | * |
||
| 86 | * @param array $values |
||
| 87 | * |
||
| 88 | * @return $this |
||
| 89 | */ |
||
| 90 | public function variables($values) { |
||
| 91 | $this->variables = $values; |
||
| 92 | |||
| 93 | return $this; |
||
| 94 | } |
||
| 95 | |||
| 96 | |||
| 97 | /** |
||
| 98 | * @param string $alias |
||
| 99 | * |
||
| 100 | * @return $this |
||
| 101 | */ |
||
| 102 | 1 | public function setAlias($alias) { |
|
| 103 | 1 | $this->alias = $alias; |
|
| 104 | |||
| 105 | 1 | return $this; |
|
| 106 | } |
||
| 107 | |||
| 108 | /** |
||
| 109 | * @return $this |
||
| 110 | */ |
||
| 111 | 3 | public function select() { |
|
| 112 | 3 | $this->operation = DbQueryConstructor::SELECT; |
|
| 113 | // if (empty($this->fields) && $initFields) { |
||
| 114 | // $this->fields = array('*'); |
||
| 115 | // } |
||
| 116 | |||
| 117 | 3 | return $this; |
|
| 118 | } |
||
| 119 | |||
| 120 | |||
| 121 | /** |
||
| 122 | * @param string $tableName |
||
| 123 | * @param string $alias |
||
| 124 | * |
||
| 125 | * @return $this |
||
| 126 | */ |
||
| 127 | 2 | public function from($tableName, $alias = '') { |
|
| 128 | 2 | $this->table = $tableName; |
|
| 129 | 2 | $this->setAlias($alias); |
|
| 130 | |||
| 131 | 2 | return $this; |
|
| 132 | } |
||
| 133 | |||
| 134 | /** |
||
| 135 | * @param mixed ... |
||
| 136 | * |
||
| 137 | * @return $this |
||
| 138 | */ |
||
| 139 | 1 | public function field() { |
|
| 140 | 1 | $arguments = func_get_args(); |
|
| 141 | |||
| 142 | // Special case - call method with array of fields |
||
| 143 | 1 | if (count($arguments) == 1 && is_array($arguments[0])) { |
|
| 144 | $arguments = array_shift($arguments); |
||
| 145 | } |
||
| 146 | |||
| 147 | 1 | foreach ($arguments as $arg) { |
|
| 148 | 1 | $this->fields[] = $arg; |
|
| 149 | 1 | } |
|
| 150 | |||
| 151 | 1 | return $this; |
|
| 152 | } |
||
| 153 | |||
| 154 | public function fieldLiteral($field = '0', $alias = DbSqlLiteral::SQL_LITERAL_ALIAS_NONE) { |
||
| 155 | return $this->field(DbSqlLiteral::build($this->db)->literal($field)); |
||
| 156 | } |
||
| 157 | |||
| 158 | public function fieldSingleFunction($functionName, $field = '*', $alias = DbSqlLiteral::SQL_LITERAL_ALIAS_NONE) { |
||
| 159 | return $this->field(DbSqlLiteral::build($this->db)->buildSingleArgument($functionName, $field, $alias)); |
||
| 160 | } |
||
| 161 | |||
| 162 | public function fieldCount($field = '*', $alias = DbSqlLiteral::SQL_LITERAL_ALIAS_NONE) { |
||
| 163 | return $this->field(DbSqlLiteral::build($this->db)->count($field, $alias)); |
||
| 164 | } |
||
| 165 | |||
| 166 | public function fieldIsNull($field = '*', $alias = DbSqlLiteral::SQL_LITERAL_ALIAS_NONE) { |
||
| 167 | return $this->field(DbSqlLiteral::build($this->db)->isNull($field, $alias)); |
||
| 168 | } |
||
| 169 | |||
| 170 | public function fieldMax($field = '*', $alias = DbSqlLiteral::SQL_LITERAL_ALIAS_NONE) { |
||
| 171 | return $this->field(DbSqlLiteral::build($this->db)->max($field, $alias)); |
||
| 172 | } |
||
| 173 | |||
| 174 | /** |
||
| 175 | * @param string $name |
||
| 176 | * @param mixed[] $arguments |
||
| 177 | * |
||
| 178 | * @return $this |
||
| 179 | */ |
||
| 180 | 4 | public function __call($name, $arguments) { |
|
| 181 | 4 | if (in_array($name, self::$propListArrayMerge)) { |
|
| 182 | // array_unshift($arguments, ''); |
||
| 183 | // $arguments[0] = &$this->$name; |
||
| 184 | // call_user_func_array('HelperArray::merge', $arguments); |
||
| 185 | 3 | HelperArray::merge($this->$name, $arguments[0], HelperArray::keyExistsOr($arguments, 1, HelperArray::MERGE_PHP)); |
|
| 186 | 4 | } elseif (in_array($name, self::$propListSetDefaultTrue)) { |
|
| 187 | 2 | $varName = lcfirst(substr($name, 3)); |
|
| 188 | 2 | if (!array_key_exists(0, $arguments)) { |
|
| 189 | 2 | $arguments[0] = true; |
|
| 190 | 2 | } |
|
| 191 | 2 | $this->$varName = $arguments[0]; |
|
| 192 | 2 | } |
|
| 193 | // TODO - make all setters protected ?? |
||
| 194 | // elseif(method_exists($this, $name)) { |
||
| 195 | // call_user_func_array(array($this, $name), $arguments); |
||
| 196 | // } |
||
| 197 | |||
| 198 | 4 | return $this; |
|
| 199 | } |
||
| 200 | |||
| 201 | /** |
||
| 202 | * @param int $limit |
||
| 203 | * |
||
| 204 | * @return $this |
||
| 205 | */ |
||
| 206 | 2 | public function limit($limit) { |
|
| 207 | 2 | $this->limit = is_numeric($limit) ? $limit : 0; |
|
| 208 | |||
| 209 | 2 | return $this; |
|
| 210 | } |
||
| 211 | |||
| 212 | /** |
||
| 213 | * @param int $offset |
||
| 214 | * |
||
| 215 | * @return $this |
||
| 216 | */ |
||
| 217 | 2 | public function offset($offset) { |
|
| 218 | 2 | $this->offset = is_numeric($offset) ? $offset : 0; |
|
| 219 | |||
| 220 | 2 | return $this; |
|
| 221 | } |
||
| 222 | |||
| 223 | /** |
||
| 224 | * @param string $className |
||
| 225 | * |
||
| 226 | * @return $this |
||
| 227 | */ |
||
| 228 | // TODO - rewrite |
||
| 229 | 2 | public function getParamsFromStaticClass($className) { |
|
| 230 | 2 | if (is_string($className) && $className && class_exists($className)) { |
|
| 231 | 2 | if(method_exists($className, 'getDb')) { |
|
| 232 | 2 | $this->setDb($className::getDb()); |
|
| 233 | 2 | } |
|
| 234 | 2 | $this->from($className::$_table); |
|
| 235 | 2 | $this->setIdField($className::$_idField); |
|
| 236 | 2 | } |
|
| 237 | |||
| 238 | 2 | return $this; |
|
| 239 | } |
||
| 240 | |||
| 241 | /** |
||
| 242 | * @param db_mysql|null $db |
||
| 243 | * @param string|object|DBStaticRecord|DbSqlAware $className |
||
| 244 | * |
||
| 245 | * @return static |
||
| 246 | */ |
||
| 247 | 1 | public static function build($db = null, $className = '') { |
|
| 248 | /** |
||
| 249 | * @var static $result |
||
| 250 | */ |
||
| 251 | 1 | $result = parent::build(null); |
|
| 252 | 1 | $result->getParamsFromStaticClass($className); |
|
| 253 | |||
| 254 | 1 | return $result; |
|
| 255 | } |
||
| 256 | |||
| 257 | /** |
||
| 258 | * Resets statement |
||
| 259 | * |
||
| 260 | * @param bool $full |
||
| 261 | * |
||
| 262 | * @return static |
||
| 263 | */ |
||
| 264 | 1 | protected function _reset($full = true) { |
|
| 265 | 1 | if ($full) { |
|
| 266 | 1 | $this->operation = ''; |
|
| 267 | 1 | $this->table = ''; |
|
| 268 | 1 | $this->alias = ''; |
|
| 269 | 1 | $this->idField = ''; |
|
| 270 | 1 | } |
|
| 271 | |||
| 272 | 1 | $this->fields = array(); |
|
| 273 | 1 | $this->where = array(); |
|
| 274 | 1 | $this->groupBy = array(); |
|
| 275 | 1 | $this->orderBy = array(); |
|
| 276 | 1 | $this->having = array(); |
|
| 277 | |||
| 278 | 1 | $this->limit = 0; |
|
| 279 | 1 | $this->offset = 0; |
|
| 280 | |||
| 281 | 1 | $this->fetchOne = false; |
|
| 282 | 1 | $this->forUpdate = false; |
|
| 283 | 1 | $this->skipLock = false; |
|
| 284 | |||
| 285 | 1 | return $this; |
|
| 286 | } |
||
| 287 | |||
| 288 | |||
| 289 | /** |
||
| 290 | * @param array $array |
||
| 291 | * |
||
| 292 | * @return array |
||
| 293 | */ |
||
| 294 | protected function arrayEscape(&$array) { |
||
| 295 | $result = array(); |
||
| 296 | foreach ($array as $key => &$value) { |
||
| 297 | $result[$key] = $this->escapeString($value); |
||
| 298 | } |
||
| 299 | |||
| 300 | return $result; |
||
| 301 | } |
||
| 302 | |||
| 303 | protected function compileOperation() { |
||
| 304 | if (empty($this->operation)) { |
||
| 305 | throw new ExceptionDbOperationEmpty(); |
||
| 306 | } |
||
| 307 | |||
| 308 | if (!in_array($this->operation, self::$allowedOperations)) { |
||
| 309 | throw new ExceptionDbOperationRestricted(); |
||
| 310 | } |
||
| 311 | |||
| 312 | $this->_compiledQuery[] = $this->escapeString($this->operation); |
||
| 313 | } |
||
| 314 | |||
| 315 | protected function compileSubject() { |
||
| 316 | $this->_compiledQuery[] = $this->selectFieldsToString($this->fields); |
||
| 317 | } |
||
| 318 | |||
| 319 | protected function compileFrom() { |
||
| 320 | $this->_compiledQuery[] = 'FROM `{{' . $this->escapeString($this->table) . '}}`'; |
||
| 321 | if (!empty($this->alias)) { |
||
| 322 | $this->_compiledQuery[] = 'AS `' . $this->escapeString($this->alias) . '`'; |
||
| 323 | } |
||
| 324 | } |
||
| 325 | |||
| 326 | protected function compileJoin() { |
||
| 327 | !empty($this->join) ? $this->_compiledQuery[] = implode(' ', $this->join) : false; |
||
| 328 | } |
||
| 329 | |||
| 330 | protected function compileWhere() { |
||
| 331 | // TODO - fields should be escaped !! |
||
| 332 | !empty($this->where) ? $this->_compiledQuery[] = 'WHERE ' . implode(' AND ', $this->where) : false; |
||
| 333 | } |
||
| 334 | |||
| 335 | protected function compileGroupBy() { |
||
| 336 | // TODO - fields should be escaped !! |
||
| 337 | // !empty($this->groupBy) ? $this->_compiledQuery[] = 'GROUP BY ' . implode(',', $this->arrayEscape($this->groupBy)) : false; |
||
| 338 | !empty($this->groupBy) ? $this->_compiledQuery[] = 'GROUP BY ' . $this->selectFieldsToString($this->groupBy) : false; |
||
| 339 | } |
||
| 340 | |||
| 341 | protected function compileOrderBy() { |
||
| 342 | // TODO - fields should be escaped !! |
||
| 343 | !empty($this->orderBy) ? $this->_compiledQuery[] = 'ORDER BY ' . implode(',', $this->arrayEscape($this->orderBy)) : false; |
||
| 344 | } |
||
| 345 | |||
| 346 | protected function compileHaving() { |
||
| 347 | // TODO - fields should be escaped !! |
||
| 348 | !empty($this->having) ? $this->_compiledQuery[] = 'HAVING ' . implode(' AND ', $this->having) : false; |
||
| 349 | } |
||
| 350 | |||
| 351 | protected function compileLimit() { |
||
| 352 | // TODO - fields should be escaped !! |
||
| 353 | if ($limit = $this->fetchOne ? 1 : $this->limit) { |
||
| 354 | $this->_compiledQuery[] = 'LIMIT ' . $limit . (!empty($this->offset) ? ' OFFSET ' . $this->offset : ''); |
||
| 355 | } |
||
| 356 | } |
||
| 357 | |||
| 358 | protected function compileForUpdate() { |
||
| 359 | $this->_compiledQuery[] = |
||
| 360 | // forUpdate flag forces select with row locking - didn't look at skipLock flag |
||
| 361 | $this->forUpdate |
||
| 362 | || |
||
| 363 | // Also row locked when transaction is up and skipLock flag is not set |
||
| 364 | ($this->db->getTransaction()->check(false) && !$this->skipLock) ? 'FOR UPDATE' : ''; |
||
| 365 | } |
||
| 366 | |||
| 367 | /** |
||
| 368 | * @param array|mixed $fields |
||
| 369 | * |
||
| 370 | * @return string |
||
| 371 | * @throws ExceptionDBFieldEmpty |
||
| 372 | */ |
||
| 373 | 16 | protected function selectFieldsToString($fields) { |
|
| 374 | 16 | HelperArray::makeArrayRef($fields); |
|
| 375 | |||
| 376 | 16 | $result = array(); |
|
| 377 | 16 | foreach ($fields as $fieldName) { |
|
| 378 | 15 | $string = $this->processField($fieldName); |
|
| 379 | 15 | if ($string !== '') { |
|
| 380 | 13 | $result[] = $string; |
|
| 381 | 13 | } |
|
| 382 | 16 | } |
|
| 383 | |||
| 384 | 16 | if (empty($result)) { |
|
| 385 | 3 | throw new ExceptionDBFieldEmpty(); |
|
| 386 | } |
||
| 387 | |||
| 388 | 13 | return implode(',', $result); |
|
| 389 | } |
||
| 390 | |||
| 391 | /** |
||
| 392 | * @param mixed $fieldName |
||
| 393 | * |
||
| 394 | * @return string |
||
| 395 | */ |
||
| 396 | 13 | protected function processField($fieldName) { |
|
| 397 | 13 | if (is_bool($fieldName)) { |
|
| 398 | 4 | $result = (string)intval($fieldName); |
|
| 399 | 13 | } elseif (is_numeric($fieldName)) { |
|
| 400 | 5 | $result = $fieldName; |
|
| 401 | 11 | } elseif (is_null($fieldName)) { |
|
| 402 | 2 | $result = 'NULL'; |
|
| 403 | 2 | } else { |
|
| 404 | // Field has other type - string or should be convertible to string |
||
| 405 | 6 | $result = (string)$fieldName; |
|
| 406 | 6 | if (!$fieldName instanceof DbSqlLiteral) { |
|
| 407 | 5 | $result = $this->quoteField($fieldName); |
|
| 408 | 5 | } |
|
| 409 | } |
||
| 410 | |||
| 411 | 13 | return $result; |
|
| 412 | } |
||
| 413 | |||
| 414 | |||
| 415 | /** |
||
| 416 | * @return string |
||
| 417 | * @throws ExceptionDbOperationEmpty |
||
| 418 | * @throws ExceptionDbOperationRestricted |
||
| 419 | */ |
||
| 420 | 2 | public function __toString() { |
|
| 421 | 2 | $this->_compiledQuery = array(); |
|
| 422 | |||
| 423 | 2 | $this->compileOperation(); |
|
| 424 | $this->compileSubject(); |
||
| 425 | $this->compileFrom(); |
||
| 426 | $this->compileJoin(); |
||
| 427 | $this->compileWhere(); |
||
| 428 | $this->compileGroupBy(); |
||
| 429 | $this->compileOrderBy(); |
||
| 430 | $this->compileHaving(); |
||
| 431 | $this->compileLimit(); |
||
| 432 | $this->compileForUpdate(); |
||
| 433 | |||
| 434 | return implode(' ', $this->_compiledQuery); |
||
| 435 | } |
||
| 436 | |||
| 437 | /** |
||
| 438 | * @param bool $skip_query_check |
||
|
0 ignored issues
–
show
|
|||
| 439 | * |
||
| 440 | * @return DbEmptyIterator|DbMysqliResultIterator |
||
| 441 | */ |
||
| 442 | public function selectIterator() { |
||
| 443 | return $this->getDb()->doSelectIterator($this->select()->__toString()); |
||
| 444 | } |
||
| 445 | |||
| 446 | /** |
||
| 447 | * @param bool $skip_query_check |
||
|
0 ignored issues
–
show
There is no parameter named
$skip_query_check. Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. Loading history...
|
|||
| 448 | * |
||
| 449 | * @return array |
||
| 450 | */ |
||
| 451 | public function selectRow() { |
||
| 452 | $result = $this->getDb()->doSelectFetch($this->select()->setFetchOne()->__toString()); |
||
| 453 | |||
| 454 | return is_array($result) ? $result : array(); |
||
| 455 | } |
||
| 456 | |||
| 457 | /** |
||
| 458 | * @param bool $skip_query_check |
||
|
0 ignored issues
–
show
There is no parameter named
$skip_query_check. Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. Loading history...
|
|||
| 459 | * |
||
| 460 | * @return mixed|null |
||
| 461 | */ |
||
| 462 | public function selectValue() { |
||
| 463 | $result = $this->selectRow(); |
||
| 464 | |||
| 465 | return is_array($result) ? reset($result) : null; |
||
| 466 | } |
||
| 467 | |||
| 468 | } |
||
| 469 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italyis not defined by the methodfinale(...).The most likely cause is that the parameter was removed, but the annotation was not.