Passed
Pull Request — master (#288)
by
unknown
04:00
created

ColumnSchema::dbTypecast()   A

Complexity

Conditions 6
Paths 3

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 6
eloc 13
c 5
b 0
f 0
nc 3
nop 1
dl 0
loc 19
ccs 14
cts 14
cp 1
crap 6
rs 9.2222
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 bindec;
18
use function decbin;
19
use function is_array;
20
use function is_int;
21
use function is_string;
22
use function json_decode;
23
use function str_pad;
24
25
/**
26
 * Represents the metadata of a column in a database table for PostgreSQL Server.
27
 *
28
 * It provides information about the column's name, type, size, precision, and other details.
29
 *
30
 * It's used to store and retrieve metadata about a column in a database table and is typically used in conjunction with
31
 * the {@see TableSchema}, which represents the metadata of a database table as a whole.
32
 *
33
 * The following code shows how to use:
34
 *
35
 * ```php
36
 * use Yiisoft\Db\Pgsql\ColumnSchema;
37
 *
38
 * $column = new ColumnSchema();
39
 * $column->name('id');
40
 * $column->allowNull(false);
41
 * $column->dbType('integer');
42
 * $column->phpType('integer');
43
 * $column->type('integer');
44
 * $column->defaultValue(0);
45
 * $column->autoIncrement(true);
46
 * $column->primaryKey(true);
47
 * ```
48
 */
49
final class ColumnSchema extends AbstractColumnSchema
50
{
51
    /**
52
     * @var int The dimension of array. Defaults to 0, means this column isn't an array.
53
     */
54
    private int $dimension = 0;
55
56
    /**
57
     * @var string|null Name of an associated sequence if column is auto incremental.
58
     */
59
    private string|null $sequenceName = null;
60
61
    /**
62
     * Converts the input value according to {@see type} and {@see dbType} for use in a db query.
63
     *
64
     * If the value is null or an {@see Expression}, it won't be converted.
65
     *
66
     * @param mixed $value input value
67
     *
68
     * @return mixed Converted value. This may also be an array containing the value as the first element and the PDO
69
     * type as the second element.
70
     */
71 87
    public function dbTypecast(mixed $value): mixed
72
    {
73 87
        if ($value === null || $value instanceof ExpressionInterface) {
74 30
            return $value;
75
        }
76
77 82
        if ($this->dimension > 0) {
78 2
            return new ArrayExpression($value, $this->getDbType(), $this->dimension);
79
        }
80
81 81
        return match ($this->getType()) {
82 81
            SchemaInterface::TYPE_JSON => new JsonExpression($value, $this->getDbType()),
83 81
            SchemaInterface::TYPE_BINARY => is_string($value)
84 3
                ? new Param($value, PDO::PARAM_LOB) // explicitly setup PDO param type for binary column
85 3
                : $this->typecast($value),
86 81
            Schema::TYPE_BIT => is_int($value)
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Pgsql\Schema was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
87 1
                ? str_pad(decbin($value), (int) $this->getSize(), '0', STR_PAD_LEFT)
88 1
                : $this->typecast($value),
89 81
            default => $this->typecast($value),
90 81
        };
91
    }
92
93
    /**
94
     * Converts the input value according to {@see phpType} after retrieval from the database.
95
     *
96
     * If the value is null or an {@see Expression}, it won't be converted.
97
     *
98
     * @param mixed $value The input value
99
     *
100
     * @throws JsonException
101
     *
102
     * @return mixed The converted value
103
     */
104 94
    public function phpTypecast(mixed $value): mixed
105
    {
106 94
        if ($this->dimension > 0) {
107 10
            if (is_string($value)) {
108 10
                $value = $this->getArrayParser()->parse($value);
109
            }
110
111 10
            if (is_array($value)) {
112 10
                array_walk_recursive($value, function (string|null &$val) {
113
                    /** @psalm-var mixed $val */
114 10
                    $val = $this->phpTypecastValue($val);
115 10
                });
116
            } else {
117 1
                return null;
118
            }
119
120 10
            return $value;
121
        }
122
123 88
        return $this->phpTypecastValue($value);
124
    }
125
126
    /**
127
     * Casts $value after retrieving from the DBMS to PHP representation.
128
     *
129
     * @throws JsonException
130
     */
131 94
    protected function phpTypecastValue(mixed $value): mixed
132
    {
133 94
        if ($value === null) {
134 9
            return null;
135
        }
136
137 94
        return match ($this->getType()) {
138 94
            Schema::TYPE_BIT => is_string($value) ? bindec($value) : $value,
139 94
            SchemaInterface::TYPE_BOOLEAN
140 94
                => match ($value) {
141 94
                    't' => true,
142 94
                    'f' => false,
143 94
                    default => (bool) $value,
144 94
                },
145 94
            SchemaInterface::TYPE_JSON
146 94
                => json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR),
147 94
            default => parent::phpTypecast($value),
148 94
        };
149
    }
150
151
    /**
152
     * Creates instance of ArrayParser.
153
     */
154 10
    protected function getArrayParser(): ArrayParser
155
    {
156 10
        return new ArrayParser();
157
    }
158
159
    /**
160
     * @return int Get the dimension of the array.
161
     *
162
     * Defaults to 0, means this column isn't an array.
163
     */
164 1
    public function getDimension(): int
165
    {
166 1
        return $this->dimension;
167
    }
168
169
    /**
170
     * @return string|null name of an associated sequence if column is auto incremental.
171
     */
172 97
    public function getSequenceName(): string|null
173
    {
174 97
        return $this->sequenceName;
175
    }
176
177
    /**
178
     * Set dimension of an array.
179
     *
180
     * Defaults to 0, means this column isn't an array.
181
     */
182 156
    public function dimension(int $dimension): void
183
    {
184 156
        $this->dimension = $dimension;
185
    }
186
187
    /**
188
     * Set the name of an associated sequence if a column is auto incremental.
189
     */
190 82
    public function sequenceName(string|null $sequenceName): void
191
    {
192 82
        $this->sequenceName = $sequenceName;
193
    }
194
}
195