Passed
Pull Request — master (#289)
by
unknown
03:30
created

ColumnSchema::getArrayParser()   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 JsonException;
8
use PDO;
9
use Yiisoft\Db\Command\Param;
10
use Yiisoft\Db\Expression\ArrayExpression;
11
use Yiisoft\Db\Expression\ExpressionInterface;
12
use Yiisoft\Db\Expression\JsonExpression;
13
use Yiisoft\Db\Schema\AbstractColumnSchema;
14
use Yiisoft\Db\Schema\SchemaInterface;
15
16
use function array_walk_recursive;
17
use function in_array;
18
use function is_array;
19
use function is_string;
20
use function json_decode;
21
use function strtolower;
22
23
/**
24
 * Represents the metadata of a column in a database table for PostgreSQL Server.
25
 *
26
 * It provides information about the column's name, type, size, precision, and other details.
27
 *
28
 * It's used to store and retrieve metadata about a column in a database table and is typically used in conjunction with
29
 * the {@see TableSchema}, which represents the metadata of a database table as a whole.
30
 *
31
 * The following code shows how to use:
32
 *
33
 * ```php
34
 * use Yiisoft\Db\Pgsql\ColumnSchema;
35
 *
36
 * $column = new ColumnSchema();
37
 * $column->name('id');
38
 * $column->allowNull(false);
39
 * $column->dbType('integer');
40
 * $column->phpType('integer');
41
 * $column->type('integer');
42
 * $column->defaultValue(0);
43
 * $column->autoIncrement(true);
44
 * $column->primaryKey(true);
45
 * ```
46
 */
47
final class ColumnSchema extends AbstractColumnSchema
48
{
49
    /**
50
     * @var int The dimension of array. Defaults to 0, means this column isn't an array.
51
     */
52
    private int $dimension = 0;
53
54
    /**
55
     * @var string|null Name of an associated sequence if column is auto incremental.
56
     */
57
    private string|null $sequenceName = null;
58
59
    /**
60
     * Converts the input value according to {@see type} and {@see dbType} for use in a db query.
61
     *
62
     * If the value is null or an {@see Expression}, it won't be converted.
63
     *
64
     * @param mixed $value input value
65
     *
66
     * @return mixed Converted value. This may also be an array containing the value as the first element and the PDO
67
     * type as the second element.
68
     */
69 85
    public function dbTypecast(mixed $value): mixed
70
    {
71 85
        if ($value === null) {
72 9
            return null;
73
        }
74
75 85
        if ($value instanceof ExpressionInterface) {
76 24
            return $value;
77
        }
78
79 81
        if ($this->dimension > 0) {
80 2
            return new ArrayExpression($value, $this->getDbType(), $this->dimension);
81
        }
82
83 80
        if (in_array($this->getDbType(), [SchemaInterface::TYPE_JSON, SchemaInterface::TYPE_JSONB], true)) {
84 1
            return new JsonExpression($value, $this->getDbType());
85
        }
86
87 80
        if (is_string($value) && $this->getType() === SchemaInterface::TYPE_BINARY) {
88
            /** explicitly setup PDO param type for binary column */
89 3
            return new Param($value, PDO::PARAM_LOB);
90
        }
91
92 80
        return $this->typecast($value);
93
    }
94
95
    /**
96
     * Converts the input value according to {@see phpType} after retrieval from the database.
97
     *
98
     * If the value is null or an {@see Expression}, it won't be converted.
99
     *
100
     * @param mixed $value The input value
101
     *
102
     * @throws JsonException
103
     *
104
     * @return mixed The converted value
105
     */
106 42
    public function phpTypecast(mixed $value): mixed
107
    {
108 42
        if ($this->dimension > 0) {
109 2
            if (is_string($value)) {
110 2
                $value = (new ArrayParser($value))->parse();
111
            }
112
113 2
            if (is_array($value)) {
114 2
                array_walk_recursive($value, function (string|null &$val) {
115
                    /** @psalm-var mixed $val */
116 2
                    $val = $this->phpTypecastValue($val);
117 2
                });
118
            } else {
119 1
                return null;
120
            }
121
122 2
            return $value;
123
        }
124
125 41
        return $this->phpTypecastValue($value);
126
    }
127
128
    /**
129
     * Casts $value after retrieving from the DBMS to PHP representation.
130
     *
131
     * @throws JsonException
132
     */
133 42
    protected function phpTypecastValue(mixed $value): mixed
134
    {
135 42
        if ($value === null) {
136 1
            return null;
137
        }
138
139 42
        switch ($this->getType()) {
140
            case SchemaInterface::TYPE_BOOLEAN:
141
                /** @psalm-var mixed $value */
142 2
                $value = is_string($value) ? strtolower($value) : $value;
143
144 2
                return match ($value) {
145 2
                    't', 'true' => true,
146 2
                    'f', 'false' => false,
147 2
                    default => (bool)$value,
148 2
                };
149
            case SchemaInterface::TYPE_JSON:
150 32
                return json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR);
151
        }
152
153 41
        return parent::phpTypecast($value);
154
    }
155
156
    /**
157
     * @return int Get the dimension of the array.
158
     *
159
     * Defaults to 0, means this column isn't an array.
160
     */
161 1
    public function getDimension(): int
162
    {
163 1
        return $this->dimension;
164
    }
165
166
    /**
167
     * @return string|null name of an associated sequence if column is auto incremental.
168
     */
169 96
    public function getSequenceName(): string|null
170
    {
171 96
        return $this->sequenceName;
172
    }
173
174
    /**
175
     * Set dimension of an array.
176
     *
177
     * Defaults to 0, means this column isn't an array.
178
     */
179 154
    public function dimension(int $dimension): void
180
    {
181 154
        $this->dimension = $dimension;
182
    }
183
184
    /**
185
     * Set the name of an associated sequence if a column is auto incremental.
186
     */
187 81
    public function sequenceName(string|null $sequenceName): void
188
    {
189 81
        $this->sequenceName = $sequenceName;
190
    }
191
}
192