Passed
Push — master ( be06f7...c027e3 )
by Wilmer
08:58 queued 06:59
created

LikeConditionBuilder   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 98
Duplicated Lines 0 %

Test Coverage

Coverage 97.22%

Importance

Changes 0
Metric Value
eloc 42
dl 0
loc 98
ccs 35
cts 36
cp 0.9722
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 136
    public function build(ExpressionInterface $expression, array &$params = []): string
39
    {
40 136
        $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 136
        $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 136
        $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 136
        $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 136
        if ($escape === null || $escape === []) {
46 132
            $escape = $this->escapingReplacements;
47
        }
48
49 136
        [$andor, $not, $operator] = $this->parseOperator($operator);
50
51 136
        if (!is_array($values)) {
52 64
            $values = [$values];
53
        }
54
55 136
        if (empty($values)) {
56 20
            return $not ? '' : '0=1';
57
        }
58
59 116
        if ($column instanceof ExpressionInterface) {
60 4
            $column = $this->queryBuilder->buildExpression($column, $params);
61 112
        } elseif (is_string($column) && strpos($column, '(') === false) {
62 112
            $column = $this->queryBuilder->getDb()->quoteColumnName($column);
0 ignored issues
show
Bug introduced by
The method quoteColumnName() does not exist on Yiisoft\Db\Connection\ConnectionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Db\Connection\ConnectionInterface. ( Ignorable by Annotation )

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

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