Skip to content

Commit 980e8d5

Browse files
[11.x] Enhance database migrations (#51373)
* enhance migrations * formatting * support drop column on legacy sqlite * formatting * fix tests * force re-run tests * formatting * fix altering a table that has a column with zero as default fixes #51747 * formatting * formatting * formatting * formatting * formatting * Formatting --------- Co-authored-by: Taylor Otwell <[email protected]>
1 parent cdf6e21 commit 980e8d5

15 files changed

+946
-251
lines changed

src/Illuminate/Database/Schema/Blueprint.php

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Illuminate\Database\Query\Expression;
99
use Illuminate\Database\Schema\Grammars\Grammar;
1010
use Illuminate\Database\Schema\Grammars\MySqlGrammar;
11+
use Illuminate\Database\Schema\Grammars\SQLiteGrammar;
1112
use Illuminate\Support\Fluent;
1213
use Illuminate\Support\Traits\Macroable;
1314

@@ -78,6 +79,13 @@ class Blueprint
7879
*/
7980
public $after;
8081

82+
/**
83+
* The blueprint state instance.
84+
*
85+
* @var \Illuminate\Database\Schema\BlueprintState|null
86+
*/
87+
protected $state;
88+
8189
/**
8290
* Create a new schema blueprint.
8391
*
@@ -136,6 +144,10 @@ public function toSql(Connection $connection, Grammar $grammar)
136144
$method = 'compile'.ucfirst($command->name);
137145

138146
if (method_exists($grammar, $method) || $grammar::hasMacro($method)) {
147+
if ($this->hasState()) {
148+
$this->state->update($command);
149+
}
150+
139151
if (! is_null($sql = $grammar->$method($this, $command, $connection))) {
140152
$statements = array_merge($statements, (array) $sql);
141153
}
@@ -161,6 +173,8 @@ protected function ensureCommandsAreValid(Connection $connection)
161173
/**
162174
* Get all of the commands matching the given names.
163175
*
176+
* @deprecated Will be removed in a future Laravel version.
177+
*
164178
* @param array $names
165179
* @return \Illuminate\Support\Collection
166180
*/
@@ -180,17 +194,20 @@ protected function commandsNamed(array $names)
180194
*/
181195
protected function addImpliedCommands(Connection $connection, Grammar $grammar)
182196
{
183-
if (count($this->getAddedColumns()) > 0 && ! $this->creating()) {
184-
array_unshift($this->commands, $this->createCommand('add'));
185-
}
186-
187-
if (count($this->getChangedColumns()) > 0 && ! $this->creating()) {
188-
array_unshift($this->commands, $this->createCommand('change'));
189-
}
190-
191197
$this->addFluentIndexes($connection, $grammar);
192198

193199
$this->addFluentCommands($connection, $grammar);
200+
201+
if (! $this->creating()) {
202+
$this->commands = array_map(
203+
fn ($command) => $command instanceof ColumnDefinition
204+
? $this->createCommand($command->change ? 'change' : 'add', ['column' => $command])
205+
: $command,
206+
$this->commands
207+
);
208+
209+
$this->addAlterCommands($connection, $grammar);
210+
}
194211
}
195212

196213
/**
@@ -260,6 +277,48 @@ public function addFluentCommands(Connection $connection, Grammar $grammar)
260277
}
261278
}
262279

280+
/**
281+
* Add the alter commands if whenever needed.
282+
*
283+
* @param \Illuminate\Database\Connection $connection
284+
* @param \Illuminate\Database\Schema\Grammars\Grammar $grammar
285+
* @return void
286+
*/
287+
public function addAlterCommands(Connection $connection, Grammar $grammar)
288+
{
289+
if (! $grammar instanceof SQLiteGrammar) {
290+
return;
291+
}
292+
293+
$alterCommands = $grammar->getAlterCommands($connection);
294+
295+
[$commands, $lastCommandWasAlter, $hasAlterCommand] = [
296+
[], false, false,
297+
];
298+
299+
foreach ($this->commands as $command) {
300+
if (in_array($command->name, $alterCommands)) {
301+
$hasAlterCommand = true;
302+
$lastCommandWasAlter = true;
303+
} elseif ($lastCommandWasAlter) {
304+
$commands[] = $this->createCommand('alter');
305+
$lastCommandWasAlter = false;
306+
}
307+
308+
$commands[] = $command;
309+
}
310+
311+
if ($lastCommandWasAlter) {
312+
$commands[] = $this->createCommand('alter');
313+
}
314+
315+
if ($hasAlterCommand) {
316+
$this->state = new BlueprintState($this, $connection, $grammar);
317+
}
318+
319+
$this->commands = $commands;
320+
}
321+
263322
/**
264323
* Determine if the blueprint has a create command.
265324
*
@@ -1634,6 +1693,10 @@ protected function addColumnDefinition($definition)
16341693
{
16351694
$this->columns[] = $definition;
16361695

1696+
if (! $this->creating()) {
1697+
$this->commands[] = $definition;
1698+
}
1699+
16371700
if ($this->after) {
16381701
$definition->after($this->after);
16391702

@@ -1671,6 +1734,10 @@ public function removeColumn($name)
16711734
return $c['name'] != $name;
16721735
}));
16731736

1737+
$this->commands = array_values(array_filter($this->commands, function ($c) use ($name) {
1738+
return ! $c instanceof ColumnDefinition || $c['name'] != $name;
1739+
}));
1740+
16741741
return $this;
16751742
}
16761743

@@ -1740,6 +1807,27 @@ public function getCommands()
17401807
return $this->commands;
17411808
}
17421809

1810+
/*
1811+
* Determine if the blueprint has state.
1812+
*
1813+
* @param mixed $name
1814+
* @return bool
1815+
*/
1816+
private function hasState(): bool
1817+
{
1818+
return ! is_null($this->state);
1819+
}
1820+
1821+
/**
1822+
* Get the state of the blueprint.
1823+
*
1824+
* @return \Illuminate\Database\Schema\BlueprintState
1825+
*/
1826+
public function getState()
1827+
{
1828+
return $this->state;
1829+
}
1830+
17431831
/**
17441832
* Get the columns on the blueprint that should be added.
17451833
*
@@ -1755,6 +1843,8 @@ public function getAddedColumns()
17551843
/**
17561844
* Get the columns on the blueprint that should be changed.
17571845
*
1846+
* @deprecated Will be removed in a future Laravel version.
1847+
*
17581848
* @return \Illuminate\Database\Schema\ColumnDefinition[]
17591849
*/
17601850
public function getChangedColumns()

0 commit comments

Comments
 (0)