Issues (265)

src/Schema/AbstractIndex.php (3 issues)

1
<?php
2
3
/**
4
 * This file is part of Cycle ORM package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Database\Schema;
13
14
use Cycle\Database\Driver\DriverInterface;
15
use Cycle\Database\IndexInterface;
16
use Cycle\Database\Schema\Traits\ElementTrait;
17
18
/**
19
 * Abstract index schema with read (see IndexInterface) and write abilities. Must be implemented
20
 * by driver to support DBMS specific syntax and creation rules.
21
 */
22
abstract class AbstractIndex implements IndexInterface, ElementInterface
23
{
24
    use ElementTrait;
25
26
    /**
27
     * Index types.
28
     */
29
    public const NORMAL = 'INDEX';
30
31
    public const UNIQUE = 'UNIQUE';
32
33
    /**
34
     * Index type, by default NORMAL and UNIQUE indexes supported, additional types can be
35
     * implemented on database driver level.
36
     */
37
    protected string $type = self::NORMAL;
38
39
    /**
40
     * Columns used to form index.
41
     */
42
    protected array $columns = [];
43
44
    /**
45
     * Columns mapping to sorting order
46
     */
47
    protected array $sort = [];
48
49
    /**
50
     * @psalm-param non-empty-string $table
51
     * @psalm-param non-empty-string $name
52 708
     */
53
    public function __construct(
54
        protected string $table,
55
        protected string $name,
56 708
    ) {}
57
58 458
    /**
59
     * Parse column name and order from column expression
60 458
     */
61
    public static function parseColumn(array|string $column): array
62
    {
63 680
        if (\is_array($column)) {
0 ignored issues
show
The condition is_array($column) is always true.
Loading history...
64
            return $column;
65 680
        }
66
67
        // Contains ASC
68
        if (\str_ends_with($column, ' ASC')) {
69
            return [
70
                \substr($column, 0, -4),
71
                'ASC',
72
            ];
73
        }
74
75
        if (\str_ends_with($column, ' DESC')) {
76 458
            return [
77
                \substr($column, 0, -5),
78 458
                'DESC',
79 458
            ];
80 458
        }
81 458
82
        return [
83
            $column,
84
            null,
85
        ];
86
    }
87
88 210
    public function isUnique(): bool
89
    {
90 210
        return $this->type === self::UNIQUE;
91
    }
92 210
93
    public function getColumns(): array
94
    {
95
        return $this->columns;
96
    }
97
98
    public function getSort(): array
99
    {
100
        return $this->sort;
101
    }
102
103
    /**
104
     * Will return columns list with their corresponding order expressions
105
     */
106
    public function getColumnsWithSort(): array
107 458
    {
108
        $self = $this;
109 458
        return \array_map(
110
            static fn(string $column): string => ($order = $self->sort[$column] ?? null) ? "$column $order" : $column,
111
            $this->columns,
112
        );
113 458
    }
114
115 458
    /**
116
     * Declare index type and behaviour to unique/non-unique state.
117
     */
118
    public function unique(bool $unique = true): self
119
    {
120
        $this->type = $unique ? self::UNIQUE : self::NORMAL;
121
122
        return $this;
123
    }
124
125
    /**
126
     * Change set of index forming columns. Method must support both array and string parameters.
127
     *
128 458
     * Example:
129
     * $index->columns('key');
130 458
     * $index->columns('key', 'key2');
131
     * $index->columns(['key', 'key2']);
132 458
     *
133
     * @param array|string $columns Columns array or comma separated list of parameters.
134
     *
135
     */
136
    public function columns(string|array $columns): self
137
    {
138
        if (!\is_array($columns)) {
0 ignored issues
show
The condition is_array($columns) is always true.
Loading history...
139
            $columns = \func_get_args();
140
        }
141
142
        $this->columns = $columns;
143 344
144
        return $this;
145 344
    }
146
147 344
    /**
148
     * Change a columns order mapping if needed.
149 344
     *
150 344
     * Example:
151
     * $index->sort(['key2' => 'DESC']);
152
     *
153
     * @param array $sort Associative array of columns to sort order.
154 344
     *
155 344
     */
156 344
    public function sort(array $sort): self
157 344
    {
158 12
        $this->sort = $sort;
159
160
        return $this;
161 344
    }
162
163 344
    /**
164
     * Index sql creation syntax.
165 344
     *
166
     * @param bool $includeTable Include table ON statement (not required for inline index creation).
167 344
     *
168
     * @psalm-return non-empty-string
169
     */
170 458
    public function sqlStatement(DriverInterface $driver, bool $includeTable = true): string
171
    {
172 458
        $statement = [$this->isUnique() ? 'UNIQUE INDEX' : 'INDEX'];
173
174
        $statement[] = $driver->identifier($this->name);
0 ignored issues
show
The method identifier() does not exist on Cycle\Database\Driver\DriverInterface. It seems like you code against a sub-type of Cycle\Database\Driver\DriverInterface such as Cycle\Database\Driver\Driver. ( Ignorable by Annotation )

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

174
        /** @scrutinizer ignore-call */ 
175
        $statement[] = $driver->identifier($this->name);
Loading history...
175
176
        if ($includeTable) {
177
            $statement[] = "ON {$driver->identifier($this->table)}";
178 706
        }
179
180 706
        //Wrapping column names
181
        $columns = [];
182
        foreach ($this->columns as $column) {
183
            $quoted = $driver->identifier($column);
184
            if ($order = $this->sort[$column] ?? null) {
185 706
                $quoted = "$quoted $order";
186
            }
187
188
            $columns[] = $quoted;
189
        }
190
        $columns = \implode(', ', $columns);
191
192 706
        $statement[] = "({$columns})";
193
194 16
        return \implode(' ', $statement);
195 16
    }
196
197
    public function compare(self $initial): bool
198
    {
199
        return $this == clone $initial;
200 706
    }
201
}
202