Skip to content

Commit

Permalink
Merge pull request #185 from cakephp/migrations-update
Browse files Browse the repository at this point in the history
Migrations `markMigrated()` update (non-shell)
  • Loading branch information
lorenzo committed Jan 19, 2016
2 parents 2ff8794 + 3ad14bc commit ba856dc
Show file tree
Hide file tree
Showing 5 changed files with 371 additions and 151 deletions.
5 changes: 5 additions & 0 deletions src/CakeAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Migrations;

use Cake\Database\Connection;
use PDO;
use Phinx\Db\Adapter\AdapterInterface;
use Phinx\Db\Table;
use Phinx\Db\Table\Column;
Expand Down Expand Up @@ -52,6 +53,10 @@ public function __construct(AdapterInterface $adapter, Connection $connection)
$this->adapter = $adapter;
$this->connection = $connection;
$pdo = $adapter->getConnection();

if ($pdo->getAttribute(PDO::ATTR_ERRMODE) !== PDO::ERRMODE_EXCEPTION) {
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
$connection->driver()->connection($pdo);
}

Expand Down
89 changes: 89 additions & 0 deletions src/CakeManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,95 @@ public function markMigrated($version, $path)
return true;
}

/**
* Decides which versions it should mark as migrated
*
* @param \Symfony\Component\Console\Input\InputInterface $input Input interface from which argument and options
* will be extracted to determine which versions to be marked as migrated
* @return array Array of versions that should be marked as migrated
* @throws \InvalidArgumentException If the `--exclude` or `--only` options are used without `--target`
* or version not found
*/
public function getVersionsToMark($input)
{
$migrations = $this->getMigrations();
$versions = array_keys($migrations);

$versionArg = $input->getArgument('version');
$targetArg = $input->getOption('target');
$hasAllVersion = in_array($versionArg, ['all', '*']);
if ((empty($versionArg) && empty($targetArg)) || $hasAllVersion) {
return $versions;
}

$version = $targetArg ?: $versionArg;

if ($input->getOption('only') || !empty($versionArg)) {
if (!in_array($version, $versions)) {
throw new \InvalidArgumentException("Migration `$version` was not found !");
}

return [$version];
}

$lengthIncrease = $input->getOption('exclude') ? 0 : 1;
$index = array_search($version, $versions);

if ($index === false) {
throw new \InvalidArgumentException("Migration `$version` was not found !");
}

return array_slice($versions, 0, $index + $lengthIncrease);
}

/**
* Mark all migrations in $versions array found in $path as migrated
*
* It will start a transaction and rollback in case one of the operation raises an exception
*
* @param string $path Path where to look for migrations
* @param array $versions Versions which should be marked
* @param \Symfony\Component\Console\Output\OutputInterface $output OutputInterface used to store
* the command output
* @return void
*/
public function markVersionsAsMigrated($path, $versions, $output)
{
$adapter = $this->getEnvironment('default')->getAdapter();

if (empty($versions)) {
$output->writeln('<info>No migrations were found. Nothing to mark as migrated.</info>');
return;
}

$adapter->beginTransaction();
foreach ($versions as $version) {
if ($this->isMigrated($version)) {
$output->writeln(sprintf('<info>Skipping migration `%s` (already migrated).</info>', $version));
continue;
}

try {
$this->markMigrated($version, $path);
$output->writeln(
sprintf('<info>Migration `%s` successfully marked migrated !</info>', $version)
);
} catch (\Exception $e) {
$adapter->rollbackTransaction();
$output->writeln(
sprintf(
'<error>An error occurred while marking migration `%s` as migrated : %s</error>',
$version,
$e->getMessage()
)
);
$output->writeln('<error>All marked migrations during this process were unmarked.</error>');
return;
}
}
$adapter->commitTransaction();
}

/**
* Resolves a migration class name based on $path
*
Expand Down
124 changes: 2 additions & 122 deletions src/Command/MarkMigrated.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,122 +122,13 @@ protected function execute(InputInterface $input, OutputInterface $output)
}

try {
$versions = $this->getVersionsToMark();
$versions = $this->getManager()->getVersionsToMark($input);
} catch (InvalidArgumentException $e) {
$output->writeln(sprintf("<error>%s</error>", $e->getMessage()));
return;
}

$this->markVersionsAsMigrated($path, $versions);
}

/**
* Mark all migrations in $versions array found in $path as migrated
*
* It will start a transaction and rollback in case one of the operation raises an exception
*
* @param string $path Path where to look for migrations
* @param array $versions Versions which should be marked
* @return void
*/
protected function markVersionsAsMigrated($path, $versions)
{
$manager = $this->getManager();
$adapter = $manager->getEnvironment('default')->getAdapter();
$output = $this->output();

if (empty($versions)) {
$output->writeln('<info>No migrations were found. Nothing to mark as migrated.</info>');
return;
}

$adapter->beginTransaction();
foreach ($versions as $version) {
if ($manager->isMigrated($version)) {
$output->writeln(sprintf('<info>Skipping migration `%s` (already migrated).</info>', $version));
continue;
}

try {
$this->getManager()->markMigrated($version, $path);
$output->writeln(
sprintf('<info>Migration `%s` successfully marked migrated !</info>', $version)
);
} catch (\Exception $e) {
$adapter->rollbackTransaction();
$output->writeln(
sprintf(
'<error>An error occurred while marking migration `%s` as migrated : %s</error>',
$version,
$e->getMessage()
)
);
$output->writeln('<error>All marked migrations during this process were unmarked.</error>');
return;
}
}
$adapter->commitTransaction();
}

/**
* Decides which versions it should mark as migrated
*
* @return array Array of versions that should be marked as migrated
* @throws \InvalidArgumentException If the `--exclude` or `--only` options are used without `--target`
* or version not found
*/
protected function getVersionsToMark()
{
$migrations = $this->getManager()->getMigrations();
$versions = array_keys($migrations);

if ($this->isAllVersion()) {
return $versions;
}

$version = $this->getTarget();

if ($this->isOnly()) {
if (!in_array($version, $versions)) {
throw new InvalidArgumentException("Migration `$version` was not found !");
}

return [$version];
}

$lengthIncrease = $this->hasExclude() ? 0 : 1;
$index = array_search($version, $versions);

if ($index === false) {
throw new \InvalidArgumentException("Migration `$version` was not found !");
}

return array_slice($versions, 0, $index + $lengthIncrease);
}

/**
* Returns the target version from `--target` or from the deprecated version argument
*
* @return string Version found as target
*/
protected function getTarget()
{
$target = $this->input->getOption('target');
return $target ? $target : $this->input->getArgument('version');
}

/**
* Checks if the $version is for all migrations
*
* @return bool Returns true if it should try to mark all versions
*/
protected function isAllVersion()
{
if ($this->isUsingDeprecatedVersion()) {
return false;
}

return $this->isUsingDeprecatedAll() || $this->input->getOption('target') === null;
$this->getManager()->markVersionsAsMigrated($path, $versions, $output);
}

/**
Expand All @@ -251,17 +142,6 @@ protected function isUsingDeprecatedAll()
return $version === 'all' || $version === '*';
}

/**
* Checks if the input has the `--only` option or it is using the deprecated version argument
*
* @return bool Returns true when it is trying to mark only one migration
*/
protected function isOnly()
{

return $this->hasOnly() || $this->isUsingDeprecatedVersion();
}

/**
* Checks if the input has the `--exclude` option
*
Expand Down
24 changes: 16 additions & 8 deletions src/Migrations.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,20 +193,28 @@ public function rollback($options = [])
*
* @return bool Success
*/
public function markMigrated($version, $options = [])
public function markMigrated($version = null, $options = [])
{
$this->setCommand('mark_migrated');
$input = $this->getInput('MarkMigrated', ['version' => $version], $options);
$params = [$version];

$isMigrated = $this->run('isMigrated', $params, $input);
if ($isMigrated) {
return true;
if (isset($options['target']) &&
isset($options['exclude']) &&
isset($options['only'])
) {
$exceptionMessage = 'You should use `exclude` OR `only` (not both) along with a `target` argument';
throw new \InvalidArgumentException($exceptionMessage);
}

$params[] = $this->getConfig()->getMigrationPath();
$input = $this->getInput('MarkMigrated', ['version' => $version], $options);
$this->setInput($input);

$params = [
$this->getConfig()->getMigrationPath(),
$this->getManager()->getVersionsToMark($input),
$this->output
];

$this->run('markMigrated', $params, $input);
$this->run('markVersionsAsMigrated', $params, $input);
return true;
}

Expand Down
Loading

0 comments on commit ba856dc

Please sign in to comment.