Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
conditiontree.php
1<?php
10
21
28{
30 protected $chains;
31
33 protected $conditions = array();
34
39 protected $logic;
40
43
44 const LOGIC_OR = 'or';
45
46 const LOGIC_AND = 'and';
47
52 protected $isNegative = false;
53
57 public function __construct()
58 {
59 $this->logic = static::LOGIC_AND;
60 }
61
70 public function logic($logic = null)
71 {
72 if ($logic === null)
73 {
74 return $this->logic;
75 }
76
77 if (!in_array(strtolower($logic), [static::LOGIC_AND, static::LOGIC_OR], true))
78 {
79 throw new ArgumentException("Unknown logic");
80 }
81
82 $this->logic = strtolower($logic);
83
84 return $this;
85 }
86
94 public function negative($negative = true)
95 {
96 $this->isNegative = (bool) $negative;
97 return $this;
98 }
99
125 public function where(...$filter)
126 {
127 // subfilter
128 if (count($filter) == 1 && $filter[0] instanceof ConditionTree)
129 {
130 $this->conditions[] = $filter[0];
131 return $this;
132 }
133
134 // ready condition
135 if (count($filter) == 1 && $filter[0] instanceof Condition)
136 {
137 $this->conditions[] = $filter[0];
138 return $this;
139 }
140
141 // array of conditions
142 if (count($filter) == 1 && is_array($filter[0]))
143 {
144 foreach ($filter[0] as $condition)
145 {
146 // call `where` for each condition
147 call_user_func_array(array($this, 'where'), $condition);
148 }
149 return $this;
150 }
151
152 // regular conditions
153 if (count($filter) == 3)
154 {
155 // everything is clear
156 list($column, $operator, $value) = $filter;
157 }
158 elseif (count($filter) == 2)
159 {
160 // equal by default
161 list($column, $value) = $filter;
162 $operator = '=';
163 }
164 elseif (count($filter) == 1)
165 {
166 // suppose it is boolean field with true value
167 $column = $filter[0];
168 $operator = '=';
169 $value = true;
170 }
171 else
172 {
173 throw new ArgumentException('Wrong arguments');
174 }
175
176 // validate operator
177 $operators = Operator::get();
178 if (!isset($operators[$operator]))
179 {
180 throw new ArgumentException("Unknown operator `{$operator}`");
181 }
182
183 // add condition
184 $this->conditions[] = new Condition($column, $operator, $value);
185
186 return $this;
187 }
188
197 public function whereNot(...$filter)
198 {
199 $subFilter = new static();
200 call_user_func_array(array($subFilter, 'where'), $filter);
201
202 $this->conditions[] = $subFilter->negative();
203 return $this;
204 }
205
215 public function whereColumn(...$filter)
216 {
217 if (count($filter) == 3)
218 {
219 list($column, $operator, $value) = $filter;
220 }
221 elseif (count($filter) == 2)
222 {
223 list($column, $value) = $filter;
224 $operator = '=';
225 }
226 else
227 {
228 throw new ArgumentException('Wrong arguments');
229 }
230
231 // convert value to column format
232 $value = new Expressions\ColumnExpression($value);
233
234 // put through general method
235 $this->where($column, $operator, $value);
236
237 return $this;
238 }
239
247 public function whereNull($column)
248 {
249 $this->conditions[] = new Condition($column, '=', null);
250
251 return $this;
252 }
253
261 public function whereNotNull($column)
262 {
263 $this->conditions[] = new Condition($column, '<>', null);
264
265 return $this;
266 }
267
276 public function whereIn($column, $values)
277 {
278 if (!empty($values))
279 {
280 $this->conditions[] = new Condition($column, 'in', $values);
281 }
282
283 return $this;
284 }
285
295 public function whereNotIn($column, $values)
296 {
297 $subFilter = new static();
298 $this->conditions[] = $subFilter->whereIn($column, $values)->negative();
299
300 return $this;
301 }
302
312 public function whereBetween($column, $valueMin, $valueMax)
313 {
314 $this->conditions[] = new Condition($column, 'between', array($valueMin, $valueMax));
315
316 return $this;
317 }
318
329 public function whereNotBetween($column, $valueMin, $valueMax)
330 {
331 $subFilter = new static();
332 $this->conditions[] = $subFilter->whereBetween($column, $valueMin, $valueMax)->negative();
333
334 return $this;
335 }
336
345 public function whereLike($column, $value)
346 {
347 $this->conditions[] = new Condition($column, 'like', $value);
348
349 return $this;
350 }
351
361 public function whereNotLike($column, $value)
362 {
363 $subFilter = new static();
364 $this->conditions[] = $subFilter->whereLike($column, $value)->negative();
365
366 return $this;
367 }
368
376 public function whereExists($query)
377 {
378 $this->conditions[] = new Condition(null, 'exists', $query);
379
380 return $this;
381 }
382
392 public function whereNotExists($query)
393 {
394 if ($query instanceof Query || $query instanceof SqlExpression)
395 {
396 $subFilter = new static();
397 $this->conditions[] = $subFilter->whereExists($query)->negative();
398
399 return $this;
400 }
401
402 throw new ArgumentException('Unknown type of query '.gettype($query));
403 }
404
414 public function whereMatch($column, $value)
415 {
416 $this->conditions[] = new Condition($column, 'match', $value);
417
418 return $this;
419 }
420
430 public function whereNotMatch($column, $value)
431 {
432 $subFilter = new static();
433 $this->conditions[] = $subFilter->whereMatch($column, $value)->negative();
434
435 return $this;
436 }
437
449 public function whereExpr($expr, $arguments)
450 {
451 // get random field name
452 $randomSequence = static::getRandomSequence();
453 $tmpName = 'TMP_'.$randomSequence->randString(10);
454
455 // set boolean expression
456 $tmpField = (new ExpressionField($tmpName, $expr, $arguments))
457 ->configureValueType(BooleanField::class);
458
459 // add condition
460 $this->where($tmpField, 'expr', true);
461
462 return $this;
463 }
464
474 public function getSql($chains)
475 {
476 // save chains
477 $this->chains = $chains;
478
479 $finalSql = array();
480
481 // build sql
482 foreach ($this->conditions as $condition)
483 {
484 if ($condition instanceof ConditionTree)
485 {
486 // subfilter
487 $subFilter = $condition;
488 $sql = $subFilter->getSql($chains);
489
490 if (count($subFilter->getConditions()) > 1)
491 {
492 $sql = "({$sql})";
493 }
494 }
495 else
496 {
497 // regular condition
498 $columnSqlDefinition = null;
499 $columnField = null;
500
501 // define column field
502 if ($condition->getColumn() !== null)
503 {
504 $chain = $chains[$condition->getDefinition()];
505 $columnSqlDefinition = $chain->getSqlDefinition();
506
508 $columnField = $chain->getLastElement()->getValue();
509 }
510
511 // final value's sql
512 if (in_array($condition->getOperator(), array('in', 'between'), true) && is_array($condition->getValue()))
513 {
514 // value is in array of atomic values
515 $finalValue = $this->convertValues($condition->getValue(), $columnField);
516 }
517 else
518 {
519 $finalValue = $this->convertValue($condition->getValue(), $columnField);
520 }
521
522 // operation method
523 $operators = Operator::get();
524 $operator = $operators[$condition->getOperator()];
525
526 // final sql
527 $sql = call_user_func(
528 array('Bitrix\Main\ORM\Query\Filter\Operator', $operator),
529 $columnSqlDefinition, $finalValue
530 );
531 }
532
533 if ($sql != '')
534 {
535 $finalSql[] = $sql;
536 }
537 }
538
539 $sql = null;
540
541 if (!empty($finalSql))
542 {
543 // concat with $this->logic
544 $sql = join(" ".strtoupper($this->logic)." ", $finalSql);
545
546 // and put NOT if negative
547 if ($this->isNegative)
548 {
549 $sql = count($finalSql) > 1 ? "NOT ({$sql})" : "NOT {$sql}";
550 }
551 }
552
553 return $sql;
554 }
555
561 public function getConditions()
562 {
563 return $this->conditions;
564 }
565
574 public function addCondition($condition)
575 {
576 if ($condition instanceof Condition || $condition instanceof ConditionTree)
577 {
578 $this->conditions[] = $condition;
579 return $this;
580 }
581
582 throw new ArgumentException('Unknown type of condition '.gettype($condition));
583 }
584
590 public function hasConditions()
591 {
592 return !empty($this->conditions);
593 }
594
603 public function replaceCondition($currentCondition, $newCondition)
604 {
605 foreach ($this->conditions as $k => $condition)
606 {
607 if ($condition === $currentCondition)
608 {
609 $this->conditions[$k] = $newCondition;
610 return true;
611 }
612 }
613
614 return false;
615 }
616
624 public function removeCondition($condition)
625 {
626 foreach ($this->conditions as $k => $_condition)
627 {
628 if ($condition == $_condition)
629 {
630 unset($this->conditions[$k]);
631 return true;
632 }
633 }
634
635 return false;
636 }
637
641 public function removeAllConditions()
642 {
643 $this->conditions = [];
644 }
645
656 protected function convertValue($value, IReadable $field = null)
657 {
658 // any sql expression
659 if ($value instanceof SqlExpression)
660 {
661 return $value->compile();
662 }
663
664 // subquery
665 if ($value instanceof Query)
666 {
667 return $value->getQuery();
668 }
669
670 // subfilter
671 if ($value instanceof ConditionTree)
672 {
673 return $value->getSql($this->chains);
674 }
675
676 // nulls
677 if ($value === null)
678 {
679 return new Expressions\NullExpression;
680 }
681
682 if ($value instanceof Expressions\ColumnExpression)
683 {
685 $valueChain = $this->chains[$value->getDefinition()];
686 return $valueChain->getSqlDefinition();
687 }
688
689 return $field->convertValueToDb($value); // give them current sql helper
690 }
691
703 protected function convertValues($values, IReadable $field = null)
704 {
705 foreach ($values as $k => $value)
706 {
707 $values[$k] = $this->convertValue($value, $field);
708 }
709
710 return $values;
711 }
712
713 public function __clone()
714 {
715 $newConditions = array();
716
717 foreach ($this->conditions as $condition)
718 {
719 $newConditions[] = clone $condition;
720 }
721
722 $this->conditions = $newConditions;
723 }
724
728 protected static function getRandomSequence(): RandomSequence
729 {
730 if (!isset(static::$randomSequence))
731 {
732 static::$randomSequence = new RandomSequence('orm.filter.expr');
733 }
734
735 return static::$randomSequence;
736 }
737
746 public static function createFromArray($filter)
747 {
748 $conditionTree = Query::filter();
749
750 if (isset($filter['logic']))
751 {
752 $conditionTree->logic($filter['logic']);
753 unset($filter['logic']);
754 }
755
756 if (isset($filter['negative']))
757 {
758 $conditionTree->negative($filter['negative']);
759 unset($filter['negative']);
760 }
761
762 foreach ($filter as $condition)
763 {
764 if (isset($condition[0]) && is_array($condition[0]))
765 {
766 $conditionTree->where(static::createFromArray($condition));
767 }
768 else
769 {
770 // parse regular filter condition
771 $valueKey = key(array_reverse($condition, true));
772 $valueElement = $condition[$valueKey];
773
774 if (is_array($valueElement))
775 {
776 if (isset($valueElement['value']))
777 {
778 $value = $valueElement['value'];
779 }
780 elseif (isset($valueElement['column']))
781 {
782 $value = new ColumnExpression($valueElement['column']);
783 }
784 else
785 {
786 // could be an array of columns
787 foreach ($valueElement as $k => $singleValue)
788 {
789 if (is_array($singleValue))
790 {
791 if (isset($singleValue['value']))
792 {
793 $valueElement[$k] = $singleValue['value'];
794 }
795 elseif (isset($singleValue['column']))
796 {
797 $valueElement[$k] = new ColumnExpression($singleValue['column']);
798 }
799 }
800 }
801
802 $value = $valueElement;
803 }
804
805 $condition[$valueKey] = $value;
806 }
807
808 $conditionTree->where(...$condition);
809 }
810 }
811
812 return $conditionTree;
813 }
814}
whereNotBetween($column, $valueMin, $valueMax)
whereBetween($column, $valueMin, $valueMax)
replaceCondition($currentCondition, $newCondition)
convertValues($values, IReadable $field=null)