Passed
Push — master ( e6cfe3...1d57d1 )
by Def
17:23 queued 13:56
created

ColumnSchema::dbTypecast()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 24
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 11
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 24
ccs 12
cts 12
cp 1
crap 7
rs 8.8333
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\ColumnSchema as AbstractColumnSchema;
14
use Yiisoft\Db\Schema\Schema as AbstractSchema;
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
 * The class ColumnSchema for PostgreSQL database.
25
 */
26
final class ColumnSchema extends AbstractColumnSchema
27
{
28
    /**
29
     * @var int the dimension of array. Defaults to 0, means this column is not an array.
30
     */
31
    private int $dimension = 0;
32
33
    /**
34
     * @var string|null name of associated sequence if column is auto-incremental.
35
     */
36
    private string|null $sequenceName = null;
37
38
    /**
39
     * Converts the input value according to {@see type} and {@see dbType} for use in a db query.
40
     *
41
     * If the value is null or an {@see Expression}, it will not be converted.
42
     *
43
     * @param mixed $value input value
44
     *
45
     * @return mixed converted value. This may also be an array containing the value as the first element and the PDO
46
     * type as the second element.
47
     */
48 77
    public function dbTypecast(mixed $value): mixed
49
    {
50 77
        if ($value === null) {
51 9
            return null;
52
        }
53
54 77
        if ($value instanceof ExpressionInterface) {
55 24
            return $value;
56
        }
57
58 73
        if ($this->dimension > 0) {
59 1
            return new ArrayExpression($value, $this->getDbType(), $this->dimension);
60
        }
61
62 73
        if (in_array($this->getDbType(), [AbstractSchema::TYPE_JSON, Schema::TYPE_JSONB], true)) {
63 1
            return new JsonExpression($value, $this->getDbType());
64
        }
65
66 73
        if ($this->getType() === Schema::TYPE_BINARY && is_string($value)) {
67
            /** explicitly setup PDO param type for binary column */
68 3
            return new Param($value, PDO::PARAM_LOB);
69
        }
70
71 73
        return $this->typecast($value);
72
    }
73
74
    /**
75
     * Converts the input value according to {@see phpType} after retrieval from the database.
76
     *
77
     * If the value is null or an {@see Expression}, it will not be converted.
78
     *
79
     * @param mixed $value input value
80
     *
81
     *@throws JsonException
82
     *
83
     * @return mixed converted value
84
     */
85 37
    public function phpTypecast(mixed $value): mixed
86
    {
87 37
        if ($this->dimension > 0) {
88 1
            if (!is_array($value) && (is_string($value) || $value === null)) {
89 1
                $value = $this->getArrayParser()->parse($value);
90
            }
91
92 1
            if (is_array($value)) {
93 1
                array_walk_recursive($value, function (string|null &$val) {
94
                    /** @var mixed */
95 1
                    $val = $this->phpTypecastValue($val);
96 1
                });
97
            } else {
98 1
                return null;
99
            }
100
101 1
            return $value;
102
        }
103
104 37
        return $this->phpTypecastValue($value);
105
    }
106
107
    /**
108
     * Casts $value after retrieving from the DBMS to PHP representation.
109
     *
110
     * @throws JsonException
111
     */
112 37
    protected function phpTypecastValue(mixed $value): mixed
113
    {
114 37
        if ($value === null) {
115 1
            return null;
116
        }
117
118 37
        switch ($this->getType()) {
119
            case AbstractSchema::TYPE_BOOLEAN:
120
                /** @var mixed */
121 2
                $value = is_string($value) ? strtolower($value) : $value;
122
123 2
                return match ($value) {
124 2
                    't', 'true' => true,
125 2
                    'f', 'false' => false,
126 2
                    default => (bool)$value,
127 2
                };
128
            case AbstractSchema::TYPE_JSON:
129 32
                return json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR);
130
        }
131
132 36
        return parent::phpTypecast($value);
133
    }
134
135
    /**
136
     * Creates instance of ArrayParser.
137
     */
138 1
    protected function getArrayParser(): ArrayParser
139
    {
140 1
        return new ArrayParser();
141
    }
142
143
    /**
144
     * @return int Get the dimension of array. Defaults to 0, means this column is not an array.
145
     */
146 1
    public function getDimension(): int
147
    {
148 1
        return $this->dimension;
149
    }
150
151
    /**
152
     * @return string|null name of associated sequence if column is auto-incremental.
153
     */
154 82
    public function getSequenceName(): string|null
155
    {
156 82
        return $this->sequenceName;
157
    }
158
159
    /**
160
     * Set dimension of array. Defaults to 0, means this column is not an array.
161
     */
162 140
    public function dimension(int $dimension): void
163
    {
164 140
        $this->dimension = $dimension;
165
    }
166
167
    /**
168
     * Set name of associated sequence if column is auto-incremental.
169
     */
170 75
    public function sequenceName(string|null $sequenceName): void
171
    {
172 75
        $this->sequenceName = $sequenceName;
173
    }
174
}
175