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\Driver; |
||||
13 | |||||
14 | use Cycle\Database\Exception\DBALException; |
||||
15 | use Cycle\Database\Exception\DriverException; |
||||
16 | use Cycle\Database\Exception\HandlerException; |
||||
17 | use Cycle\Database\Exception\StatementException; |
||||
18 | use Cycle\Database\Schema\AbstractColumn; |
||||
0 ignored issues
–
show
|
|||||
19 | use Cycle\Database\Schema\AbstractForeignKey; |
||||
20 | use Cycle\Database\Schema\AbstractIndex; |
||||
21 | use Cycle\Database\Schema\AbstractTable; |
||||
22 | use Cycle\Database\Schema\ComparatorInterface; |
||||
23 | use Cycle\Database\Schema\ElementInterface; |
||||
24 | |||||
25 | abstract class Handler implements HandlerInterface |
||||
26 | { |
||||
27 | protected ?DriverInterface $driver = null; |
||||
28 | |||||
29 | 76 | public function withDriver(DriverInterface $driver): HandlerInterface |
|||
30 | { |
||||
31 | 76 | $handler = clone $this; |
|||
32 | 76 | $handler->driver = $driver; |
|||
33 | |||||
34 | 76 | return $handler; |
|||
35 | } |
||||
36 | |||||
37 | /** |
||||
38 | * Associated driver. |
||||
39 | */ |
||||
40 | public function getDriver(): DriverInterface |
||||
41 | { |
||||
42 | return $this->driver; |
||||
0 ignored issues
–
show
|
|||||
43 | } |
||||
44 | |||||
45 | 1948 | public function createTable(AbstractTable $table): void |
|||
46 | { |
||||
47 | 1948 | $this->run($this->createStatement($table)); |
|||
48 | |||||
49 | //Not all databases support adding index while table creation, so we can do it after |
||||
50 | 1942 | foreach ($table->getIndexes() as $index) { |
|||
51 | 282 | $this->createIndex($table, $index); |
|||
52 | } |
||||
53 | 1942 | } |
|||
54 | |||||
55 | 1930 | public function dropTable(AbstractTable $table): void |
|||
56 | { |
||||
57 | 1930 | $this->run( |
|||
58 | 1930 | "DROP TABLE {$this->identify($table->getInitialName())}", |
|||
59 | ); |
||||
60 | 1930 | } |
|||
61 | |||||
62 | 538 | public function syncTable(AbstractTable $table, int $operation = self::DO_ALL): void |
|||
63 | { |
||||
64 | 538 | $comparator = $table->getComparator(); |
|||
65 | |||||
66 | 538 | $comparator->isPrimaryChanged() and throw new DBALException('Unable to change primary keys for existed table'); |
|||
67 | |||||
68 | 538 | if ($operation & self::DO_RENAME && $comparator->isRenamed()) { |
|||
69 | 8 | $this->renameTable($table->getInitialName(), $table->getFullName()); |
|||
70 | } |
||||
71 | |||||
72 | /* |
||||
73 | * This is schema synchronization code, if you are reading it you are either experiencing |
||||
74 | * VERY weird bug, or you are very curious. Please contact me in a any scenario :) |
||||
75 | */ |
||||
76 | 538 | $this->executeChanges($table, $operation, $comparator); |
|||
77 | 538 | } |
|||
78 | |||||
79 | /** |
||||
80 | * @psalm-param non-empty-string $table |
||||
81 | * @psalm-param non-empty-string $name |
||||
82 | */ |
||||
83 | 122 | public function renameTable(string $table, string $name): void |
|||
84 | { |
||||
85 | 122 | $this->run( |
|||
86 | 122 | "ALTER TABLE {$this->identify($table)} RENAME TO {$this->identify($name)}", |
|||
87 | ); |
||||
88 | 122 | } |
|||
89 | |||||
90 | 80 | public function createColumn(AbstractTable $table, AbstractColumn $column): void |
|||
91 | { |
||||
92 | 80 | $this->run( |
|||
93 | 80 | "ALTER TABLE {$this->identify($table)} ADD COLUMN {$column->sqlStatement($this->driver)}", |
|||
94 | ); |
||||
95 | 80 | } |
|||
96 | |||||
97 | 24 | public function dropColumn(AbstractTable $table, AbstractColumn $column): void |
|||
98 | { |
||||
99 | 24 | foreach ($column->getConstraints() as $constraint) { |
|||
100 | //We have to erase all associated constraints |
||||
101 | $this->dropConstrain($table, $constraint); |
||||
102 | } |
||||
103 | |||||
104 | 24 | $this->run( |
|||
105 | 24 | "ALTER TABLE {$this->identify($table)} DROP COLUMN {$this->identify($column)}", |
|||
106 | ); |
||||
107 | 24 | } |
|||
108 | |||||
109 | 458 | public function createIndex(AbstractTable $table, AbstractIndex $index): void |
|||
110 | { |
||||
111 | 458 | $this->run("CREATE {$index->sqlStatement($this->driver)}"); |
|||
0 ignored issues
–
show
It seems like
$this->driver can also be of type null ; however, parameter $driver of Cycle\Database\Schema\Ab...ctIndex::sqlStatement() does only seem to accept Cycle\Database\Driver\DriverInterface , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
112 | 458 | } |
|||
113 | |||||
114 | 24 | public function dropIndex(AbstractTable $table, AbstractIndex $index): void |
|||
115 | { |
||||
116 | 24 | $this->run("DROP INDEX {$this->identify($index)}"); |
|||
117 | 24 | } |
|||
118 | |||||
119 | 6 | public function alterIndex( |
|||
120 | AbstractTable $table, |
||||
121 | AbstractIndex $initial, |
||||
122 | AbstractIndex $index, |
||||
123 | ): void { |
||||
124 | 6 | $this->dropIndex($table, $initial); |
|||
125 | 6 | $this->createIndex($table, $index); |
|||
126 | 6 | } |
|||
127 | |||||
128 | 132 | public function createForeignKey(AbstractTable $table, AbstractForeignKey $foreignKey): void |
|||
129 | { |
||||
130 | 132 | $this->run( |
|||
131 | 132 | "ALTER TABLE {$this->identify($table)} ADD {$foreignKey->sqlStatement($this->driver)}", |
|||
0 ignored issues
–
show
It seems like
$this->driver can also be of type null ; however, parameter $driver of Cycle\Database\Schema\Ab...eignKey::sqlStatement() does only seem to accept Cycle\Database\Driver\DriverInterface , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
132 | ); |
||||
133 | 132 | } |
|||
134 | |||||
135 | 112 | public function dropForeignKey(AbstractTable $table, AbstractForeignKey $foreignKey): void |
|||
136 | { |
||||
137 | 112 | $this->dropConstrain($table, $foreignKey->getName()); |
|||
138 | 112 | } |
|||
139 | |||||
140 | 42 | public function alterForeignKey( |
|||
141 | AbstractTable $table, |
||||
142 | AbstractForeignKey $initial, |
||||
143 | AbstractForeignKey $foreignKey, |
||||
144 | ): void { |
||||
145 | 42 | $this->dropForeignKey($table, $initial); |
|||
146 | 42 | $this->createForeignKey($table, $foreignKey); |
|||
147 | 42 | } |
|||
148 | |||||
149 | 130 | public function dropConstrain(AbstractTable $table, string $constraint): void |
|||
150 | { |
||||
151 | 130 | $this->run( |
|||
152 | 130 | "ALTER TABLE {$this->identify($table)} DROP CONSTRAINT {$this->identify($constraint)}", |
|||
153 | ); |
||||
154 | 130 | } |
|||
155 | |||||
156 | /** |
||||
157 | * @psalm-return non-empty-string |
||||
158 | */ |
||||
159 | 1948 | protected function createStatement(AbstractTable $table): string |
|||
160 | { |
||||
161 | 1948 | $statement = ["CREATE TABLE {$this->identify($table)} ("]; |
|||
162 | 1948 | $innerStatement = []; |
|||
163 | |||||
164 | //Columns |
||||
165 | 1948 | foreach ($table->getColumns() as $column) { |
|||
166 | 1948 | $this->assertValid($column); |
|||
167 | 1944 | $innerStatement[] = $column->sqlStatement($this->driver); |
|||
168 | } |
||||
169 | |||||
170 | //Primary key |
||||
171 | 1944 | if ($table->getPrimaryKeys() !== []) { |
|||
172 | 1380 | $primaryKeys = \array_map([$this, 'identify'], $table->getPrimaryKeys()); |
|||
173 | |||||
174 | 1380 | $innerStatement[] = 'PRIMARY KEY (' . \implode(', ', $primaryKeys) . ')'; |
|||
175 | } |
||||
176 | |||||
177 | //Constraints and foreign keys |
||||
178 | 1944 | foreach ($table->getForeignKeys() as $reference) { |
|||
179 | 134 | $innerStatement[] = $reference->sqlStatement($this->driver); |
|||
180 | } |
||||
181 | |||||
182 | 1944 | $statement[] = ' ' . \implode(",\n ", $innerStatement); |
|||
183 | 1944 | $statement[] = ')'; |
|||
184 | |||||
185 | 1944 | return \implode("\n", $statement); |
|||
186 | } |
||||
187 | |||||
188 | 538 | protected function executeChanges( |
|||
189 | AbstractTable $table, |
||||
190 | int $operation, |
||||
191 | ComparatorInterface $comparator, |
||||
192 | ): void { |
||||
193 | //Remove all non needed table constraints |
||||
194 | 538 | $this->dropConstrains($table, $operation, $comparator); |
|||
195 | |||||
196 | 538 | if ($operation & self::CREATE_COLUMNS) { |
|||
197 | //After drops and before creations we can add new columns |
||||
198 | 470 | $this->createColumns($table, $comparator); |
|||
199 | } |
||||
200 | |||||
201 | 538 | if ($operation & self::ALTER_COLUMNS) { |
|||
202 | //We can alter columns now |
||||
203 | 470 | $this->alterColumns($table, $comparator); |
|||
204 | } |
||||
205 | |||||
206 | //Add new constrains and modify existed one |
||||
207 | 538 | $this->setConstrains($table, $operation, $comparator); |
|||
208 | 538 | } |
|||
209 | |||||
210 | /** |
||||
211 | * Execute statement. |
||||
212 | * |
||||
213 | * @psalm-param non-empty-string $statement |
||||
214 | * |
||||
215 | * @throws HandlerException |
||||
216 | */ |
||||
217 | 1946 | protected function run(string $statement, array $parameters = []): int |
|||
218 | { |
||||
219 | try { |
||||
220 | 1946 | return $this->driver->execute($statement, $parameters); |
|||
0 ignored issues
–
show
The method
execute() 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
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. ![]() |
|||||
221 | 10 | } catch (StatementException $e) { |
|||
222 | 2 | throw new HandlerException($e); |
|||
223 | } |
||||
224 | } |
||||
225 | |||||
226 | /** |
||||
227 | * Create element identifier. |
||||
228 | * |
||||
229 | * @psalm-return non-empty-string |
||||
230 | */ |
||||
231 | 1950 | protected function identify(AbstractTable|ElementInterface|string $element): string |
|||
232 | { |
||||
233 | 1950 | if (\is_string($element)) { |
|||
234 | 1942 | return $this->driver->identifier($element); |
|||
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
![]() |
|||||
235 | } |
||||
236 | |||||
237 | 1950 | if ($element instanceof AbstractTable) { |
|||
238 | 1950 | return $this->driver->identifier($element->getFullName()); |
|||
239 | } |
||||
240 | |||||
241 | 178 | if ($element instanceof ElementInterface) { |
|||
0 ignored issues
–
show
|
|||||
242 | 178 | return $this->driver->identifier($element->getName()); |
|||
243 | } |
||||
244 | |||||
245 | throw new \InvalidArgumentException('Invalid argument type'); |
||||
246 | } |
||||
247 | |||||
248 | 470 | protected function alterForeignKeys(AbstractTable $table, ComparatorInterface $comparator): void |
|||
249 | { |
||||
250 | 470 | foreach ($comparator->alteredForeignKeys() as $pair) { |
|||
251 | /** |
||||
252 | * @var AbstractForeignKey $initial |
||||
253 | * @var AbstractForeignKey $current |
||||
254 | */ |
||||
255 | 42 | [$current, $initial] = $pair; |
|||
256 | |||||
257 | 42 | $this->alterForeignKey($table, $initial, $current); |
|||
258 | } |
||||
259 | 470 | } |
|||
260 | |||||
261 | 496 | protected function createForeignKeys(AbstractTable $table, ComparatorInterface $comparator): void |
|||
262 | { |
||||
263 | 496 | foreach ($comparator->addedForeignKeys() as $foreign) { |
|||
264 | 90 | $this->createForeignKey($table, $foreign); |
|||
265 | } |
||||
266 | 496 | } |
|||
267 | |||||
268 | 470 | protected function alterIndexes(AbstractTable $table, ComparatorInterface $comparator): void |
|||
269 | { |
||||
270 | 470 | foreach ($comparator->alteredIndexes() as $pair) { |
|||
271 | /** |
||||
272 | * @var AbstractIndex $initial |
||||
273 | * @var AbstractIndex $current |
||||
274 | */ |
||||
275 | 8 | [$current, $initial] = $pair; |
|||
276 | |||||
277 | 8 | $this->alterIndex($table, $initial, $current); |
|||
278 | } |
||||
279 | 470 | } |
|||
280 | |||||
281 | 470 | protected function createIndexes(AbstractTable $table, ComparatorInterface $comparator): void |
|||
282 | { |
||||
283 | 470 | foreach ($comparator->addedIndexes() as $index) { |
|||
284 | 180 | $this->createIndex($table, $index); |
|||
285 | } |
||||
286 | 470 | } |
|||
287 | |||||
288 | 470 | protected function alterColumns(AbstractTable $table, ComparatorInterface $comparator): void |
|||
289 | { |
||||
290 | 470 | foreach ($comparator->alteredColumns() as $pair) { |
|||
291 | /** |
||||
292 | * @var AbstractColumn $initial |
||||
293 | * @var AbstractColumn $current |
||||
294 | */ |
||||
295 | 116 | [$current, $initial] = $pair; |
|||
296 | |||||
297 | 116 | $this->assertValid($current); |
|||
298 | 116 | $this->alterColumn($table, $initial, $current); |
|||
299 | } |
||||
300 | 470 | } |
|||
301 | |||||
302 | 470 | protected function createColumns(AbstractTable $table, ComparatorInterface $comparator): void |
|||
303 | { |
||||
304 | 470 | foreach ($comparator->addedColumns() as $column) { |
|||
305 | 120 | $this->assertValid($column); |
|||
306 | 120 | $this->createColumn($table, $column); |
|||
307 | } |
||||
308 | 470 | } |
|||
309 | |||||
310 | 470 | protected function dropColumns(AbstractTable $table, ComparatorInterface $comparator): void |
|||
311 | { |
||||
312 | 470 | foreach ($comparator->droppedColumns() as $column) { |
|||
313 | 24 | $this->dropColumn($table, $column); |
|||
314 | } |
||||
315 | 470 | } |
|||
316 | |||||
317 | 484 | protected function dropIndexes(AbstractTable $table, ComparatorInterface $comparator): void |
|||
318 | { |
||||
319 | 484 | foreach ($comparator->droppedIndexes() as $index) { |
|||
320 | 40 | $this->dropIndex($table, $index); |
|||
321 | } |
||||
322 | 484 | } |
|||
323 | |||||
324 | 538 | protected function dropForeignKeys(AbstractTable $table, ComparatorInterface $comparator): void |
|||
325 | { |
||||
326 | 538 | foreach ($comparator->droppedForeignKeys() as $foreign) { |
|||
327 | 168 | $this->dropForeignKey($table, $foreign); |
|||
328 | } |
||||
329 | 538 | } |
|||
330 | |||||
331 | /** |
||||
332 | * Applied to every column in order to make sure that driver support it. |
||||
333 | * |
||||
334 | * @throws DriverException |
||||
335 | */ |
||||
336 | 1472 | protected function assertValid(AbstractColumn $column): void |
|||
337 | { |
||||
338 | //All valid by default |
||||
339 | 1472 | } |
|||
340 | |||||
341 | 538 | protected function dropConstrains( |
|||
342 | AbstractTable $table, |
||||
343 | int $operation, |
||||
344 | ComparatorInterface $comparator, |
||||
345 | ): void { |
||||
346 | 538 | if ($operation & self::DROP_FOREIGN_KEYS) { |
|||
347 | 538 | $this->dropForeignKeys($table, $comparator); |
|||
348 | } |
||||
349 | |||||
350 | 538 | if ($operation & self::DROP_INDEXES) { |
|||
351 | 484 | $this->dropIndexes($table, $comparator); |
|||
352 | } |
||||
353 | |||||
354 | 538 | if ($operation & self::DROP_COLUMNS) { |
|||
355 | 470 | $this->dropColumns($table, $comparator); |
|||
356 | } |
||||
357 | 538 | } |
|||
358 | |||||
359 | 538 | protected function setConstrains( |
|||
360 | AbstractTable $table, |
||||
361 | int $operation, |
||||
362 | ComparatorInterface $comparator, |
||||
363 | ): void { |
||||
364 | 538 | if ($operation & self::CREATE_INDEXES) { |
|||
365 | 470 | $this->createIndexes($table, $comparator); |
|||
366 | } |
||||
367 | |||||
368 | 538 | if ($operation & self::ALTER_INDEXES) { |
|||
369 | 470 | $this->alterIndexes($table, $comparator); |
|||
370 | } |
||||
371 | |||||
372 | 538 | if ($operation & self::CREATE_FOREIGN_KEYS) { |
|||
373 | 496 | $this->createForeignKeys($table, $comparator); |
|||
374 | } |
||||
375 | |||||
376 | 538 | if ($operation & self::ALTER_FOREIGN_KEYS) { |
|||
377 | 470 | $this->alterForeignKeys($table, $comparator); |
|||
378 | } |
||||
379 | 538 | } |
|||
380 | } |
||||
381 |
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:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths