Passed
Pull Request — master (#303)
by
unknown
03:47
created

CompositeExpression::getType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Pgsql;
6
7
use ArrayAccess;
8
use ArrayIterator;
9
use Countable;
10
use IteratorAggregate;
11
use Yiisoft\Db\Exception\InvalidConfigException;
12
use Yiisoft\Db\Expression\ExpressionInterface;
13
use Yiisoft\Db\Schema\ColumnSchemaInterface;
14
15
use function count;
16
17
/**
18
 * Represents a composite SQL expression.
19
 *
20
 * For example:
21
 *
22
 * ```php
23
 * new CompositeExpression(['price' => 10, 'currency_code' => 'USD']);
24
 * ```
25
 *
26
 * Will be encoded to `ROW(10, USD)`
27
 *
28
 * @template-implements ArrayAccess<string, mixed>
29
 * @template-implements IteratorAggregate<string>
30
 */
31
class CompositeExpression implements ExpressionInterface, ArrayAccess, Countable, IteratorAggregate
32
{
33
    /**
34
     * @param ColumnSchemaInterface[]|null $columns
35
     * @psalm-param array<string, ColumnSchemaInterface>|null $columns
36
     */
37 1
    public function __construct(
38
        private mixed $value = [],
39
        private string|null $type = null,
40
        private array|null $columns = null,
41
    ) {
42 1
    }
43
44
    /**
45
     * The composite type name.
46
     *
47
     * Defaults to `null` which means the type isn't explicitly specified.
48
     *
49
     * Note that in the case where a type isn't specified explicitly and DBMS can't guess it from the context, SQL error
50
     * will be raised.
51
     */
52 1
    public function getType(): string|null
53
    {
54 1
        return $this->type;
55
    }
56
57
    /**
58
     * @return ColumnSchemaInterface[]|null
59
     */
60 1
    public function getColumns(): array|null
61
    {
62 1
        return $this->columns;
63
    }
64
65
    /**
66
     * The composite type's content. It can be represented as an associative array of the composite type's column names
67
     * and values.
68
     */
69 1
    public function getValue(): mixed
70
    {
71 1
        return $this->value;
72
    }
73
74
    /**
75
     * Sort values according to `$columns` order and fill skipped items with default values
76
     */
77 1
    public function getNormalizedValue(): mixed
78
    {
79 1
        if ($this->columns === null || !is_array($this->value) || !is_string(array_key_first($this->value))) {
80
            return $this->value;
81
        }
82
83 1
        $value = [];
84
85 1
        foreach ($this->columns as $name => $column) {
86 1
            if (array_key_exists($name, $this->value)) {
87
                /** @psalm-suppress MixedAssignment */
88 1
                $value[$name] = $this->value[$name];
89
            } else {
90
                /** @psalm-suppress MixedAssignment */
91
                $value[$name] = $column->getDefaultValue();
92
            }
93
        }
94
95 1
        return $value;
96
    }
97
98
    /**
99
     * Whether an offset exists.
100
     *
101
     * @link https://php.net/manual/en/arrayaccess.offsetexists.php
102
     *
103
     * @param int|string $offset An offset to check for.
104
     *
105
     * @throws InvalidConfigException If value is not an array.
106
     * @return bool Its `true` on success or `false` on failure.
107
     */
108
    public function offsetExists(mixed $offset): bool
109
    {
110
        $this->value = $this->validateValue($this->value);
111
        return array_key_exists($offset, $this->value);
112
    }
113
114
    /**
115
     * Offset to retrieve.
116
     *
117
     * @link https://php.net/manual/en/arrayaccess.offsetget.php
118
     *
119
     * @param int|string $offset The offset to retrieve.
120
     *
121
     * @throws InvalidConfigException If value is not an array.
122
     * @return mixed Can return all value types.
123
     */
124
    public function offsetGet(mixed $offset): mixed
125
    {
126
        $this->value = $this->validateValue($this->value);
127
        return $this->value[$offset];
128
    }
129
130
    /**
131
     * Offset to set.
132
     *
133
     * @link https://php.net/manual/en/arrayaccess.offsetset.php
134
     *
135
     * @param int|string $offset The offset to assign the value to.
136
     * @param mixed $value The value to set.
137
     *
138
     * @throws InvalidConfigException If content value is not an array.
139
     */
140
    public function offsetSet(mixed $offset, mixed $value): void
141
    {
142
        $this->value = $this->validateValue($this->value);
143
        $this->value[$offset] = $value;
144
    }
145
146
    /**
147
     * Offset to unset.
148
     *
149
     * @param int|string $offset The offset to unset.
150
     *
151
     * @throws InvalidConfigException If value is not an array.
152
     *
153
     * @link https://php.net/manual/en/arrayaccess.offsetunset.php
154
     */
155
    public function offsetUnset(mixed $offset): void
156
    {
157
        $this->value = $this->validateValue($this->value);
158
        unset($this->value[$offset]);
159
    }
160
161
    /**
162
     * Count elements of the composite type's content.
163
     *
164
     * @link https://php.net/manual/en/countable.count.php
165
     *
166
     * @return int The custom count as an integer.
167
     */
168
    public function count(): int
169
    {
170
        return count((array) $this->value);
171
    }
172
173
    /**
174
     * Retrieve an external iterator.
175
     *
176
     * @link https://php.net/manual/en/iteratoraggregate.getiterator.php
177
     *
178
     * @throws InvalidConfigException If value is not an array.
179
     *
180
     * @return ArrayIterator An instance of an object implementing `Iterator` or `Traversable`.
181
     */
182
    public function getIterator(): ArrayIterator
183
    {
184
        $this->value = $this->validateValue($this->value);
185
        return new ArrayIterator($this->value);
186
    }
187
188
    /**
189
     * Validates the value of the composite expression is an array.
190
     *
191
     * @throws InvalidConfigException If value is not an array.
192
     */
193
    private function validateValue(mixed $value): array
194
    {
195
        if (!is_array($value)) {
196
            throw new InvalidConfigException('The CompositeExpression value must be an array.');
197
        }
198
199
        return $value;
200
    }
201
}
202