Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/en/guides/writing-migrations/migration-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,29 @@ migration. This can be used to prevent the migration from being executed at
this time. It always returns `true` by default. You can override it in your
custom `BaseMigration` implementation.

The database adapter is available inside `shouldExecute()`, so the decision can
be based on the current state of the database (for example the server version or
whether a table already exists):

```php
<?php

use Migrations\BaseMigration;

class MyNewMigration extends BaseMigration
{
public function shouldExecute(): bool
{
return !$this->hasTable('some_table');
}

public function change(): void
{
// ...
}
}
```

## Working With Tables

The Table object enables you to manipulate database tables using PHP code. You
Expand Down
7 changes: 7 additions & 0 deletions src/Migration/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,10 @@ public function executeMigration(MigrationInterface $migration, string $directio
{
$this->getIo()->out('');

// Make the adapter available so shouldExecute() can inspect the database.
// The environment sets it again (and wraps it for down/change) before running the migration body.
$migration->setAdapter($this->getEnvironment()->getAdapter());

// Skip the migration if it should not be executed
if (!$migration->shouldExecute()) {
$this->printMigrationStatus($migration, 'skipped');
Expand Down Expand Up @@ -540,6 +544,9 @@ public function executeMigration(MigrationInterface $migration, string $directio
*/
public function executeSeed(SeedInterface $seed, bool $force = false, bool $fake = false): void
{
// Make the adapter available so shouldExecute() can inspect the database.
$seed->setAdapter($this->getEnvironment()->getAdapter());

// Skip the seed if it should not be executed
if (!$seed->shouldExecute()) {
$this->getIo()->out('');
Expand Down
16 changes: 16 additions & 0 deletions tests/TestCase/Migration/ManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2987,4 +2987,20 @@ public function testMigrationWillNotBeExecuted(): void

$this->assertTrue($adapter->hasTable('info'));
}

public function testMigrationShouldExecuteCanQueryDatabase(): void
{
$configArray = $this->getConfigArray();
$adapter = $this->manager->getEnvironment()->getAdapter();

// override the migrations directory to use a shouldExecute() that queries the database
$configArray['paths']['migrations'] = ROOT . '/config/ShouldExecuteWithDb/';
$config = new Config($configArray);

// shouldExecute() calls getAdapter()->hasTable(); before the fix this threw 'Adapter not set.'
$this->manager->setConfig($config);
$this->manager->migrate(20201207205100);

$this->assertTrue($adapter->hasTable('info'));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);

use Migrations\BaseMigration;

class ShouldExecuteWithDbMigration extends BaseMigration
{
public function change(): void
{
// info table
$this->table('info')->create();
}

public function shouldExecute(): bool
{
// Query the database to decide eligibility. Before the fix the adapter
// was not set at this point and getAdapter() threw 'Adapter not set.'.
return !$this->getAdapter()->hasTable('info');
}
}
Loading