Passed
Pull Request — master (#163)
by Wilmer
17:48 queued 02:54
created

LikeConditionBuilder   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 98
Duplicated Lines 0 %

Test Coverage

Coverage 97.14%

Importance

Changes 0
Metric Value
eloc 42
dl 0
loc 98
ccs 34
cts 35
cp 0.9714
rs 10
c 0
b 0
f 0
wmc 17

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getEscapeSql() 0 7 2
C build() 0 43 12
A parseOperator() 0 11 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Query\Conditions;
6
7
use Yiisoft\Db\Exception\InvalidArgumentException;
8
use Yiisoft\Db\Expression\ExpressionBuilderInterface;
9
use Yiisoft\Db\Expression\ExpressionBuilderTrait;
10
use Yiisoft\Db\Expression\ExpressionInterface;
11
12
/**
13
 * Class LikeConditionBuilder builds objects of {@see LikeCondition}.
14
 */
15
class LikeConditionBuilder implements ExpressionBuilderInterface
16
{
17
    use ExpressionBuilderTrait;
18
19
    /**
20
     * @var array map of chars to their replacements in LIKE conditions. By default it's configured to escape
21
     * `%`, `_` and `\` with `\`.
22
     */
23
    protected array $escapingReplacements = [
24
        '%'  => '\%',
25
        '_'  => '\_',
26
        '\\' => '\\\\',
27
    ];
28
    protected ?string $escapeCharacter = null;
29
30
    /**
31
     * Method builds the raw SQL from the $expression that will not be additionally escaped or quoted.
32
     *
33
     * @param ExpressionInterface|LikeCondition $expression the expression to be built.
34
     * @param array $params the binding parameters.
35
     *
36
     * @return string the raw SQL that will not be additionally escaped or quoted.
37
     */
38 78
    public function build(ExpressionInterface $expression, &$params = []): string
39
    {
40 78
        $operator = strtoupper($expression->getOperator());
0 ignored issues
show
Bug introduced by
The method getOperator() does not exist on Yiisoft\Db\Expression\ExpressionInterface. It seems like you code against a sub-type of Yiisoft\Db\Expression\ExpressionInterface such as Yiisoft\Db\Query\Conditions\ConjunctionCondition or Yiisoft\Db\Query\Conditions\BetweenCondition or Yiisoft\Db\Query\Conditions\SimpleCondition or Yiisoft\Db\Query\Conditions\ExistsCondition or Yiisoft\Db\Query\Conditions\InCondition or Yiisoft\Db\Query\Conditi...BetweenColumnsCondition. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

40
        $operator = strtoupper($expression->/** @scrutinizer ignore-call */ getOperator());
Loading history...
41 78
        $column = $expression->getColumn();
0 ignored issues
show
Bug introduced by
The method getColumn() does not exist on Yiisoft\Db\Expression\ExpressionInterface. It seems like you code against a sub-type of Yiisoft\Db\Expression\ExpressionInterface such as Yiisoft\Db\Query\Conditions\BetweenCondition or Yiisoft\Db\Query\Conditions\SimpleCondition or Yiisoft\Db\Query\Conditions\InCondition. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

41
        /** @scrutinizer ignore-call */ 
42
        $column = $expression->getColumn();
Loading history...
42 78
        $values = $expression->getValue();
0 ignored issues
show
Bug introduced by
The method getValue() does not exist on Yiisoft\Db\Expression\ExpressionInterface. It seems like you code against a sub-type of Yiisoft\Db\Expression\ExpressionInterface such as Yiisoft\Db\Pdo\PdoValue or Yiisoft\Db\Expression\ArrayExpression or Yiisoft\Db\Expression\JsonExpression or Yiisoft\Db\Query\Conditions\SimpleCondition or Yiisoft\Db\Query\Conditi...BetweenColumnsCondition. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

42
        /** @scrutinizer ignore-call */ 
43
        $values = $expression->getValue();
Loading history...
43 78
        $escape = $expression->getEscapingReplacements();
0 ignored issues
show
Bug introduced by
The method getEscapingReplacements() does not exist on Yiisoft\Db\Expression\ExpressionInterface. It seems like you code against a sub-type of Yiisoft\Db\Expression\ExpressionInterface such as Yiisoft\Db\Query\Conditions\LikeCondition. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

43
        /** @scrutinizer ignore-call */ 
44
        $escape = $expression->getEscapingReplacements();
Loading history...
44
45 78
        if ($escape === null || $escape === []) {
46 75
            $escape = $this->escapingReplacements;
47
        }
48
49 78
        [$andor, $not, $operator] = $this->parseOperator($operator);
50
51 78
        if (!is_array($values)) {
52 34
            $values = [$values];
53
        }
54
55 78
        if (empty($values)) {
56 16
            return $not ? '' : '0=1';
57
        }
58
59 62
        if ($column instanceof ExpressionInterface) {
60 62
            $column = $this->queryBuilder->buildExpression($column, $params);
61
        } elseif (is_string($column) && strpos($column, '(') === false) {
62
            $column = $this->queryBuilder->getDb()->quoteColumnName($column);
63 62
        }
64 62
65 62
        $escapeSql = $this->getEscapeSql();
66 62
67 24
        $parts = [];
68
        foreach ($values as $value) {
69 50
            if ($value instanceof ExpressionInterface) {
70 50
                $phName = $this->queryBuilder->buildExpression($value, $params);
71
            } else {
72 62
                $phName = $this->queryBuilder->bindParam(
73
                    empty($escape) ? $value : ('%' . strtr($value, $escape) . '%'),
74
                    $params
75 62
                );
76
            }
77
            $parts[] = "{$column} {$operator} {$phName}{$escapeSql}";
78
        }
79
80
        return implode($andor, $parts);
81
    }
82
83 62
    /**
84
     * @var string|null character used to escape special characters in LIKE conditions.
85 62
     *
86 18
     * By default it's assumed to be `\`.
87
     */
88
    private function getEscapeSql(): ?string
89 44
    {
90
        if ($this->escapeCharacter !== null) {
91
            return " ESCAPE '{$this->escapeCharacter}'";
92
        }
93
94
        return '';
95
    }
96
97 78
    /**
98
     * @param string $operator
99 78
     *
100
     * @return array
101
     */
102 78
    protected function parseOperator($operator): array
103 78
    {
104 78
        if (!preg_match('/^(AND |OR |)(((NOT |))I?LIKE)/', $operator, $matches)) {
105
            throw new InvalidArgumentException("Invalid operator '$operator'.");
106 78
        }
107
108
        $andor = ' ' . (!empty($matches[1]) ? $matches[1] : 'AND ');
109 1
        $not = !empty($matches[3]);
110
        $operator = $matches[2];
111
112
        return [$andor, $not, $operator];
113
    }
114
}
115