1
|
|
|
<?php namespace Limoncello\Data\Migrations; |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Copyright 2015-2017 [email protected] |
5
|
|
|
* |
6
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
7
|
|
|
* you may not use this file except in compliance with the License. |
8
|
|
|
* You may obtain a copy of the License at |
9
|
|
|
* |
10
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0 |
11
|
|
|
* |
12
|
|
|
* Unless required by applicable law or agreed to in writing, software |
13
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, |
14
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15
|
|
|
* See the License for the specific language governing permissions and |
16
|
|
|
* limitations under the License. |
17
|
|
|
*/ |
18
|
|
|
|
19
|
|
|
use Closure; |
20
|
|
|
use Doctrine\DBAL\Connection; |
21
|
|
|
use Doctrine\DBAL\Schema\AbstractSchemaManager; |
22
|
|
|
use Doctrine\DBAL\Schema\Table; |
23
|
|
|
use Doctrine\DBAL\Types\Type; |
24
|
|
|
use Limoncello\Contracts\Data\MigrationInterface; |
25
|
|
|
use Limoncello\Contracts\Data\ModelSchemaInfoInterface; |
26
|
|
|
use Limoncello\Contracts\Data\RelationshipTypes; |
27
|
|
|
use Limoncello\Contracts\Data\TimestampFields; |
28
|
|
|
use Limoncello\Data\Contracts\MigrationContextInterface; |
29
|
|
|
use Psr\Container\ContainerInterface; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @package Limoncello\Data |
33
|
|
|
*/ |
34
|
|
|
trait MigrationTrait |
35
|
|
|
{ |
36
|
|
|
/** |
37
|
|
|
* @var ContainerInterface |
38
|
|
|
*/ |
39
|
|
|
private $container; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @inheritdoc |
43
|
|
|
*/ |
44
|
2 |
|
public function init(ContainerInterface $container): MigrationInterface |
45
|
|
|
{ |
46
|
2 |
|
$this->container = $container; |
47
|
|
|
|
48
|
|
|
/** @var MigrationInterface $self */ |
49
|
2 |
|
$self = $this; |
50
|
|
|
|
51
|
2 |
|
return $self; |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @return ContainerInterface |
56
|
|
|
*/ |
57
|
2 |
|
protected function getContainer(): ContainerInterface |
58
|
|
|
{ |
59
|
2 |
|
return $this->container; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @return Connection |
64
|
|
|
*/ |
65
|
2 |
|
protected function getConnection(): Connection |
66
|
|
|
{ |
67
|
2 |
|
assert($this->getContainer()->has(Connection::class) === true); |
68
|
|
|
|
69
|
2 |
|
return $this->getContainer()->get(Connection::class); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @return ModelSchemaInfoInterface |
74
|
|
|
*/ |
75
|
2 |
|
protected function getModelSchemas(): ModelSchemaInfoInterface |
76
|
|
|
{ |
77
|
2 |
|
assert($this->getContainer()->has(ModelSchemaInfoInterface::class) === true); |
78
|
|
|
|
79
|
2 |
|
return $this->getContainer()->get(ModelSchemaInfoInterface::class); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @return AbstractSchemaManager |
84
|
|
|
*/ |
85
|
2 |
|
protected function getSchemaManager(): AbstractSchemaManager |
86
|
|
|
{ |
87
|
2 |
|
return $this->getConnection()->getSchemaManager(); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @param string $modelClass |
92
|
|
|
* @param Closure[] $expressions |
93
|
|
|
* |
94
|
|
|
* @return Table |
95
|
|
|
*/ |
96
|
2 |
|
protected function createTable(string $modelClass, array $expressions = []): Table |
97
|
|
|
{ |
98
|
2 |
|
$context = new MigrationContext($modelClass, $this->getModelSchemas()); |
99
|
2 |
|
$tableName = $this->getModelSchemas()->getTable($modelClass); |
100
|
2 |
|
$table = new Table($tableName); |
101
|
2 |
|
foreach ($expressions as $expression) { |
102
|
|
|
/** @var Closure $expression */ |
103
|
2 |
|
$expression($table, $context); |
104
|
|
|
} |
105
|
|
|
|
106
|
2 |
|
$this->getSchemaManager()->dropAndCreateTable($table); |
107
|
|
|
|
108
|
2 |
|
return $table; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* @param string $modelClass |
113
|
|
|
* |
114
|
|
|
* @return void |
115
|
|
|
*/ |
116
|
1 |
|
protected function dropTableIfExists(string $modelClass): void |
117
|
|
|
{ |
118
|
1 |
|
$tableName = $this->getModelSchemas()->getTable($modelClass); |
119
|
1 |
|
$schemaManager = $this->getSchemaManager(); |
120
|
|
|
|
121
|
1 |
|
if ($schemaManager->tablesExist([$tableName]) === true) { |
122
|
1 |
|
$schemaManager->dropTable($tableName); |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* @param string $name |
128
|
|
|
* |
129
|
|
|
* @return Closure |
130
|
|
|
*/ |
131
|
|
|
protected function primaryInt(string $name): Closure |
132
|
|
|
{ |
133
|
2 |
|
return function (Table $table) use ($name) { |
134
|
2 |
|
$table->addColumn($name, Type::INTEGER)->setAutoincrement(true)->setUnsigned(true)->setNotnull(true); |
135
|
2 |
|
$table->setPrimaryKey([$name]); |
136
|
2 |
|
}; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* @param string $name |
141
|
|
|
* |
142
|
|
|
* @return Closure |
143
|
|
|
*/ |
144
|
|
View Code Duplication |
protected function primaryString(string $name): Closure |
|
|
|
|
145
|
|
|
{ |
146
|
1 |
|
return function (Table $table, MigrationContextInterface $context) use ($name) { |
147
|
1 |
|
$length = $context->getModelSchemas()->getAttributeLength($context->getModelClass(), $name); |
148
|
1 |
|
$table->addColumn($name, Type::STRING)->setLength($length)->setNotnull(true); |
149
|
1 |
|
$table->setPrimaryKey([$name]); |
150
|
1 |
|
}; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* @param string $name |
155
|
|
|
* @param null|int $default |
156
|
|
|
* |
157
|
|
|
* @return Closure |
158
|
|
|
*/ |
159
|
1 |
|
protected function unsignedInt(string $name, int $default = null): Closure |
160
|
|
|
{ |
161
|
1 |
|
return $this->unsignedIntImpl($name, true, $default); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* @param string $name |
166
|
|
|
* @param null|int $default |
167
|
|
|
* |
168
|
|
|
* @return Closure |
169
|
|
|
*/ |
170
|
1 |
|
protected function nullableUnsignedInt(string $name, int $default = null): Closure |
171
|
|
|
{ |
172
|
1 |
|
return $this->unsignedIntImpl($name, false, $default); |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* @param string $name |
177
|
|
|
* |
178
|
|
|
* @return Closure |
179
|
|
|
*/ |
180
|
|
|
protected function float(string $name): Closure |
181
|
|
|
{ |
182
|
|
|
// precision and scale both seems to be ignored in Doctrine so not much sense to have them as inputs |
183
|
|
|
|
184
|
1 |
|
return function (Table $table) use ($name) { |
185
|
1 |
|
$table->addColumn($name, Type::FLOAT)->setNotnull(true); |
186
|
1 |
|
}; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* @param string $name |
191
|
|
|
* |
192
|
|
|
* @return Closure |
193
|
|
|
*/ |
194
|
|
View Code Duplication |
protected function string(string $name): Closure |
|
|
|
|
195
|
|
|
{ |
196
|
1 |
|
return function (Table $table, MigrationContextInterface $context) use ($name) { |
197
|
1 |
|
$length = $context->getModelSchemas()->getAttributeLength($context->getModelClass(), $name); |
198
|
1 |
|
$table->addColumn($name, Type::STRING)->setLength($length)->setNotnull(true); |
199
|
1 |
|
}; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* @param string $name |
204
|
|
|
* |
205
|
|
|
* @return Closure |
206
|
|
|
*/ |
207
|
|
View Code Duplication |
protected function nullableString(string $name): Closure |
|
|
|
|
208
|
|
|
{ |
209
|
1 |
|
return function (Table $table, MigrationContextInterface $context) use ($name) { |
210
|
1 |
|
$length = $context->getModelSchemas()->getAttributeLength($context->getModelClass(), $name); |
211
|
1 |
|
$table->addColumn($name, Type::STRING)->setLength($length)->setNotnull(false); |
212
|
1 |
|
}; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* @param string $name |
217
|
|
|
* |
218
|
|
|
* @return Closure |
219
|
|
|
*/ |
220
|
|
|
protected function text(string $name): Closure |
221
|
|
|
{ |
222
|
1 |
|
return function (Table $table) use ($name) { |
223
|
1 |
|
$table->addColumn($name, Type::TEXT)->setNotnull(true); |
224
|
1 |
|
}; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* @param string $name |
229
|
|
|
* |
230
|
|
|
* @return Closure |
231
|
|
|
*/ |
232
|
|
|
protected function nullableText(string $name): Closure |
233
|
|
|
{ |
234
|
1 |
|
return function (Table $table) use ($name) { |
235
|
1 |
|
$table->addColumn($name, Type::TEXT)->setNotnull(false); |
236
|
1 |
|
}; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* @param string $name |
241
|
|
|
* @param null|bool $default |
242
|
|
|
* |
243
|
|
|
* @return Closure |
244
|
|
|
*/ |
245
|
|
View Code Duplication |
protected function bool(string $name, $default = null): Closure |
|
|
|
|
246
|
|
|
{ |
247
|
1 |
|
return function (Table $table) use ($name, $default) { |
248
|
1 |
|
$column = $table->addColumn($name, Type::BOOLEAN)->setNotnull(true); |
249
|
1 |
|
if ($default !== null && is_bool($default) === true) { |
250
|
1 |
|
$column->setDefault($default); |
251
|
|
|
} |
252
|
1 |
|
}; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* @param string $name |
257
|
|
|
* @param array $values |
258
|
|
|
* |
259
|
|
|
* @return Closure |
260
|
|
|
*/ |
261
|
1 |
|
protected function enum(string $name, array $values): Closure |
262
|
|
|
{ |
263
|
1 |
|
return $this->enumImpl($name, $values, true); |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* @param string $name |
268
|
|
|
* @param array $values |
269
|
|
|
* |
270
|
|
|
* @return Closure |
271
|
|
|
*/ |
272
|
1 |
|
protected function nullableEnum(string $name, array $values): Closure |
273
|
|
|
{ |
274
|
1 |
|
return $this->enumImpl($name, $values, false); |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
/** |
278
|
|
|
* @return Closure |
279
|
|
|
*/ |
280
|
|
|
protected function timestamps(): Closure |
281
|
|
|
{ |
282
|
1 |
|
return function (Table $table, MigrationContextInterface $context) { |
283
|
1 |
|
$modelClass = $context->getModelClass(); |
284
|
|
|
|
285
|
1 |
|
$createdAt = TimestampFields::FIELD_CREATED_AT; |
286
|
1 |
|
$updatedAt = TimestampFields::FIELD_UPDATED_AT; |
287
|
1 |
|
$deletedAt = TimestampFields::FIELD_DELETED_AT; |
288
|
|
|
|
289
|
|
|
// a list of data columns and `nullable` flag |
290
|
1 |
|
$datesToAdd = []; |
291
|
1 |
|
if ($this->getModelSchemas()->hasAttributeType($modelClass, $createdAt) === true) { |
292
|
1 |
|
$datesToAdd[$createdAt] = true; |
293
|
|
|
} |
294
|
1 |
|
if ($this->getModelSchemas()->hasAttributeType($modelClass, $updatedAt) === true) { |
295
|
1 |
|
$datesToAdd[$updatedAt] = false; |
296
|
|
|
} |
297
|
1 |
|
if ($this->getModelSchemas()->hasAttributeType($modelClass, $deletedAt) === true) { |
298
|
1 |
|
$datesToAdd[$deletedAt] = false; |
299
|
|
|
} |
300
|
|
|
|
301
|
1 |
|
foreach ($datesToAdd as $column => $isNullable) { |
302
|
1 |
|
$table->addColumn($column, Type::DATETIME)->setNotnull($isNullable); |
303
|
|
|
} |
304
|
1 |
|
}; |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
/** |
308
|
|
|
* @param string $name |
309
|
|
|
* |
310
|
|
|
* @return Closure |
311
|
|
|
*/ |
312
|
|
|
protected function datetime(string $name): Closure |
313
|
|
|
{ |
314
|
1 |
|
return function (Table $table) use ($name) { |
315
|
1 |
|
$table->addColumn($name, Type::DATETIME)->setNotnull(true); |
316
|
1 |
|
}; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* @param string $name |
321
|
|
|
* |
322
|
|
|
* @return Closure |
323
|
|
|
*/ |
324
|
|
|
protected function nullableDatetime(string $name): Closure |
325
|
|
|
{ |
326
|
1 |
|
return function (Table $table) use ($name) { |
327
|
1 |
|
$table->addColumn($name, Type::DATETIME)->setNotnull(false); |
328
|
1 |
|
}; |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
/** |
332
|
|
|
* @param string $name |
333
|
|
|
* |
334
|
|
|
* @return Closure |
335
|
|
|
*/ |
336
|
|
|
protected function date(string $name): Closure |
337
|
|
|
{ |
338
|
1 |
|
return function (Table $table) use ($name) { |
339
|
1 |
|
$table->addColumn($name, Type::DATE)->setNotnull(true); |
340
|
1 |
|
}; |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
/** |
344
|
|
|
* @param string $name |
345
|
|
|
* |
346
|
|
|
* @return Closure |
347
|
|
|
*/ |
348
|
|
|
protected function nullableDate(string $name): Closure |
349
|
|
|
{ |
350
|
1 |
|
return function (Table $table) use ($name) { |
351
|
1 |
|
$table->addColumn($name, Type::DATE)->setNotnull(false); |
352
|
1 |
|
}; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* @param string[] $names |
357
|
|
|
* |
358
|
|
|
* @return Closure |
359
|
|
|
*/ |
360
|
|
|
protected function unique(array $names): Closure |
361
|
|
|
{ |
362
|
1 |
|
return function (Table $table) use ($names) { |
363
|
1 |
|
$table->addUniqueIndex($names); |
364
|
1 |
|
}; |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* @param string[] $names |
369
|
|
|
* |
370
|
|
|
* @return Closure |
371
|
|
|
*/ |
372
|
|
|
protected function searchable(array $names): Closure |
373
|
|
|
{ |
374
|
1 |
|
return function (Table $table) use ($names) { |
375
|
1 |
|
$table->addIndex($names, null, ['fulltext']); |
376
|
1 |
|
}; |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
/** |
380
|
|
|
* @param string $column |
381
|
|
|
* @param string $referredClass |
382
|
|
|
* @param bool $cascadeDelete |
383
|
|
|
* |
384
|
|
|
* @return Closure |
385
|
|
|
* |
386
|
|
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag) |
387
|
|
|
*/ |
388
|
|
View Code Duplication |
protected function foreignRelationship( |
|
|
|
|
389
|
|
|
string $column, |
390
|
|
|
string $referredClass, |
391
|
|
|
bool $cascadeDelete = false |
392
|
|
|
): Closure { |
393
|
1 |
|
return function ( |
394
|
|
|
Table $table, |
395
|
|
|
MigrationContextInterface $context |
396
|
|
|
) use ( |
397
|
1 |
|
$column, |
398
|
1 |
|
$referredClass, |
399
|
1 |
|
$cascadeDelete |
400
|
|
|
) { |
401
|
1 |
|
$tableName = $this->getTableNameForClass($referredClass); |
402
|
1 |
|
$pkName = $this->getModelSchemas()->getPrimaryKey($referredClass); |
403
|
1 |
|
$columnType = $this->getModelSchemas()->getAttributeType($context->getModelClass(), $column); |
404
|
|
|
|
405
|
1 |
|
$closure = $this->foreignColumn($column, $tableName, $pkName, $columnType, $cascadeDelete); |
406
|
|
|
|
407
|
1 |
|
return $closure($table, $context); |
408
|
1 |
|
}; |
409
|
|
|
} |
410
|
|
|
|
411
|
|
|
/** |
412
|
|
|
* @param string $column |
413
|
|
|
* @param string $referredClass |
414
|
|
|
* @param bool $cascadeDelete |
415
|
|
|
* |
416
|
|
|
* @return Closure |
417
|
|
|
* |
418
|
|
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag) |
419
|
|
|
*/ |
420
|
|
View Code Duplication |
protected function nullableForeignRelationship( |
|
|
|
|
421
|
|
|
string $column, |
422
|
|
|
string $referredClass, |
423
|
|
|
bool $cascadeDelete = false |
424
|
|
|
): Closure { |
425
|
1 |
|
return function ( |
426
|
|
|
Table $table, |
427
|
|
|
MigrationContextInterface $context |
428
|
|
|
) use ( |
429
|
1 |
|
$column, |
430
|
1 |
|
$referredClass, |
431
|
1 |
|
$cascadeDelete |
432
|
|
|
) { |
433
|
1 |
|
$tableName = $this->getTableNameForClass($referredClass); |
434
|
1 |
|
$pkName = $this->getModelSchemas()->getPrimaryKey($referredClass); |
435
|
1 |
|
$columnType = $this->getModelSchemas()->getAttributeType($context->getModelClass(), $column); |
436
|
|
|
|
437
|
1 |
|
$closure = $this->nullableForeignColumn($column, $tableName, $pkName, $columnType, $cascadeDelete); |
438
|
|
|
|
439
|
1 |
|
return $closure($table, $context); |
440
|
1 |
|
}; |
441
|
|
|
} |
442
|
|
|
|
443
|
|
|
/** |
444
|
|
|
* @param string $localKey |
445
|
|
|
* @param string $foreignTable |
446
|
|
|
* @param string $foreignKey |
447
|
|
|
* @param string $type |
448
|
|
|
* @param bool $cascadeDelete |
449
|
|
|
* |
450
|
|
|
* @return Closure |
451
|
|
|
* |
452
|
|
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag) |
453
|
|
|
*/ |
454
|
1 |
|
protected function foreignColumn( |
455
|
|
|
string $localKey, |
456
|
|
|
string $foreignTable, |
457
|
|
|
string $foreignKey, |
458
|
|
|
string $type, |
459
|
|
|
bool $cascadeDelete = false |
460
|
|
|
): Closure { |
461
|
1 |
|
return $this->foreignColumnImpl($localKey, $foreignTable, $foreignKey, $type, true, $cascadeDelete); |
462
|
|
|
} |
463
|
|
|
|
464
|
|
|
/** |
465
|
|
|
* @param string $localKey |
466
|
|
|
* @param string $foreignTable |
467
|
|
|
* @param string $foreignKey |
468
|
|
|
* @param string $type |
469
|
|
|
* @param bool $cascadeDelete |
470
|
|
|
* |
471
|
|
|
* @return Closure |
472
|
|
|
* |
473
|
|
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag) |
474
|
|
|
*/ |
475
|
1 |
|
protected function nullableForeignColumn( |
476
|
|
|
string $localKey, |
477
|
|
|
string $foreignTable, |
478
|
|
|
string $foreignKey, |
479
|
|
|
string $type, |
480
|
|
|
bool $cascadeDelete = false |
481
|
|
|
): Closure { |
482
|
1 |
|
return $this->foreignColumnImpl($localKey, $foreignTable, $foreignKey, $type, false, $cascadeDelete); |
483
|
|
|
} |
484
|
|
|
|
485
|
|
|
/** |
486
|
|
|
* @param string $name |
487
|
|
|
* @param bool $cascadeDelete |
488
|
|
|
* |
489
|
|
|
* @return Closure |
490
|
|
|
* |
491
|
|
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag) |
492
|
|
|
*/ |
493
|
1 |
|
protected function nullableRelationship(string $name, bool $cascadeDelete = false): Closure |
494
|
|
|
{ |
495
|
1 |
|
return $this->relationshipImpl($name, false, $cascadeDelete); |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
/** |
499
|
|
|
* @param string $name |
500
|
|
|
* @param bool $cascadeDelete |
501
|
|
|
* |
502
|
|
|
* @return Closure |
503
|
|
|
* |
504
|
|
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag) |
505
|
|
|
*/ |
506
|
1 |
|
protected function relationship(string $name, bool $cascadeDelete = false): Closure |
507
|
|
|
{ |
508
|
1 |
|
return $this->relationshipImpl($name, true, $cascadeDelete); |
509
|
|
|
} |
510
|
|
|
|
511
|
|
|
/** |
512
|
|
|
* @param string $modelClass |
513
|
|
|
* |
514
|
|
|
* @return string |
515
|
|
|
*/ |
516
|
1 |
|
protected function getTableNameForClass(string $modelClass): string |
517
|
|
|
{ |
518
|
1 |
|
assert( |
519
|
1 |
|
$this->getModelSchemas()->hasClass($modelClass), |
520
|
1 |
|
"Table name is not specified for model '$modelClass'." |
521
|
|
|
); |
522
|
|
|
|
523
|
1 |
|
$tableName = $this->getModelSchemas()->getTable($modelClass); |
524
|
|
|
|
525
|
1 |
|
return $tableName; |
526
|
|
|
} |
527
|
|
|
|
528
|
|
|
/** |
529
|
|
|
* @param string $name |
530
|
|
|
* @param bool $notNullable |
531
|
|
|
* @param null|mixed $default |
532
|
|
|
* |
533
|
|
|
* @return Closure |
534
|
|
|
*/ |
535
|
|
View Code Duplication |
private function unsignedIntImpl($name, $notNullable, $default = null): Closure |
|
|
|
|
536
|
|
|
{ |
537
|
1 |
|
return function (Table $table) use ($name, $notNullable, $default) { |
538
|
1 |
|
$column = $table->addColumn($name, Type::INTEGER)->setUnsigned(true)->setNotnull($notNullable); |
539
|
1 |
|
$default === null ?: $column->setDefault($default); |
540
|
1 |
|
}; |
541
|
|
|
} |
542
|
|
|
|
543
|
|
|
/** |
544
|
|
|
* @param string $name |
545
|
|
|
* @param array $values |
546
|
|
|
* @param bool $notNullable |
547
|
|
|
* |
548
|
|
|
* @return Closure |
549
|
|
|
* |
550
|
|
|
* @SuppressWarnings(PHPMD.StaticAccess) |
551
|
|
|
*/ |
552
|
|
|
private function enumImpl($name, array $values, $notNullable): Closure |
553
|
|
|
{ |
554
|
1 |
|
return function (Table $table) use ($name, $values, $notNullable) { |
555
|
1 |
|
Type::hasType(EnumType::TYPE_NAME) === true ?: Type::addType(EnumType::TYPE_NAME, EnumType::class); |
556
|
1 |
|
EnumType::setValues($values); |
557
|
1 |
|
$table->addColumn($name, EnumType::TYPE_NAME)->setNotnull($notNullable); |
558
|
1 |
|
}; |
559
|
|
|
} |
560
|
|
|
|
561
|
|
|
/** @noinspection PhpTooManyParametersInspection |
562
|
|
|
* @param string $localKey |
563
|
|
|
* @param string $foreignTable |
564
|
|
|
* @param string $foreignKey |
565
|
|
|
* @param string $type |
566
|
|
|
* @param bool $notNullable |
567
|
|
|
* @param bool $cascadeDelete |
568
|
|
|
* |
569
|
|
|
* @return Closure |
570
|
|
|
*/ |
571
|
|
|
private function foreignColumnImpl( |
572
|
|
|
string $localKey, |
573
|
|
|
string $foreignTable, |
574
|
|
|
string $foreignKey, |
575
|
|
|
string $type, |
576
|
|
|
bool $notNullable, |
577
|
|
|
bool $cascadeDelete |
578
|
|
|
): Closure { |
579
|
1 |
|
return function (Table $table) use ( |
580
|
1 |
|
$localKey, |
581
|
1 |
|
$foreignTable, |
582
|
1 |
|
$foreignKey, |
583
|
1 |
|
$notNullable, |
584
|
1 |
|
$cascadeDelete, |
585
|
1 |
|
$type |
586
|
|
|
) { |
587
|
1 |
|
$options = $cascadeDelete === true ? ['onDelete' => 'CASCADE'] : []; |
588
|
1 |
|
$table->addColumn($localKey, $type)->setUnsigned(true)->setNotnull($notNullable); |
589
|
1 |
|
$table->addForeignKeyConstraint($foreignTable, [$localKey], [$foreignKey], $options); |
590
|
1 |
|
}; |
591
|
|
|
} |
592
|
|
|
|
593
|
|
|
/** |
594
|
|
|
* @param string $name |
595
|
|
|
* @param bool $notNullable |
596
|
|
|
* @param bool $cascadeDelete |
597
|
|
|
* |
598
|
|
|
* @return Closure |
599
|
|
|
*/ |
600
|
|
|
private function relationshipImpl(string $name, bool $notNullable, bool $cascadeDelete): Closure |
601
|
|
|
{ |
602
|
1 |
|
return function ( |
603
|
|
|
Table $table, |
604
|
|
|
MigrationContextInterface $context |
605
|
|
|
) use ( |
606
|
1 |
|
$name, |
607
|
1 |
|
$notNullable, |
608
|
1 |
|
$cascadeDelete |
609
|
|
|
) { |
610
|
1 |
|
$modelClass = $context->getModelClass(); |
611
|
|
|
|
612
|
1 |
|
assert( |
613
|
1 |
|
$this->getModelSchemas()->hasRelationship($modelClass, $name), |
614
|
1 |
|
"Relationship `$name` not found for model `$modelClass`." |
615
|
|
|
); |
616
|
1 |
|
assert( |
617
|
1 |
|
$this->getModelSchemas()->getRelationshipType($modelClass, $name) === RelationshipTypes::BELONGS_TO, |
618
|
1 |
|
"Relationship `$name` for model `$modelClass` must be `belongsTo`." |
619
|
|
|
); |
620
|
|
|
|
621
|
1 |
|
$localKey = $this->getModelSchemas()->getForeignKey($modelClass, $name); |
622
|
1 |
|
$columnType = $this->getModelSchemas()->getAttributeType($modelClass, $localKey); |
623
|
|
|
|
624
|
1 |
|
$otherModelClass = $this->getModelSchemas()->getReverseModelClass($modelClass, $name); |
625
|
1 |
|
$foreignTable = $this->getModelSchemas()->getTable($otherModelClass); |
626
|
1 |
|
$foreignKey = $this->getModelSchemas()->getPrimaryKey($otherModelClass); |
627
|
|
|
|
628
|
1 |
|
$fkClosure = $this->foreignColumnImpl( |
629
|
1 |
|
$localKey, |
630
|
1 |
|
$foreignTable, |
631
|
1 |
|
$foreignKey, |
632
|
1 |
|
$columnType, |
633
|
1 |
|
$notNullable, |
634
|
1 |
|
$cascadeDelete |
635
|
|
|
); |
636
|
|
|
|
637
|
1 |
|
return $fkClosure($table); |
638
|
1 |
|
}; |
639
|
|
|
} |
640
|
|
|
} |
641
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.