Passed
Push — master ( 6ca53f...98da5a )
by Wilmer
02:50
created

ArrayExpression::getType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
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
 * The ArrayExpression class 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. Defaults to `null` which means the type is not explicitly specified.
40
     *
41
     * Note that in case when type is not specified explicitly and DBMS can not guess it from the context, SQL error
42
     * will be raised.
43
     */
44
    public function getType(): string|null
45
    {
46
        return $this->type;
47
    }
48 32
49
    /**
50 32
     * The array's content. In can be represented as an array of values or a {@see QueryInterface} that returns these
51
     * values.
52
     */
53
    public function getValue(): mixed
54
    {
55
        return $this->value;
56
    }
57
58 32
    /**
59
     * @return int The number of indices needed to select an element
60 32
     */
61
    public function getDimension(): int
62
    {
63
        return $this->dimension;
64
    }
65
66 29
    /**
67
     * Whether an offset exists.
68 29
     *
69
     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
70
     *
71
     * @param mixed $offset An offset to check for.
72
     *
73
     * @throws InvalidConfigException If offset is not an integer.
74
     *
75
     * @return bool `true` on success or `false` on failure. The return value will be cast to boolean if non-boolean
76
     * was returned.
77
     */
78
    public function offsetExists(mixed $offset): bool
79
    {
80
        $key = $this->validateKey($offset);
81
        return isset($this->value[$key]);
82
    }
83
84
    /**
85
     * Offset to retrieve.
86
     *
87
     * @link http://php.net/manual/en/arrayaccess.offsetget.php
88
     *
89
     * @param mixed $offset The offset to retrieve.
90
     *
91
     * @throws InvalidConfigException If offset is not an integer.
92
     *
93
     * @return mixed Can return all value types.
94
     */
95
    public function offsetGet(mixed $offset): mixed
96
    {
97
        $key = $this->validateKey($offset);
98
        $this->value = $this->validateValue($this->value);
99
        return $this->value[$key];
100
    }
101
102
    /**
103
     * Offset to set.
104
     *
105
     * @link http://php.net/manual/en/arrayaccess.offsetset.php
106
     *
107
     * @param mixed $offset The offset to assign the value to.
108
     * @param mixed $value The value to set.
109
     *
110
     * @throws InvalidConfigException If offset is not an integer.
111
     */
112
    public function offsetSet(mixed $offset, mixed $value): void
113
    {
114
        $key = $this->validateKey($offset);
115
        $this->value = $this->validateValue($this->value);
116
        $this->value[$key] = $value;
117
    }
118
119
    /**
120
     * Offset to unset.
121
     *
122
     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
123
     */
124
    public function offsetUnset(mixed $offset): void
125
    {
126
        $key = $this->validateKey($offset);
127
        $this->value = $this->validateValue($this->value);
128
        unset($this->value[$key]);
129
    }
130
131
    /**
132
     * Count elements of an object.
133
     *
134
     * @link http://php.net/manual/en/countable.count.php
135
     *
136
     * @return int The custom count as an integer.
137
     */
138
    public function count(): int
139
    {
140
        return count((array) $this->value);
141
    }
142
143
    /**
144
     * Retrieve an external iterator.
145
     *
146
     * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
147
     *
148
     * @return ArrayIterator An instance of an object implementing `Iterator` or `Traversable`.
149
     */
150
    public function getIterator(): Traversable
151
    {
152
        $value = $this->validateValue($this->value);
153
        return new ArrayIterator($value);
154
    }
155
156
    /**
157
     * Validates the key of the array expression is an integer.
158
     *
159
     * @throws InvalidConfigException If offset is not an integer.
160
     */
161
    private function validateKey(mixed $key): int
162
    {
163
        if (!is_int($key)) {
164
            throw new InvalidConfigException('The ArrayExpression offset must be an integer.');
165
        }
166
167
        return $key;
168
    }
169
170
    /**
171
     * Validates the value of the array expression is an array.
172
     */
173
    private function validateValue(mixed $value): array
174
    {
175
        if (!is_array($value)) {
176
            throw new InvalidConfigException('The ArrayExpression value must be an array.');
177
        }
178
179
        return $value;
180
    }
181
}
182