bytic /
database
| 1 | <?php |
||||
| 2 | |||||
| 3 | namespace Nip\Database\Query; |
||||
| 4 | |||||
| 5 | use Nip\Database\Connections\Connection; |
||||
| 6 | use Nip\Database\Query\Condition\Condition; |
||||
| 7 | use Nip\Database\Result; |
||||
| 8 | |||||
| 9 | /** |
||||
| 10 | * Class AbstractQuery |
||||
| 11 | * @package Nip\Database\Query |
||||
| 12 | * |
||||
| 13 | * @method $this setCols() setCols(array | string $cols = null) |
||||
| 14 | * @method $this setWhere() setWhere(array | string $cols = null) |
||||
| 15 | * |
||||
| 16 | * @method $this cols() cols(array | string $cols) |
||||
| 17 | * @method $this count() count(string $col, string $alias = null) |
||||
| 18 | * @method $this sum() sum(array | string $cols) |
||||
| 19 | * @method $this from() from(array | string $from) |
||||
| 20 | * @method $this data() data(array $data) |
||||
| 21 | * @method $this table() table(array | string $table) |
||||
| 22 | * @method $this order() order(array | string $order)\ |
||||
| 23 | * @method $this group() group(array | string $group, $rollup = false)\ |
||||
| 24 | */ |
||||
| 25 | abstract class AbstractQuery |
||||
| 26 | { |
||||
| 27 | /** |
||||
| 28 | * @var Connection |
||||
| 29 | */ |
||||
| 30 | protected $db; |
||||
| 31 | |||||
| 32 | protected $parts = [ |
||||
| 33 | 'where' => null, |
||||
| 34 | ]; |
||||
| 35 | |||||
| 36 | protected $string = null; |
||||
| 37 | |||||
| 38 | /** |
||||
| 39 | * @param Connection $manager |
||||
| 40 | * @return $this |
||||
| 41 | */ |
||||
| 42 | public function setManager(Connection $manager) |
||||
| 43 | 23 | { |
|||
| 44 | $this->db = $manager; |
||||
| 45 | 23 | ||||
| 46 | return $this; |
||||
| 47 | 23 | } |
|||
| 48 | |||||
| 49 | /** |
||||
| 50 | * @param $name |
||||
| 51 | * @param $arguments |
||||
| 52 | * @return $this |
||||
| 53 | */ |
||||
| 54 | public function __call($name, $arguments) |
||||
| 55 | 13 | { |
|||
| 56 | if (strpos($name, 'set') === 0) { |
||||
| 57 | 13 | $name = str_replace('set', '', $name); |
|||
| 58 | 1 | $name[0] = strtolower($name[0]); |
|||
| 59 | 1 | $this->initPart($name); |
|||
| 60 | 1 | } |
|||
| 61 | |||||
| 62 | foreach ($arguments as $argument) { |
||||
| 63 | 13 | $this->addPart($name, $argument); |
|||
| 64 | 13 | } |
|||
| 65 | |||||
| 66 | return $this; |
||||
| 67 | 13 | } |
|||
| 68 | |||||
| 69 | /** |
||||
| 70 | * @param $name |
||||
| 71 | * @return $this |
||||
| 72 | */ |
||||
| 73 | protected function initPart($name) |
||||
| 74 | 13 | { |
|||
| 75 | $this->isGenerated(false); |
||||
| 76 | 13 | $this->parts[$name] = []; |
|||
| 77 | 13 | ||||
| 78 | return $this; |
||||
| 79 | 13 | } |
|||
| 80 | |||||
| 81 | /** |
||||
| 82 | * @param boolean $generated |
||||
| 83 | * @return bool |
||||
| 84 | */ |
||||
| 85 | public function isGenerated($generated = null) |
||||
| 86 | 13 | { |
|||
| 87 | if ($generated === false) { |
||||
| 88 | 13 | $this->string = null; |
|||
| 89 | 13 | } |
|||
| 90 | |||||
| 91 | return $this->string !== null; |
||||
| 92 | 13 | } |
|||
| 93 | |||||
| 94 | /** |
||||
| 95 | * @param $name |
||||
| 96 | * @param $value |
||||
| 97 | * @return $this |
||||
| 98 | */ |
||||
| 99 | protected function addPart($name, $value) |
||||
| 100 | 13 | { |
|||
| 101 | if (!isset($this->parts[$name])) { |
||||
| 102 | 13 | $this->initPart($name); |
|||
| 103 | 13 | } |
|||
| 104 | |||||
| 105 | $this->isGenerated(false); |
||||
| 106 | 13 | $this->parts[$name][] = $value; |
|||
| 107 | 13 | ||||
| 108 | return $this; |
||||
| 109 | 13 | } |
|||
| 110 | |||||
| 111 | /** |
||||
| 112 | * @param $params |
||||
| 113 | */ |
||||
| 114 | public function addParams($params) |
||||
| 115 | { |
||||
| 116 | $this->checkParamSelect($params); |
||||
| 117 | $this->checkParamFrom($params); |
||||
| 118 | $this->checkParamWhere($params); |
||||
| 119 | $this->checkParamOrder($params); |
||||
| 120 | $this->checkParamGroup($params); |
||||
| 121 | $this->checkParamHaving($params); |
||||
| 122 | $this->checkParamLimit($params); |
||||
| 123 | } |
||||
| 124 | |||||
| 125 | /** |
||||
| 126 | * @param $params |
||||
| 127 | */ |
||||
| 128 | protected function checkParamSelect($params) |
||||
| 129 | { |
||||
| 130 | if (isset($params['select']) && is_array($params['select'])) { |
||||
| 131 | call_user_func_array([$this, 'cols'], $params['select']); |
||||
| 132 | } |
||||
| 133 | } |
||||
| 134 | |||||
| 135 | /** |
||||
| 136 | * @param $params |
||||
| 137 | */ |
||||
| 138 | protected function checkParamFrom($params) |
||||
| 139 | { |
||||
| 140 | if (isset($params['from']) && !empty($params['from'])) { |
||||
| 141 | $this->from($params['from']); |
||||
| 142 | } |
||||
| 143 | } |
||||
| 144 | |||||
| 145 | /** |
||||
| 146 | * @param $params |
||||
| 147 | */ |
||||
| 148 | protected function checkParamWhere($params) |
||||
| 149 | { |
||||
| 150 | if (isset($params['where']) && is_array($params['where'])) { |
||||
| 151 | foreach ($params['where'] as $condition) { |
||||
| 152 | if ($condition instanceof Condition) { |
||||
| 153 | $condition->setQuery($this); |
||||
| 154 | $this->where($condition); |
||||
| 155 | continue; |
||||
| 156 | } |
||||
| 157 | $condition = (array)$condition; |
||||
| 158 | $this->where( |
||||
| 159 | $condition[0], |
||||
| 160 | isset($condition[1]) ? $condition[1] : null |
||||
| 161 | ); |
||||
| 162 | } |
||||
| 163 | } |
||||
| 164 | } |
||||
| 165 | |||||
| 166 | /** |
||||
| 167 | 6 | * @param $string |
|||
| 168 | * @param array $values |
||||
| 169 | * @return $this |
||||
| 170 | 6 | */ |
|||
| 171 | 6 | public function where($string, $values = []) |
|||
| 172 | 2 | { |
|||
| 173 | /** @var Condition $this ->_parts[] */ |
||||
| 174 | 6 | if ($string) { |
|||
| 175 | if (isset($this->parts['where']) && $this->parts['where'] instanceof Condition) { |
||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 176 | $this->parts['where'] = $this->parts['where']->and_($this->getCondition($string, $values)); |
||||
|
0 ignored issues
–
show
The method
getCondition() does not exist on Nip\Database\Query\Condition\Condition.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||||
| 177 | } else { |
||||
| 178 | 6 | $this->parts['where'] = $this->getCondition($string, $values); |
|||
| 179 | } |
||||
| 180 | } |
||||
| 181 | |||||
| 182 | return $this; |
||||
|
0 ignored issues
–
show
|
|||||
| 183 | } |
||||
| 184 | |||||
| 185 | /** |
||||
| 186 | 13 | * @param string $string |
|||
| 187 | * @param array $values |
||||
| 188 | 13 | * |
|||
| 189 | 13 | * @return Condition |
|||
| 190 | 13 | */ |
|||
| 191 | public function getCondition($string, $values = []) |
||||
| 192 | { |
||||
| 193 | if (!is_object($string)) { |
||||
|
0 ignored issues
–
show
|
|||||
| 194 | $condition = new Condition($string, $values); |
||||
| 195 | 13 | $condition->setQuery($this); |
|||
| 196 | } else { |
||||
| 197 | $condition = $string; |
||||
| 198 | } |
||||
| 199 | |||||
| 200 | return $condition; |
||||
| 201 | } |
||||
| 202 | |||||
| 203 | /** |
||||
| 204 | * @param $params |
||||
| 205 | */ |
||||
| 206 | protected function checkParamOrder($params) |
||||
| 207 | { |
||||
| 208 | if (isset($params['order']) && !empty($params['order'])) { |
||||
| 209 | call_user_func_array([$this, 'order'], $params['order']); |
||||
| 210 | } |
||||
| 211 | } |
||||
| 212 | |||||
| 213 | /** |
||||
| 214 | * @param $params |
||||
| 215 | */ |
||||
| 216 | protected function checkParamGroup($params) |
||||
| 217 | { |
||||
| 218 | if (isset($params['group']) && !empty($params['group'])) { |
||||
| 219 | call_user_func_array([$this, 'group'], [$params['group']]); |
||||
| 220 | } |
||||
| 221 | } |
||||
| 222 | |||||
| 223 | /** |
||||
| 224 | * @param $params |
||||
| 225 | */ |
||||
| 226 | protected function checkParamHaving($params) |
||||
| 227 | { |
||||
| 228 | if (isset($params['having']) && !empty($params['having'])) { |
||||
| 229 | call_user_func_array([$this, 'having'], [$params['having']]); |
||||
| 230 | } |
||||
| 231 | } |
||||
| 232 | |||||
| 233 | /** |
||||
| 234 | * @param $params |
||||
| 235 | */ |
||||
| 236 | protected function checkParamLimit($params) |
||||
| 237 | { |
||||
| 238 | if (isset($params['limit']) && !empty($params['limit'])) { |
||||
| 239 | call_user_func_array([$this, 'limit'], [$params['limit']]); |
||||
| 240 | } |
||||
| 241 | } |
||||
| 242 | |||||
| 243 | 2 | /** |
|||
| 244 | * @param integer $start |
||||
| 245 | 2 | * @param bool $offset |
|||
| 246 | 2 | * @return $this |
|||
| 247 | 1 | */ |
|||
| 248 | public function limit($start, $offset = false) |
||||
| 249 | { |
||||
| 250 | 2 | $this->parts['limit'] = $start; |
|||
| 251 | if ($offset) { |
||||
| 252 | $this->parts['limit'] .= ',' . $offset; |
||||
|
0 ignored issues
–
show
Are you sure
$offset of type true can be used in concatenation?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 253 | } |
||||
| 254 | |||||
| 255 | return $this; |
||||
| 256 | } |
||||
| 257 | |||||
| 258 | 1 | /** |
|||
| 259 | * @param $string |
||||
| 260 | 1 | * @param array $values |
|||
| 261 | 1 | * |
|||
| 262 | 1 | * @return $this |
|||
| 263 | */ |
||||
| 264 | public function orWhere($string, $values = []) |
||||
| 265 | { |
||||
| 266 | if ($string) { |
||||
| 267 | if ($this->parts['where'] instanceof Condition) { |
||||
| 268 | 1 | $this->parts['where'] = $this->parts['where']->or_($this->getCondition($string, $values)); |
|||
| 269 | } else { |
||||
| 270 | $this->parts['where'] = $this->getCondition($string, $values); |
||||
| 271 | } |
||||
| 272 | } |
||||
| 273 | |||||
| 274 | return $this; |
||||
| 275 | } |
||||
| 276 | |||||
| 277 | /** |
||||
| 278 | * @param $string |
||||
| 279 | * @param array $values |
||||
| 280 | * |
||||
| 281 | * @return $this |
||||
| 282 | */ |
||||
| 283 | public function having($string, $values = []) |
||||
| 284 | { |
||||
| 285 | if (empty($string)) { |
||||
| 286 | return $this; |
||||
| 287 | } |
||||
| 288 | |||||
| 289 | $condition = $this->getCondition($string, $values); |
||||
| 290 | $having = $this->getPart('having'); |
||||
| 291 | |||||
| 292 | if ($having instanceof Condition) { |
||||
| 293 | $having = $having->and_($this->getCondition($string, $values)); |
||||
| 294 | } else { |
||||
| 295 | $having = $condition; |
||||
| 296 | } |
||||
| 297 | $this->parts['having'] = $having; |
||||
| 298 | return $this; |
||||
| 299 | } |
||||
| 300 | |||||
| 301 | /** |
||||
| 302 | * Escapes data for safe use in SQL queries |
||||
| 303 | 3 | * |
|||
| 304 | * @param string $data |
||||
| 305 | 3 | * @return string |
|||
| 306 | */ |
||||
| 307 | public function cleanData($data) |
||||
| 308 | { |
||||
| 309 | return $this->getManager()->getAdapter()->cleanData($data); |
||||
| 310 | } |
||||
| 311 | |||||
| 312 | /** |
||||
| 313 | * @return Connection |
||||
| 314 | */ |
||||
| 315 | public function getManager() |
||||
| 316 | { |
||||
| 317 | return $this->db; |
||||
| 318 | } |
||||
| 319 | |||||
| 320 | /** |
||||
| 321 | 2 | * @return Result |
|||
| 322 | */ |
||||
| 323 | 2 | public function execute() |
|||
| 324 | { |
||||
| 325 | return $this->getManager()->execute($this); |
||||
| 326 | } |
||||
| 327 | |||||
| 328 | /** |
||||
| 329 | 2 | * Implements magic method. |
|||
| 330 | * |
||||
| 331 | 2 | * @return string This object as a Query string. |
|||
| 332 | 2 | */ |
|||
| 333 | public function __toString() |
||||
| 334 | { |
||||
| 335 | 2 | return $this->getString(); |
|||
| 336 | } |
||||
| 337 | |||||
| 338 | /** |
||||
| 339 | * @return string |
||||
| 340 | */ |
||||
| 341 | public function getString() |
||||
| 342 | { |
||||
| 343 | if ($this->string === null) { |
||||
| 344 | $this->string = (string)$this->assemble(); |
||||
|
0 ignored issues
–
show
Are you sure the usage of
$this->assemble() targeting Nip\Database\Query\AbstractQuery::assemble() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
|
|||||
| 345 | } |
||||
| 346 | |||||
| 347 | return $this->string; |
||||
| 348 | } |
||||
| 349 | |||||
| 350 | /** |
||||
| 351 | * @return null |
||||
| 352 | */ |
||||
| 353 | abstract public function assemble(); |
||||
| 354 | 10 | ||||
| 355 | /** |
||||
| 356 | 10 | * @return array |
|||
| 357 | */ |
||||
| 358 | 10 | public function getParts() |
|||
| 359 | 6 | { |
|||
| 360 | return $this->parts; |
||||
| 361 | } |
||||
| 362 | 4 | ||||
| 363 | /** |
||||
| 364 | * @return null|string |
||||
| 365 | */ |
||||
| 366 | protected function assembleWhere() |
||||
| 367 | { |
||||
| 368 | 10 | $where = $this->parseWhere(); |
|||
| 369 | |||||
| 370 | 10 | if (!empty($where)) { |
|||
| 371 | return " WHERE $where"; |
||||
| 372 | } |
||||
| 373 | |||||
| 374 | return null; |
||||
| 375 | } |
||||
| 376 | 10 | ||||
| 377 | /** |
||||
| 378 | 10 | * @return string |
|||
| 379 | 10 | */ |
|||
| 380 | 1 | protected function parseWhere() |
|||
| 381 | { |
||||
| 382 | return is_object($this->parts['where']) ? (string)$this->parts['where'] : ''; |
||||
| 383 | 9 | } |
|||
| 384 | |||||
| 385 | /** |
||||
| 386 | * @return null|string |
||||
| 387 | */ |
||||
| 388 | protected function assembleLimit() |
||||
| 389 | { |
||||
| 390 | 11 | $limit = $this->getPart('limit'); |
|||
| 391 | if (!empty($limit)) { |
||||
| 392 | 11 | return " LIMIT {$this->parts['limit']}"; |
|||
| 393 | } |
||||
| 394 | |||||
| 395 | return null; |
||||
| 396 | } |
||||
| 397 | |||||
| 398 | /** |
||||
| 399 | 13 | * @param string $name |
|||
| 400 | * @return mixed|null |
||||
| 401 | 13 | */ |
|||
| 402 | 11 | public function getPart($name) |
|||
| 403 | { |
||||
| 404 | 3 | return $this->hasPart($name) ? $this->parts[$name] : null; |
|||
| 405 | } |
||||
| 406 | |||||
| 407 | 3 | /** |
|||
| 408 | 1 | * @param $name |
|||
| 409 | * @return bool |
||||
| 410 | */ |
||||
| 411 | 3 | public function hasPart($name) |
|||
| 412 | { |
||||
| 413 | if (!isset($this->parts[$name])) { |
||||
| 414 | return false; |
||||
| 415 | } |
||||
| 416 | if ($this->parts[$name] === null) { |
||||
|
0 ignored issues
–
show
|
|||||
| 417 | return false; |
||||
| 418 | } |
||||
| 419 | if (is_array($this->parts[$name]) && count($this->parts[$name]) < 1) { |
||||
| 420 | return false; |
||||
| 421 | } |
||||
| 422 | if (is_string($this->parts[$name]) && empty($this->parts[$name])) { |
||||
| 423 | return false; |
||||
| 424 | } |
||||
| 425 | |||||
| 426 | return true; |
||||
| 427 | } |
||||
| 428 | |||||
| 429 | /** |
||||
| 430 | 2 | * @param $name |
|||
| 431 | * @param $value |
||||
| 432 | 2 | * |
|||
| 433 | * @return $this |
||||
| 434 | */ |
||||
| 435 | protected function setPart($name, $value) |
||||
| 436 | 2 | { |
|||
| 437 | $this->initPart($name); |
||||
| 438 | $this->addPart($name, $value); |
||||
| 439 | |||||
| 440 | return $this; |
||||
| 441 | } |
||||
| 442 | 10 | ||||
| 443 | /** |
||||
| 444 | 10 | * @return string |
|||
| 445 | * @return mixed |
||||
| 446 | */ |
||||
| 447 | protected function getTable() |
||||
| 448 | 10 | { |
|||
| 449 | if (!is_array($this->parts['table']) && count($this->parts['table']) < 1) { |
||||
|
0 ignored issues
–
show
$this->parts['table'] of type null is incompatible with the type Countable|array expected by parameter $value of count().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 450 | trigger_error('No Table defined', E_USER_WARNING); |
||||
| 451 | } |
||||
| 452 | |||||
| 453 | return reset($this->parts['table']); |
||||
| 454 | } |
||||
| 455 | |||||
| 456 | 10 | /** |
|||
| 457 | * @return string |
||||
| 458 | 10 | */ |
|||
| 459 | 10 | protected function parseHaving() |
|||
| 460 | { |
||||
| 461 | if (isset($this->parts['having'])) { |
||||
| 462 | return (string)$this->parts['having']; |
||||
| 463 | } |
||||
| 464 | |||||
| 465 | return ''; |
||||
| 466 | } |
||||
| 467 | |||||
| 468 | /** |
||||
| 469 | * Parses ORDER BY entries. |
||||
| 470 | * Parses ORDER BY entries |
||||
| 471 | * |
||||
| 472 | * @return string |
||||
| 473 | */ |
||||
| 474 | protected function parseOrder() |
||||
| 475 | { |
||||
| 476 | if (!isset($this->parts['order']) || !is_array($this->parts['order']) || count($this->parts['order']) < 1) { |
||||
|
0 ignored issues
–
show
|
|||||
| 477 | return false; |
||||
|
0 ignored issues
–
show
|
|||||
| 478 | } |
||||
| 479 | |||||
| 480 | $orderParts = []; |
||||
| 481 | |||||
| 482 | foreach ($this->parts['order'] as $itemOrder) { |
||||
| 483 | if ($itemOrder) { |
||||
| 484 | if (!is_array($itemOrder)) { |
||||
| 485 | $itemOrder = [$itemOrder]; |
||||
| 486 | } |
||||
| 487 | |||||
| 488 | $column = isset($itemOrder[0]) ? $itemOrder[0] : false; |
||||
| 489 | 7 | $type = isset($itemOrder[1]) ? $itemOrder[1] : ''; |
|||
| 490 | $protected = isset($itemOrder[2]) ? $itemOrder[2] : true; |
||||
| 491 | 7 | ||||
| 492 | 7 | $column = ($protected ? $this->protect($column) : $column) . ' ' . strtoupper($type); |
|||
| 493 | |||||
| 494 | $orderParts[] = trim($column); |
||||
| 495 | } |
||||
| 496 | } |
||||
| 497 | |||||
| 498 | return implode(', ', $orderParts); |
||||
| 499 | } |
||||
| 500 | |||||
| 501 | /** |
||||
| 502 | * Adds backticks to input. |
||||
| 503 | * |
||||
| 504 | * @param string $input |
||||
| 505 | * |
||||
| 506 | * @return string |
||||
| 507 | */ |
||||
| 508 | protected function protect($input) |
||||
| 509 | { |
||||
| 510 | return strpos($input, '(') !== false ? $input : str_replace( |
||||
| 511 | "`*`", |
||||
| 512 | "*", |
||||
| 513 | '`' . str_replace('.', '`.`', $input) . '`' |
||||
| 514 | ); |
||||
| 515 | } |
||||
| 516 | |||||
| 517 | /** |
||||
| 518 | * Prefixes table names |
||||
| 519 | * |
||||
| 520 | * @param string $table |
||||
| 521 | * @return string |
||||
| 522 | */ |
||||
| 523 | protected function tableName($table = '') |
||||
| 524 | { |
||||
| 525 | return $this->getManager()->tableName($table); |
||||
| 526 | } |
||||
| 527 | |||||
| 528 | /** |
||||
| 529 | * Removes backticks from input |
||||
| 530 | * |
||||
| 531 | * @param string $input |
||||
| 532 | * @return string |
||||
| 533 | */ |
||||
| 534 | protected function cleanProtected($input) |
||||
| 535 | { |
||||
| 536 | return str_replace('`', '', $input); |
||||
| 537 | } |
||||
| 538 | } |
||||
| 539 |