ArrayExpression   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 156
Duplicated Lines 0 %

Test Coverage

Coverage 35.48%

Importance

Changes 0
Metric Value
eloc 23
dl 0
loc 156
ccs 11
cts 31
cp 0.3548
rs 10
c 0
b 0
f 0
wmc 14

12 Methods

Rating   Name   Duplication   Size   Complexity  
A count() 0 3 1
A getType() 0 3 1
A __construct() 0 2 1
A validateKey() 0 7 2
A offsetSet() 0 5 1
A getValue() 0 3 1
A offsetExists() 0 4 1
A getDimension() 0 3 1
A offsetUnset() 0 5 1
A offsetGet() 0 5 1
A getIterator() 0 4 1
A validateValue() 0 7 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Expression;
6
7
use ArrayAccess;
8
use ArrayIterator;
9
use Countable;
10
use IteratorAggregate;
11
use Traversable;
12
use Yiisoft\Db\Exception\InvalidConfigException;
13
use Yiisoft\Db\Query\QueryInterface;
14
15
use function count;
16
17
/**
18
 * Represents an array SQL expression.
19
 *
20
 * Expressions of this type can be used in conditions as well:
21
 *
22
 * ```php
23
 * $query->andWhere(['@>', 'items', new ArrayExpression([1, 2, 3], 'integer')]);
24
 * ```
25
 *
26
 * Which, depending on DBMS, will result in a well-prepared condition. For example, in PostgresSQL it will be compiled
27
 * to `WHERE "items" @> ARRAY[1, 2, 3]::integer[]`.
28
 *
29 9
 * @template-implements ArrayAccess<int, mixed>
30
 * @template-implements IteratorAggregate<int>
31 9
 */
32 1
class ArrayExpression implements ExpressionInterface, ArrayAccess, Countable, IteratorAggregate
33
{
34
    public function __construct(private mixed $value = [], private string|null $type = null, private int $dimension = 1)
35 9
    {
36 9
    }
37 9
38 9
    /**
39
     * The type of the array elements.
40
     *
41
     * Defaults to `null` which means the type isn't explicitly specified.
42
     *
43
     * Note that in the case where a type isn't specified explicitly and DBMS can't guess it from the context, SQL error
44
     * will be raised.
45
     */
46
    public function getType(): string|null
47
    {
48 32
        return $this->type;
49
    }
50 32
51
    /**
52
     * The array's content. In can be represented as an array of values or a {@see QueryInterface} that returns these
53
     * values.
54
     */
55
    public function getValue(): mixed
56
    {
57
        return $this->value;
58 32
    }
59
60 32
    /**
61
     * @return int The number of indices needed to select an element.
62
     */
63
    public function getDimension(): int
64
    {
65
        return $this->dimension;
66 29
    }
67
68 29
    /**
69
     * Whether an offset exists.
70
     *
71
     * @link https://php.net/manual/en/arrayaccess.offsetexists.php
72
     *
73
     * @param mixed $offset An offset to check for.
74
     *
75
     * @throws InvalidConfigException If offset isn't an integer.
76
     *
77
     * @return bool Its `true` on success or `false` on failure. The return value will be cast to boolean if non-boolean
78
     * was returned.
79
     */
80
    public function offsetExists(mixed $offset): bool
81
    {
82
        $key = $this->validateKey($offset);
83
        return isset($this->value[$key]);
84
    }
85
86
    /**
87
     * Offset to retrieve.
88
     *
89
     * @link https://php.net/manual/en/arrayaccess.offsetget.php
90
     *
91
     * @param mixed $offset The offset to retrieve.
92
     *
93
     * @throws InvalidConfigException If offset isn't an integer.
94
     *
95
     * @return mixed Can return all value types.
96
     */
97
    public function offsetGet(mixed $offset): mixed
98
    {
99
        $key = $this->validateKey($offset);
100
        $this->value = $this->validateValue($this->value);
101
        return $this->value[$key];
102
    }
103
104
    /**
105
     * Offset to set.
106
     *
107
     * @link https://php.net/manual/en/arrayaccess.offsetset.php
108
     *
109
     * @param mixed $offset The offset to assign the value to.
110
     * @param mixed $value The value to set.
111
     *
112
     * @throws InvalidConfigException If offset isn't an integer.
113
     */
114
    public function offsetSet(mixed $offset, mixed $value): void
115
    {
116
        $key = $this->validateKey($offset);
117
        $this->value = $this->validateValue($this->value);
118
        $this->value[$key] = $value;
119
    }
120
121
    /**
122
     * Offset to unset.
123
     *
124
     * @throws InvalidConfigException If offset isn't an integer.
125
     *
126
     * @link https://php.net/manual/en/arrayaccess.offsetunset.php
127
     */
128
    public function offsetUnset(mixed $offset): void
129
    {
130
        $key = $this->validateKey($offset);
131
        $this->value = $this->validateValue($this->value);
132
        unset($this->value[$key]);
133
    }
134
135
    /**
136
     * Count elements of an object.
137
     *
138
     * @link https://php.net/manual/en/countable.count.php
139
     *
140
     * @return int The custom count as an integer.
141
     */
142
    public function count(): int
143
    {
144
        return count((array) $this->value);
145
    }
146
147
    /**
148
     * Retrieve an external iterator.
149
     *
150
     * @link https://php.net/manual/en/iteratoraggregate.getiterator.php
151
     *
152
     * @throws InvalidConfigException If value isn't an array.
153
     *
154
     * @return ArrayIterator An instance of an object implementing `Iterator` or `Traversable`.
155
     */
156
    public function getIterator(): Traversable
157
    {
158
        $value = $this->validateValue($this->value);
159
        return new ArrayIterator($value);
160
    }
161
162
    /**
163
     * Validates the key of the array expression is an integer.
164
     *
165
     * @throws InvalidConfigException If offset isn't an integer.
166
     */
167
    private function validateKey(mixed $key): int
168
    {
169
        if (!is_int($key)) {
170
            throw new InvalidConfigException('The ArrayExpression offset must be an integer.');
171
        }
172
173
        return $key;
174
    }
175
176
    /**
177
     * Validates the value of the array expression is an array.
178
     *
179
     * @throws InvalidConfigException If value isn't an array.
180
     */
181
    private function validateValue(mixed $value): array
182
    {
183
        if (!is_array($value)) {
184
            throw new InvalidConfigException('The ArrayExpression value must be an array.');
185
        }
186
187
        return $value;
188
    }
189
}
190