Test Failed
Pull Request — master (#315)
by Sergei
03:20
created

ArrayColumnSchema   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 24
eloc 54
c 2
b 0
f 0
dl 0
loc 135
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A dimension() 0 3 1
A dbTypecastArray() 0 27 6
A dbTypecast() 0 13 5
A getDimension() 0 3 1
A phpTypecast() 0 26 6
A getColumn() 0 25 5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Pgsql\Column;
6
7
use Yiisoft\Db\Expression\ArrayExpression;
8
use Yiisoft\Db\Expression\ExpressionInterface;
9
use Yiisoft\Db\Pgsql\ArrayParser;
10
use Yiisoft\Db\Pgsql\Schema;
11
use Yiisoft\Db\Schema\Column\AbstractColumnSchema;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Schema\Column\AbstractColumnSchema 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...
12
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Schema\Column\ColumnSchemaInterface 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...
13
use Yiisoft\Db\Schema\Column\DoubleColumnSchema;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Schema\Column\DoubleColumnSchema 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...
14
use Yiisoft\Db\Schema\Column\JsonColumnSchema;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Schema\Column\JsonColumnSchema 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...
15
use Yiisoft\Db\Schema\Column\StringColumnSchema;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Schema\Column\StringColumnSchema 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...
16
use Yiisoft\Db\Schema\SchemaInterface;
17
18
use function array_map;
19
use function array_walk_recursive;
20
use function is_array;
21
use function is_iterable;
22
use function is_string;
23
24
final class ArrayColumnSchema extends AbstractColumnSchema
25
{
26
    private ColumnSchemaInterface|null $column = null;
27
28
    /**
29
     * @var int The dimension of array, must be greater than 0.
30
     */
31
    private int $dimension = 1;
32
33
    /**
34
     * Set dimension of an array, must be greater than 0.
35
     */
36
    public function dimension(int $dimension): void
37
    {
38
        $this->dimension = $dimension;
39
    }
40
41
    /**
42
     * @return int Get the dimension of the array.
43
     */
44
    public function getDimension(): int
45
    {
46
        return $this->dimension;
47
    }
48
49
    public function dbTypecast(mixed $value): ExpressionInterface|null
50
    {
51
        if ($value === null || $value instanceof ExpressionInterface) {
52
            return $value;
53
        }
54
55
        if ($this->dimension === 1 && is_array($value)) {
56
            $value = array_map([$this->getColumn(), 'dbTypecast'], $value);
57
        } else {
58
            $value = $this->dbTypecastArray($value, $this->dimension);
59
        }
60
61
        return new ArrayExpression($value, $this->getDbType(), $this->dimension);
62
    }
63
64
    public function phpTypecast(mixed $value): array|null
65
    {
66
        if (is_string($value)) {
67
            $value = (new ArrayParser())->parse($value);
68
        }
69
70
        if (!is_array($value)) {
71
            return null;
72
        }
73
74
        if ($this->getType() === SchemaInterface::TYPE_STRING) {
75
            return $value;
76
        }
77
78
        $column = $this->getColumn();
79
80
        if ($this->dimension === 1 && $this->getType() !== SchemaInterface::TYPE_JSON) {
81
            return array_map([$column, 'phpTypecast'], $value);
82
        }
83
84
        array_walk_recursive($value, function (string|null &$val) use ($column): void {
85
            /** @psalm-var mixed $val */
86
            $val = $column->phpTypecast($val);
87
        });
88
89
        return $value;
90
    }
91
92
    /**
93
     * Recursively converts array values for use in a db query.
94
     *
95
     * @param mixed $value The array or iterable object.
96
     * @param int $dimension The array dimension. Should be more than 0.
97
     *
98
     * @return array|null Converted values.
99
     */
100
    private function dbTypecastArray(mixed $value, int $dimension): array|null
101
    {
102
        if ($value === null) {
103
            return null;
104
        }
105
106
        if (!is_iterable($value)) {
107
            return [];
108
        }
109
110
        $items = [];
111
        $column = $this->getColumn();
112
113
        if ($dimension > 1) {
114
            /** @psalm-var mixed $val */
115
            foreach ($value as $val) {
116
                $items[] = $this->dbTypecastArray($val, $dimension - 1);
117
            }
118
        } else {
119
            /** @psalm-var mixed $val */
120
            foreach ($value as $val) {
121
                /** @psalm-var mixed */
122
                $items[] = $column->dbTypecast($val);
123
            }
124
        }
125
126
        return $items;
127
    }
128
129
    /**
130
     * Get an instance of `ColumnSchemaInterface` according to the type of array values for casting type of the values
131
     *
132
     * @return ColumnSchemaInterface
133
     */
134
    private function getColumn(): ColumnSchemaInterface
135
    {
136
        if ($this->column === null) {
137
            if ($this->getType() === Schema::TYPE_BIT) {
138
                $this->column = new BitColumnSchema($this->getName());
139
                $this->column->size($this->getSize());
0 ignored issues
show
Bug introduced by
The method size() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

139
                $this->column->/** @scrutinizer ignore-call */ 
140
                               size($this->getSize());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
140
            } elseif (PHP_INT_SIZE !== 8 && $this->getType() === SchemaInterface::TYPE_BIGINT) {
141
                $this->column = new BigIntColumnSchema($this->getName());
142
            } else {
143
                $this->column = match ($this->getPhpType()) {
144
                    SchemaInterface::PHP_TYPE_INTEGER => new IntegerColumnSchema($this->getName()),
145
                    SchemaInterface::PHP_TYPE_DOUBLE => new DoubleColumnSchema($this->getName()),
146
                    SchemaInterface::PHP_TYPE_BOOLEAN => new BooleanColumnSchema($this->getName()),
147
                    SchemaInterface::PHP_TYPE_RESOURCE => new BinaryColumnSchema($this->getName()),
148
                    SchemaInterface::PHP_TYPE_ARRAY => new JsonColumnSchema($this->getName()),
149
                    default => new StringColumnSchema($this->getName()),
150
                };
151
            }
152
153
            $this->column->dbType($this->getDbType());
154
            $this->column->type($this->getType());
155
            $this->column->phpType($this->getPhpType());
156
        }
157
158
        return $this->column;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->column could return the type null which is incompatible with the type-hinted return Yiisoft\Db\Schema\Column\ColumnSchemaInterface. Consider adding an additional type-check to rule them out.
Loading history...
159
    }
160
}
161