Skip to content

Commit

Permalink
Merge pull request #1939 from AdrienPoupa/migration-shouldrun
Browse files Browse the repository at this point in the history
Add new shouldExecute method to prevent a migration or seeder from being executed
  • Loading branch information
dereuromark authored Jun 3, 2021
2 parents 6a66b88 + 71f1eff commit 70f4263
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 19 deletions.
8 changes: 8 additions & 0 deletions docs/en/migrations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ The ``init()`` method is run by Phinx before the migration methods if it exists.
This can be used for setting common class properties that are then used within
the migration methods.

The Should Execute Method
~~~~~~~~~~~~~~~~~~~~~~~~~

The ``shouldExecute()`` method is run by Phinx before executing the 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 ``AbstractMigration``
implementation.

Executing Queries
-----------------

Expand Down
8 changes: 8 additions & 0 deletions docs/en/seeding.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ The Init Method
The ``init()`` method is run by Phinx before the run method if it exists. This
can be used to initialize properties of the Seed class before using run.

The Should Execute Method
~~~~~~~~~~~~~~~~~~~~~~~~~

The ``shouldExecute()`` method is run by Phinx before executing the seed.
This can be used to prevent the seed from being executed at this time. It always
returns true by default. You can override it in your custom ``AbstractSeed``
implementation.

Foreign Key Dependencies
~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
14 changes: 14 additions & 0 deletions src/Phinx/Migration/AbstractMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -321,4 +321,18 @@ public function postFlightCheck()
}
}
}

/**
* Checks to see if the migration should be executed.
*
* Returns true by default.
*
* You can use this to prevent a migration from executing.
*
* @return bool
*/
public function shouldExecute()
{
return true;
}
}
94 changes: 75 additions & 19 deletions src/Phinx/Migration/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -371,22 +371,25 @@ public function migrate($environment, $version = null, $fake = false)
public function executeMigration($name, MigrationInterface $migration, $direction = MigrationInterface::UP, $fake = false)
{
$this->getOutput()->writeln('');
$this->getOutput()->writeln(
' ==' .
' <info>' . $migration->getVersion() . ' ' . $migration->getName() . ':</info>' .
' <comment>' . ($direction === MigrationInterface::UP ? 'migrating' : 'reverting') . '</comment>'
);

// Skip the migration if it should not be executed
if (!$migration->shouldExecute()) {
$this->printMigrationStatus($migration, 'skipped');

return;
}

$this->printMigrationStatus($migration, ($direction === MigrationInterface::UP ? 'migrating' : 'reverting'));

// Execute the migration and log the time elapsed.
$start = microtime(true);
$this->getEnvironment($name)->executeMigration($migration, $direction, $fake);
$end = microtime(true);

$this->getOutput()->writeln(
' ==' .
' <info>' . $migration->getVersion() . ' ' . $migration->getName() . ':</info>' .
' <comment>' . ($direction === MigrationInterface::UP ? 'migrated' : 'reverted') .
' ' . sprintf('%.4fs', $end - $start) . '</comment>'
$this->printMigrationStatus(
$migration,
($direction === MigrationInterface::UP ? 'migrated' : 'reverted'),
sprintf('%.4fs', $end - $start)
);
}

Expand All @@ -395,28 +398,81 @@ public function executeMigration($name, MigrationInterface $migration, $directio
*
* @param string $name Environment Name
* @param \Phinx\Seed\SeedInterface $seed Seed
*
* @return void
*/
public function executeSeed($name, SeedInterface $seed)
{
$this->getOutput()->writeln('');
$this->getOutput()->writeln(
' ==' .
' <info>' . $seed->getName() . ':</info>' .
' <comment>seeding</comment>'
);

// Skip the seed if it should not be executed
if (!$seed->shouldExecute()) {
$this->printSeedStatus($seed, 'skipped');

return;
}

$this->printSeedStatus($seed, 'seeding');

// Execute the seeder and log the time elapsed.
$start = microtime(true);
$this->getEnvironment($name)->executeSeed($seed);
$end = microtime(true);

$this->printSeedStatus(
$seed,
'seeded',
sprintf('%.4fs', $end - $start)
);
}

/**
* Print Migration Status
*
* @param \Phinx\Migration\MigrationInterface $migration Migration
* @param string $status Status of the migration
* @param string|null $duration Duration the migration took the be executed
* @return void
*/
protected function printMigrationStatus(MigrationInterface $migration, $status, $duration = null)
{
$this->printStatusOutput(
$migration->getVersion() . ' ' . $migration->getName(),
$status,
$duration
);
}

/**
* Print Seed Status
*
* @param \Phinx\Seed\SeedInterface $seed Seed
* @param string $status Status of the seed
* @param string|null $duration Duration the seed took the be executed
* @return void
*/
protected function printSeedStatus(SeedInterface $seed, $status, $duration = null)
{
$this->printStatusOutput(
$seed->getName(),
$status,
$duration
);
}

/**
* Print Status in Output
*
* @param string $name Name of the migration or seed
* @param string $status Status of the migration or seed
* @param string|null $duration Duration the migration or seed took the be executed
* @return void
*/
protected function printStatusOutput($name, $status, $duration = null)
{
$this->getOutput()->writeln(
' ==' .
' <info>' . $seed->getName() . ':</info>' .
' <comment>seeded' .
' ' . sprintf('%.4fs', $end - $start) . '</comment>'
' <info>' . $name . ':</info>' .
' <comment>' . $status . ' ' . $duration . '</comment>'
);
}

Expand Down
11 changes: 11 additions & 0 deletions src/Phinx/Migration/MigrationInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,15 @@ public function preFlightCheck();
* @return void
*/
public function postFlightCheck();

/**
* Checks to see if the migration should be executed.
*
* Returns true by default.
*
* You can use this to prevent a migration from executing.
*
* @return bool
*/
public function shouldExecute();
}
14 changes: 14 additions & 0 deletions src/Phinx/Seed/AbstractSeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,18 @@ public function table($tableName, $options = [])
{
return new Table($tableName, $options, $this->getAdapter());
}

/**
* Checks to see if the seed should be executed.
*
* Returns true by default.
*
* You can use this to prevent a seed from executing.
*
* @return bool
*/
public function shouldExecute()
{
return true;
}
}
11 changes: 11 additions & 0 deletions src/Phinx/Seed/SeedInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,15 @@ public function hasTable($tableName);
* @return \Phinx\Db\Table
*/
public function table($tableName, $options);

/**
* Checks to see if the seed should be executed.
*
* Returns true by default.
*
* You can use this to prevent a seed from executing.
*
* @return bool
*/
public function shouldExecute();
}
42 changes: 42 additions & 0 deletions tests/Phinx/Migration/ManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5460,6 +5460,19 @@ public function testOrderSeeds()
$this->assertInstanceOf('PostSeeder', $seeds[2]);
}

public function testSeedWillNotBeExecuted()
{
// stub environment
$envStub = $this->getMockBuilder('\Phinx\Migration\Manager\Environment')
->setConstructorArgs(['mockenv', []])
->getMock();
$this->manager->setEnvironments(['mockenv' => $envStub]);
$this->manager->seed('mockenv', 'UserSeederNotExecuted');
rewind($this->manager->getOutput()->getStream());
$output = stream_get_contents($this->manager->getOutput()->getStream());
$this->assertStringContainsString('skipped', $output);
}

public function testGettingInputObject()
{
$migrations = $this->manager->getMigrations('mockenv');
Expand Down Expand Up @@ -6067,6 +6080,35 @@ public function testInvalidVersionBreakpoint()
$outputStr = stream_get_contents($this->manager->getOutput()->getStream());
$this->assertEquals("warning 20120133235330 is not a valid version", trim($outputStr));
}

public function testMigrationWillNotBeExecuted()
{
if (!defined('MYSQL_DB_CONFIG')) {
$this->markTestSkipped('Mysql tests disabled.');
}
$configArray = $this->getConfigArray();
$adapter = $this->manager->getEnvironment('production')->getAdapter();

// override the migrations directory to use the should execute migrations
$configArray['paths']['migrations'] = $this->getCorrectedPath(__DIR__ . '/_files/should_execute');
$config = new Config($configArray);

// ensure the database is empty
$adapter->dropDatabase(MYSQL_DB_CONFIG['name']);
$adapter->createDatabase(MYSQL_DB_CONFIG['name']);
$adapter->disconnect();

// Run the migration with shouldExecute returning false: the table should not be created
$this->manager->setConfig($config);
$this->manager->migrate('production', '20201207205056');

$this->assertFalse($adapter->hasTable('info'));

// Run the migration with shouldExecute returning true: the table should be created
$this->manager->migrate('production', '20201207205057');

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

/**
Expand Down
30 changes: 30 additions & 0 deletions tests/Phinx/Migration/_files/seeds/UserSeederNotExecuted.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);

use Phinx\Seed\AbstractSeed;

class UserSeederNotExecuted extends AbstractSeed
{
public function run()
{
$data = [
[
'name' => 'foo',
'created' => date('Y-m-d H:i:s'),
],
[
'name' => 'bar',
'created' => date('Y-m-d H:i:s'),
],
];

$users = $this->table('users');
$users->insert($data)
->save();
}

public function shouldExecute()
{
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);

use Phinx\Migration\AbstractMigration;

class ShouldNotExecuteMigration extends AbstractMigration
{
public function change()
{
// info table
$this->table('info')->create();
}

public function shouldExecute()
{
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);

use Phinx\Migration\AbstractMigration;

class ShouldExecuteMigration extends AbstractMigration
{
public function change()
{
// info table
$this->table('info')->create();
}

public function shouldExecute()
{
return true;
}
}

0 comments on commit 70f4263

Please sign in to comment.