Skip to content

Commit e8b472e

Browse files
committed
added foreignId, unspecifying of default index names and better line wrap
1 parent 1b24254 commit e8b472e

File tree

32 files changed

+303
-126
lines changed

32 files changed

+303
-126
lines changed

src/Attributes/ForeignKey.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ public function __construct(
4444
public function getReferenceTableName()
4545
{
4646
if (null === $this->referenceTableName) {
47-
$this->referenceTableName = is_a($this->on, Model::class) ? $this->on->getTable() : $this->on;
47+
if (is_a($this->on, Model::class, true)) {
48+
$on = is_string($this->on) ? (new $this->on()) : $this->on;
49+
$this->referenceTableName = $on->getTable();
50+
} else {
51+
$this->referenceTableName = $this->on;
52+
}
4853
}
4954

5055
return $this->referenceTableName;
@@ -180,6 +185,8 @@ public function ensureColumns(Blueprint $table, array $blueprints, array $modelN
180185

181186
protected function process(Blueprint $table): Blueprint
182187
{
188+
$this->references = empty($this->references) ? ['id'] : $this->references;
189+
183190
$references = is_array($this->references) && count($this->references) === 1
184191
? $this->references[0]
185192
: $this->references;

src/Blueprint/BlueprintDiff.php

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,25 +34,23 @@ public function __construct(
3434

3535
public function applyColumnIndexes(bool $reverse = false)
3636
{
37+
$original = $reverse ? $this->from : $this->to;
38+
3739
/** @var SimplifyingBlueprint */
38-
$blueprint = App::make(SimplifyingBlueprint::class, ['tableName' => $this->to->getTable()]);
40+
$blueprint = App::make(SimplifyingBlueprint::class, ['tableName' => ($original)->getTable()]);
3941

4042
foreach ($this->getAddedColumns($reverse) as $column) {
4143
$blueprint->addColumn($column->type, $column->name, $column->getAttributes());
4244
}
4345

4446
foreach ($this->getAddedIndexes($reverse) as $index) {
45-
$addedIndex = $blueprint->{$index->name}($index->columns, $index->index, $index->algorithm);
47+
$addedIndex = $blueprint->{$index->name}($index->columns, $this->indexName($index), $index->algorithm);
4648

4749
foreach (array_keys($index->getAttributes()) as $attribute) {
4850
$addedIndex->{$attribute} = $index->{$attribute};
4951
}
5052
}
5153

52-
foreach ($this->getRenamedIndexes($reverse) as $from => $to) {
53-
$blueprint->renameIndex($from, $to);
54-
}
55-
5654
$blueprint->applyColumnIndexes();
5755

5856
if ($reverse) {
@@ -200,10 +198,52 @@ public function extractForeignKey(string $on, string $reference): Fluent
200198
continue;
201199
}
202200

203-
$this->addedIndexes = array_filter($this->addedIndexes, fn($i) => $i->index !== $index->index);
201+
$this->addedIndexes = array_filter(
202+
$this->addedIndexes,
203+
fn($i) => $this->indexName($i) !== $this->indexName($index)
204+
);
204205
return $index;
205206
}
206207

207208
throw new Exception("Reference {$on}.{$reference} has no foreign key in blueprint for {$this->to->getTable()}");
208209
}
210+
211+
public function dropAddedIndex($indexName, bool $reverse = false)
212+
{
213+
$remaining = [];
214+
215+
foreach ($this->getAddedIndexes($reverse) as $index) {
216+
if ($this->indexName($index) === $indexName) {
217+
continue;
218+
}
219+
220+
$remaining[] = $index;
221+
}
222+
223+
if ($reverse) {
224+
$this->droppedIndexes = $remaining;
225+
} else {
226+
$this->addedIndexes = $remaining;
227+
}
228+
}
229+
230+
public function stripDefaultIndexNames(bool $reverse = false)
231+
{
232+
$blueprint = $reverse ? $this->from : $this->to;
233+
foreach ($this->getAddedIndexes($reverse) as $index) {
234+
if ($blueprint->defaultIndexName($index) === $index->index) {
235+
$index->index = null;
236+
}
237+
}
238+
}
239+
240+
public function indexName(Fluent $index, bool $reverse = false)
241+
{
242+
return $index->index ?? $this->defaultIndexName($index, $reverse);
243+
}
244+
245+
public function defaultIndexName(Fluent $index, bool $reverse = false)
246+
{
247+
return ($reverse ? $this->from : $this->to)->defaultIndexName($index);
248+
}
209249
}

src/Blueprint/Exporters/ColumnExporter.php

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
namespace Toramanlis\ImplicitMigrations\Blueprint\Exporters;
44

5+
use Illuminate\Database\Eloquent\Model;
56
use Illuminate\Database\Schema\Builder;
67
use Illuminate\Database\Schema\ColumnDefinition;
8+
use Illuminate\Support\Fluent;
79
use Toramanlis\ImplicitMigrations\Attributes\Column;
810
use Toramanlis\ImplicitMigrations\Attributes\IndexType;
911

@@ -17,10 +19,34 @@ class ColumnExporter extends Exporter
1719

1820
protected ?string $collapsedType = null;
1921

22+
public ?Fluent $foreignKey = null;
23+
2024
public const SUPPORTED_MODIFIERS = Column::SUPPORTED_MODIFIERS;
2125

22-
public function __construct(protected ColumnDefinition $definition)
26+
public function __construct(public readonly ColumnDefinition $definition)
2327
{
28+
$this->attributes = array_filter($this->definition->getAttributes());
29+
unset(
30+
$this->attributes['type'],
31+
$this->attributes['name'],
32+
$this->attributes['change'],
33+
$this->attributes[IndexType::Primary->value],
34+
$this->attributes[IndexType::Unique->value],
35+
$this->attributes[IndexType::Index->value]
36+
);
37+
38+
$this->runCollapsables();
39+
}
40+
41+
public function setForeignKey(Fluent $foreignKey)
42+
{
43+
if ('unsignedBigInteger' !== $this->collapsedType || !empty($this->collapsedAttributes)) {
44+
return false;
45+
}
46+
47+
$foreignKey->references = 'id' === $foreignKey->references ? null : $foreignKey->references;
48+
$this->foreignKey = $foreignKey;
49+
return true;
2450
}
2551

2652
protected function buildIndexModifiers(bool $up = true)
@@ -41,17 +67,6 @@ protected function buildIndexModifiers(bool $up = true)
4167

4268
protected function exportUp(): string
4369
{
44-
$this->attributes = array_filter($this->definition->getAttributes());
45-
unset(
46-
$this->attributes['type'],
47-
$this->attributes['name'],
48-
$this->attributes['change'],
49-
$this->attributes[IndexType::Primary->value],
50-
$this->attributes[IndexType::Unique->value],
51-
$this->attributes[IndexType::Index->value]
52-
);
53-
54-
$this->runCollapsables();
5570
$modifiers = $this->extractModifiers($this->attributes);
5671
$indexModifiers = $this->buildIndexModifiers();
5772
$collapsedModifiers = $this->extractModifiers($this->collapsedAttributes);
@@ -73,12 +88,23 @@ protected function exportUp(): string
7388
$type = $this->definition->type;
7489
}
7590

91+
$modifiers = array_merge($modifiers, $indexModifiers);
92+
7693
$parameters = in_array($type, ['id', 'rememberToken', 'softDeletes']) ? [] : [$this->definition->name];
7794
if ('id' === $type && 'id' !== $this->definition->name) {
7895
$parameters[] = $this->definition->name;
7996
}
8097

81-
return $this->exportMethodCall($type, $parameters, array_merge($modifiers, $indexModifiers));
98+
if ($this->foreignKey && 'unsignedBigInteger' === $type) {
99+
$modifiers = array_merge([static::makeModifier('constrained', array_filter([
100+
$this->foreignKey->on,
101+
'id' == $this->foreignKey->references ? null : $this->foreignKey->references,
102+
$this->foreignKey->index
103+
]))], $modifiers);
104+
return $this->exportMethodCall('foreignId', $parameters, $modifiers);
105+
}
106+
107+
return $this->exportMethodCall($type, $parameters, $modifiers);
82108
} else {
83109
return $this->exportMethodCall('addColumn', [
84110
$this->definition->type,

src/Blueprint/Exporters/Exporter.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ abstract class Exporter
1313
public const MODE_UP = 1;
1414
public const MODE_DOWN = 2;
1515

16+
protected const WRAP_LIMIT = 80;
17+
1618
protected string $source;
1719

1820
abstract protected function exportUp(): string;
@@ -37,7 +39,7 @@ public static function varExport(mixed $variable)
3739

3840
$totalLength = array_sum(array_map('strlen', $components));
3941

40-
if ($totalLength > 80) {
42+
if ($totalLength > static::WRAP_LIMIT) {
4143
$start = "\n\t";
4244
$end = ",\n";
4345
$separator = ",\n\t";
@@ -48,6 +50,8 @@ public static function varExport(mixed $variable)
4850
}
4951

5052
return "[{$start}" . implode($separator, $components) . "{$end}]";
53+
} elseif (is_null($variable)) {
54+
return 'null';
5155
}
5256

5357
return (string) var_export($variable, true);
@@ -115,7 +119,7 @@ protected static function exportParameters(array $parameters): string
115119

116120
$totalLength = array_sum(array_map('strlen', $items));
117121

118-
if ($totalLength > 80) {
122+
if ($totalLength > static::WRAP_LIMIT) {
119123
$parameters = str_replace("\n", "\n\t", implode(",\n", $items));
120124
} else {
121125
$parameters = implode(', ', $items);
@@ -137,7 +141,13 @@ protected static function exportMethodCall(string $methodName, array $parameters
137141
sort($modifiers);
138142
$joinedModifiers = static::joinModifiers($modifiers);
139143
$parameters = static::exportParameters($parameters);
140-
return "\$table->{$methodName}({$parameters}){$joinedModifiers};";
144+
$unmodified = "\$table->{$methodName}({$parameters})";
145+
146+
if (strlen($unmodified) + strpos("{$joinedModifiers}\n", "\n") > static::WRAP_LIMIT) {
147+
$unmodified .= "\n\t";
148+
}
149+
150+
return "{$unmodified}{$joinedModifiers};";
141151
}
142152

143153
protected static function makeModifier($name, $parameters)

src/Blueprint/Exporters/IndexExporter.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ protected function exportUp(): string
3737
}
3838

3939
if (!in_array($method, ['spatialIndex', 'foreign']) && null !== $this->definition->algorithm) {
40+
if (null === $this->definition->index) {
41+
$parameters[] = null;
42+
}
4043
$parameters[] = $this->definition->algorithm;
4144
}
4245

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace Toramanlis\ImplicitMigrations\Blueprint\Exporters;
4+
5+
trait SortsColumns
6+
{
7+
protected function getSortedExports(array $exporters)
8+
{
9+
$exports = [];
10+
$ids = [];
11+
$primary = null;
12+
13+
foreach ($exporters as $exporter) {
14+
$columnExport = $exporter->export();
15+
16+
if ($exporter->definition->primary) {
17+
$primary = $columnExport;
18+
} elseif ($exporter->foreignKey) {
19+
array_unshift($exports, $columnExport);
20+
} elseif ('id' === $exporter->getCollapsedType()) {
21+
if ('id' == $exporter->definition->name) {
22+
array_unshift($ids, $columnExport);
23+
} else {
24+
$ids[] = $columnExport;
25+
}
26+
} else {
27+
$exports[] = $columnExport;
28+
}
29+
}
30+
31+
if ($primary) {
32+
array_unshift($ids, $primary);
33+
}
34+
35+
array_unshift($exports, ...$ids);
36+
37+
return $exports;
38+
}
39+
}

src/Blueprint/Exporters/TableDiffExporter.php

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
namespace Toramanlis\ImplicitMigrations\Blueprint\Exporters;
44

55
use Illuminate\Database\Schema\ColumnDefinition;
6+
use Illuminate\Support\Facades\App;
67
use Illuminate\Support\Fluent;
8+
use Toramanlis\ImplicitMigrations\Attributes\IndexType;
79
use Toramanlis\ImplicitMigrations\Blueprint\BlueprintDiff;
810

911
class TableDiffExporter extends Exporter
1012
{
13+
use SortsColumns;
14+
1115
public function __construct(protected BlueprintDiff $definition)
1216
{
1317
}
@@ -65,13 +69,30 @@ protected function exportRename(bool $reverse = false): string
6569
*/
6670
protected function exportAddedColumns(bool $reverse = false): string
6771
{
68-
$exports = [];
72+
$exporters = [];
6973

7074
foreach ($this->definition->getAddedColumns($reverse) as $column) {
71-
$exports[] = ColumnExporter::exportDefinition($column);
75+
/** @var ColumnExporter */
76+
$exporter = App::make(ColumnExporter::class, ['definition' => $column]);
77+
78+
foreach ($this->definition->getAddedIndexes($reverse) as $i => $index) {
79+
if (
80+
IndexType::Foreign->value === $index->name &&
81+
count($index->columns) === 1 &&
82+
$column->name === $index->columns[0]
83+
) {
84+
if ($exporter->setForeignKey($index)) {
85+
$indexName = $index->index ?? $this->definition->defaultIndexName($index, $reverse);
86+
$this->definition->dropAddedIndex($indexName, $reverse);
87+
break;
88+
}
89+
}
90+
}
91+
92+
$exporters[] = $exporter;
7293
}
7394

74-
return $this->joinExports($exports);
95+
return $this->joinExports($this->getSortedExports($exporters));
7596
}
7697

7798
/**
@@ -113,7 +134,9 @@ protected function exportDroppedIndexes(bool $reverse = false): string
113134
$exports = [];
114135

115136
foreach ($this->definition->getDroppedIndexes($reverse) as $index) {
116-
$exports[] = IndexExporter::exportDefinition($index, IndexExporter::MODE_DOWN);
137+
$tmp = clone $index;
138+
$tmp->index = ($reverse ? $this->definition->from : $this->definition->to)->defaultIndexName($tmp);
139+
$exports[] = IndexExporter::exportDefinition($tmp, IndexExporter::MODE_DOWN);
117140
}
118141

119142
return $this->joinExports($exports);

0 commit comments

Comments
 (0)