From 535b78c05bc743dd45a3b1d1012fe79047432954 Mon Sep 17 00:00:00 2001 From: Richard Quadling Date: Thu, 8 Jun 2017 12:51:47 +0100 Subject: [PATCH 1/7] Refactor and standardise some aspects of the AbstractCommand into traits Also, rename and refactor template creation so that it isn't purely related to migrations and will now be consistent for seeds and for the repeatable migrations. --- UPGRADE_0.9.md | 35 ++++++++ docs/commands.rst | 2 +- docs/configuration.rst | 2 +- src/Phinx/Console/Command/AbstractCommand.php | 82 ++++++------------- src/Phinx/Console/Command/Breakpoint.php | 11 +++ src/Phinx/Console/Command/Create.php | 20 ++++- src/Phinx/Console/Command/Migrate.php | 11 +++ src/Phinx/Console/Command/Rollback.php | 13 ++- src/Phinx/Console/Command/SeedCreate.php | 11 +++ src/Phinx/Console/Command/SeedRun.php | 11 +++ src/Phinx/Console/Command/Status.php | 11 +++ src/Phinx/Console/Command/Test.php | 58 ++++++++----- .../Command/Traits/AbstractCommandTrait.php | 12 +++ .../Command/Traits/MigrationCommandTrait.php | 65 +++++++++++++++ .../Command/Traits/SeedCommandTrait.php | 65 +++++++++++++++ src/Phinx/Seed/SeedInterface.php | 1 - .../AbstractTemplateCreation.php | 4 +- .../TemplateCreationInterface.php} | 31 +++---- tests/Phinx/Config/ConfigFileTest.php | 16 +--- tests/Phinx/Config/Fixtures/VoidCommand.php | 26 ++++++ tests/Phinx/Console/Command/CreateTest.php | 6 +- .../DoesNotImplementRequiredInterface.php | 3 +- .../TemplateGenerators/NullGenerator.php | 26 ++---- .../TemplateGenerators/SimpleGenerator.php | 23 ++---- 24 files changed, 385 insertions(+), 160 deletions(-) create mode 100644 UPGRADE_0.9.md create mode 100644 src/Phinx/Console/Command/Traits/AbstractCommandTrait.php create mode 100644 src/Phinx/Console/Command/Traits/MigrationCommandTrait.php create mode 100644 src/Phinx/Console/Command/Traits/SeedCommandTrait.php rename src/Phinx/{Migration => Templates}/AbstractTemplateCreation.php (95%) rename src/Phinx/{Migration/CreationInterface.php => Templates/TemplateCreationInterface.php} (76%) create mode 100644 tests/Phinx/Config/Fixtures/VoidCommand.php diff --git a/UPGRADE_0.9.md b/UPGRADE_0.9.md new file mode 100644 index 000000000..846cccff2 --- /dev/null +++ b/UPGRADE_0.9.md @@ -0,0 +1,35 @@ +# Upgrading Phinx to 0.9 + +* Template Creation is now supported for use by Migrations, Repeatable Migrations and Seeds. + + Some renaming of the interface, abstract base class and methods has + been undertaken so that the names are not tied specifically to + Migrations. + + The following elements have been renamed: + + * Interface + + Phinx 0.8 + `Phinx\Migration\CreationInterface` + + Phinx 0.9 + `Phinx\Templates\TemplateCreationInterface` + + * Class + + Phinx 0.8 + `Phinx\Migration\AbstractTemplateCreation` + + Phinx 0.9 + `Phinx\Templates\AbstractTemplateCreation` + + * Methods + + Phinx 0.8: + `Phinx\Migration\CreationInterface\getMigrationTemplate()`, + `Phinx\Migration\CreationInterface\postMigrationCreation($migrationFilename, $className, $baseClassName)` + + Phinx 0.9 + `Phinx\Templates\TemplateCreationInterface\getTemplate()`, + `Phinx\Templates\TemplateCreationInterface\postTemplateCreation($filename, $className, $baseClassName)` diff --git a/docs/commands.rst b/docs/commands.rst index 8dea85b83..1de9e6bf9 100644 --- a/docs/commands.rst +++ b/docs/commands.rst @@ -57,7 +57,7 @@ alternative template filename. $ phinx create MyNewMigration --template="" You can also supply a template generating class. This class must implement the -interface ``Phinx\Migration\CreationInterface``. +interface ``Phinx\Templates\TemplateCreationInterface``. .. code-block:: bash diff --git a/docs/configuration.rst b/docs/configuration.rst index 8f2ef3657..e1c7cb8e8 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -293,7 +293,7 @@ Aliases Template creation class names can be aliased and used with the ``--class`` command line option for the :doc:`Create Command `. -The aliased classes will still be required to implement the ``Phinx\Migration\CreationInterface`` interface. +The aliased classes will still be required to implement the ``Phinx\Templates\TemplateCreationInterface`` interface. .. code-block:: yaml diff --git a/src/Phinx/Console/Command/AbstractCommand.php b/src/Phinx/Console/Command/AbstractCommand.php index b5bd83d87..54e448727 100644 --- a/src/Phinx/Console/Command/AbstractCommand.php +++ b/src/Phinx/Console/Command/AbstractCommand.php @@ -49,12 +49,12 @@ abstract class AbstractCommand extends Command /** * The location of the default migration template. */ - const DEFAULT_MIGRATION_TEMPLATE = '/../../Migration/Migration.template.php.dist'; + const DEFAULT_MIGRATION_TEMPLATE = 'Migration/Migration.template.php.dist'; /** * The location of the default seed template. */ - const DEFAULT_SEED_TEMPLATE = '/../../Seed/Seed.template.php.dist'; + const DEFAULT_SEED_TEMPLATE = 'Seed/Seed.template.php.dist'; /** * @var ConfigInterface @@ -95,26 +95,7 @@ public function bootstrap(InputInterface $input, OutputInterface $output) $this->loadManager($input, $output); - // report the paths - $paths = $this->getConfig()->getMigrationPaths(); - - $output->writeln('using migration paths '); - - foreach (Util::globAll($paths) as $path) { - $output->writeln(' - ' . realpath($path) . ''); - } - - try { - $paths = $this->getConfig()->getSeedPaths(); - - $output->writeln('using seed paths '); - - foreach (Util::globAll($paths) as $path) { - $output->writeln(' - ' . realpath($path) . ''); - } - } catch (\UnexpectedValueException $e) { - // do nothing as seeds are optional - } + $this->reportPaths($input, $output); } /** @@ -293,70 +274,53 @@ protected function loadManager(InputInterface $input, OutputInterface $output) } /** - * Verify that the migration directory exists and is writable. + * Report a single set of paths. * - * @param string $path - * @throws \InvalidArgumentException - * @return void + * @param InputInterface $input + * @param OutputInterface $output + * @param array $paths + * @param string $pathsLabel */ - protected function verifyMigrationDirectory($path) - { - if (!is_dir($path)) { - throw new \InvalidArgumentException(sprintf( - 'Migration directory "%s" does not exist', - $path - )); - } + protected function reportPathSet(InputInterface $input, OutputInterface $output, array $paths, $pathsLabel) { + $output->writeln(sprintf('using %s paths ', strtolower($pathsLabel))); - if (!is_writable($path)) { - throw new \InvalidArgumentException(sprintf( - 'Migration directory "%s" is not writable', - $path - )); + foreach (Util::globAll($paths) as $path) { + $output->writeln(' - ' . realpath($path) . ''); } } /** - * Verify that the seed directory exists and is writable. + * Verify that a directory exists and is writable. * * @param string $path + * @param string $pathLabel * @throws \InvalidArgumentException * @return void */ - protected function verifySeedDirectory($path) + protected function verifyDirectory($path, $pathLabel) { if (!is_dir($path)) { throw new \InvalidArgumentException(sprintf( - 'Seed directory "%s" does not exist', + '%s directory "%s" does not exist', + ucfirst(strtolower($pathLabel)), $path )); } if (!is_writable($path)) { throw new \InvalidArgumentException(sprintf( - 'Seed directory "%s" is not writable', + '%s directory "%s" is not writable', + ucfirst(strtolower($pathLabel)), $path )); } } /** - * Returns the migration template filename. + * Report paths appropriate to the command * - * @return string - */ - protected function getMigrationTemplateFilename() - { - return __DIR__ . self::DEFAULT_MIGRATION_TEMPLATE; - } - - /** - * Returns the seed template filename. - * - * @return string + * @param InputInterface $input + * @param OutputInterface $output */ - protected function getSeedTemplateFilename() - { - return __DIR__ . self::DEFAULT_SEED_TEMPLATE; - } + abstract protected function reportPaths(InputInterface $input, OutputInterface $output); } diff --git a/src/Phinx/Console/Command/Breakpoint.php b/src/Phinx/Console/Command/Breakpoint.php index 1c2bc49be..9b5a33732 100644 --- a/src/Phinx/Console/Command/Breakpoint.php +++ b/src/Phinx/Console/Command/Breakpoint.php @@ -29,12 +29,15 @@ */ namespace Phinx\Console\Command; +use Phinx\Console\Command\Traits\MigrationCommandTrait; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Breakpoint extends AbstractCommand { + use MigrationCommandTrait; + /** * {@inheritdoc} */ @@ -95,4 +98,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->getManager()->toggleBreakpoint($environment, $version); } } + + /** + * {@inheritdoc} + */ + protected function reportPaths(InputInterface $input, OutputInterface $output) + { + $this->reportMigrationPaths($input, $output); + } } diff --git a/src/Phinx/Console/Command/Create.php b/src/Phinx/Console/Command/Create.php index 5a9a482b7..1100aaf01 100644 --- a/src/Phinx/Console/Command/Create.php +++ b/src/Phinx/Console/Command/Create.php @@ -28,7 +28,8 @@ */ namespace Phinx\Console\Command; -use Phinx\Migration\CreationInterface; +use Phinx\Console\Command\Traits\MigrationCommandTrait; +use Phinx\Templates\TemplateCreationInterface; use Phinx\Util\Util; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -39,10 +40,12 @@ class Create extends AbstractCommand { + use MigrationCommandTrait; + /** * The name of the interface that any external template creation class is required to implement. */ - const CREATION_INTERFACE = 'Phinx\Migration\CreationInterface'; + const CREATION_INTERFACE = 'Phinx\Templates\TemplateCreationInterface'; /** * {@inheritdoc} @@ -265,8 +268,9 @@ protected function execute(InputInterface $input, OutputInterface $output) // Determine the appropriate mechanism to get the template if ($creationClassName) { // Get the template from the creation class + /** @var TemplateCreationInterface $creationClass */ $creationClass = new $creationClassName($input, $output); - $contents = $creationClass->getMigrationTemplate(); + $contents = $creationClass->getTemplate(); } else { // Load the alternative template if it is defined. $contents = file_get_contents($altTemplate ?: $this->getMigrationTemplateFilename()); @@ -290,7 +294,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // Do we need to do the post creation call to the creation class? if (isset($creationClass)) { - $creationClass->postMigrationCreation($filePath, $className, $this->getConfig()->getMigrationBaseClassName()); + $creationClass->postTemplateCreation($filePath, $className, $this->getConfig()->getMigrationBaseClassName()); } $output->writeln('using migration base class ' . $classes['$useClassName']); @@ -305,4 +309,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln('created ' . str_replace(getcwd() . DIRECTORY_SEPARATOR, '', $filePath)); } + + /** + * {@inheritdoc} + */ + protected function reportPaths(InputInterface $input, OutputInterface $output) + { + $this->reportMigrationPaths($input, $output); + } } diff --git a/src/Phinx/Console/Command/Migrate.php b/src/Phinx/Console/Command/Migrate.php index aacce82c3..fc80c2a88 100644 --- a/src/Phinx/Console/Command/Migrate.php +++ b/src/Phinx/Console/Command/Migrate.php @@ -28,12 +28,15 @@ */ namespace Phinx\Console\Command; +use Phinx\Console\Command\Traits\MigrationCommandTrait; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Migrate extends AbstractCommand { + use MigrationCommandTrait; + /** * {@inheritdoc} */ @@ -119,4 +122,12 @@ protected function execute(InputInterface $input, OutputInterface $output) return 0; } + + /** + * {@inheritdoc} + */ + protected function reportPaths(InputInterface $input, OutputInterface $output) + { + $this->reportMigrationPaths($input, $output); + } } diff --git a/src/Phinx/Console/Command/Rollback.php b/src/Phinx/Console/Command/Rollback.php index 495720672..949714429 100644 --- a/src/Phinx/Console/Command/Rollback.php +++ b/src/Phinx/Console/Command/Rollback.php @@ -28,6 +28,7 @@ */ namespace Phinx\Console\Command; +use Phinx\Console\Command\Traits\MigrationCommandTrait; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -35,6 +36,8 @@ class Rollback extends AbstractCommand { + use MigrationCommandTrait; + /** * {@inheritdoc} */ @@ -107,7 +110,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if (isset($envOptions['name'])) { $output->writeln('using database ' . $envOptions['name']); } - + $versionOrder = $this->getConfig()->getVersionOrder(); $output->writeln('ordering by ' . $versionOrder . " time"); @@ -164,4 +167,12 @@ public function getTargetFromDate($date) return $dateTime->format('YmdHis'); } + + /** + * {@inheritdoc} + */ + protected function reportPaths(InputInterface $input, OutputInterface $output) + { + $this->reportMigrationPaths($input, $output); + } } diff --git a/src/Phinx/Console/Command/SeedCreate.php b/src/Phinx/Console/Command/SeedCreate.php index 3c32e45fc..968078d80 100644 --- a/src/Phinx/Console/Command/SeedCreate.php +++ b/src/Phinx/Console/Command/SeedCreate.php @@ -28,6 +28,7 @@ */ namespace Phinx\Console\Command; +use Phinx\Console\Command\Traits\SeedCommandTrait; use Phinx\Util\Util; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -38,6 +39,8 @@ class SeedCreate extends AbstractCommand { + use SeedCommandTrait; + /** * {@inheritdoc} */ @@ -190,4 +193,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln('using seed base class ' . $classes['$useClassName']); $output->writeln('created .' . str_replace(getcwd(), '', $filePath)); } + + /** + * {@inheritdoc} + */ + protected function reportPaths(InputInterface $input, OutputInterface $output) + { + $this->reportSeedPaths($input, $output); + } } diff --git a/src/Phinx/Console/Command/SeedRun.php b/src/Phinx/Console/Command/SeedRun.php index 86962860d..d545f1aea 100644 --- a/src/Phinx/Console/Command/SeedRun.php +++ b/src/Phinx/Console/Command/SeedRun.php @@ -28,12 +28,15 @@ */ namespace Phinx\Console\Command; +use Phinx\Console\Command\Traits\SeedCommandTrait; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class SeedRun extends AbstractCommand { + use SeedCommandTrait; + /** * {@inheritdoc} */ @@ -120,4 +123,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln(''); $output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . ''); } + + /** + * {@inheritdoc} + */ + protected function reportPaths(InputInterface $input, OutputInterface $output) + { + $this->reportSeedPaths($input, $output); + } } diff --git a/src/Phinx/Console/Command/Status.php b/src/Phinx/Console/Command/Status.php index 3d53ecc36..7498a8f98 100644 --- a/src/Phinx/Console/Command/Status.php +++ b/src/Phinx/Console/Command/Status.php @@ -28,12 +28,15 @@ */ namespace Phinx\Console\Command; +use Phinx\Console\Command\Traits\MigrationCommandTrait; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Status extends AbstractCommand { + use MigrationCommandTrait; + /** * {@inheritdoc} */ @@ -87,4 +90,12 @@ protected function execute(InputInterface $input, OutputInterface $output) // print the status return $this->getManager()->printStatus($environment, $format); } + + /** + * {@inheritdoc} + */ + protected function reportPaths(InputInterface $input, OutputInterface $output) + { + $this->reportMigrationPaths($input, $output); + } } diff --git a/src/Phinx/Console/Command/Test.php b/src/Phinx/Console/Command/Test.php index 35bc26c88..ab6366d9a 100644 --- a/src/Phinx/Console/Command/Test.php +++ b/src/Phinx/Console/Command/Test.php @@ -26,8 +26,11 @@ * @package Phinx * @subpackage Phinx\Console */ + namespace Phinx\Console\Command; +use Phinx\Console\Command\Traits\MigrationCommandTrait; +use Phinx\Console\Command\Traits\SeedCommandTrait; use Phinx\Migration\Manager\Environment; use Phinx\Util\Util; use Symfony\Component\Console\Input\InputInterface; @@ -39,6 +42,8 @@ */ class Test extends AbstractCommand { + use MigrationCommandTrait, SeedCommandTrait; + /** * {@inheritdoc} */ @@ -49,16 +54,16 @@ protected function configure() $this->addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment'); $this->setName('test') - ->setDescription('Verify the configuration file') - ->setHelp( -<<setDescription('Verify the configuration file') + ->setHelp( + <<test command verifies the YAML configuration file and optionally an environment phinx test phinx test -e development EOT - ); + ); } /** @@ -66,34 +71,36 @@ protected function configure() * * @param InputInterface $input * @param OutputInterface $output + * * @throws \RuntimeException * @throws \InvalidArgumentException * @return void */ protected function execute(InputInterface $input, OutputInterface $output) { - $this->loadConfig($input, $output); - $this->loadManager($input, $output); + $this->bootstrap($input, $output); - // Verify the migrations path(s) - array_map( - [$this, 'verifyMigrationDirectory'], - Util::globAll($this->getConfig()->getMigrationPaths()) - ); - - // Verify the seed path(s) - array_map( - [$this, 'verifySeedDirectory'], - Util::globAll($this->getConfig()->getSeedPaths()) - ); + // Verify the path(s) + foreach ( + [ + 'verifyMigrationDirectory' => $this->getConfig()->getMigrationPaths(), + 'verifySeedDirectory' => $this->getConfig()->getSeedPaths(), + ] as $verifyDirectoryMethod => $paths) { + array_map( + [$this, $verifyDirectoryMethod], + Util::globAll($paths) + ); + } $envName = $input->getOption('environment'); if ($envName) { if (!$this->getConfig()->hasEnvironment($envName)) { - throw new \InvalidArgumentException(sprintf( - 'The environment "%s" does not exist', - $envName - )); + throw new \InvalidArgumentException( + sprintf( + 'The environment "%s" does not exist', + $envName + ) + ); } $output->writeln(sprintf('validating environment %s', $envName)); @@ -107,4 +114,13 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln('success!'); } + + /** + * {@inheritdoc} + */ + protected function reportPaths(InputInterface $input, OutputInterface $output) + { + $this->reportMigrationPaths($input, $output); + $this->reportSeedPaths($input, $output); + } } diff --git a/src/Phinx/Console/Command/Traits/AbstractCommandTrait.php b/src/Phinx/Console/Command/Traits/AbstractCommandTrait.php new file mode 100644 index 000000000..77657824d --- /dev/null +++ b/src/Phinx/Console/Command/Traits/AbstractCommandTrait.php @@ -0,0 +1,12 @@ +reportPathSet($input, $output, $this->getConfig()->getMigrationPaths(), 'migration'); + } + + /** + * Verify that the migration directory exists and is writable. + * + * @param string $path + * @throws \InvalidArgumentException + * @return void + */ + protected function verifyMigrationDirectory($path) + { + $this->verifyDirectory($path, 'migration'); + } + + /** + * Returns the migration template filename. + * + * @return string + */ + protected function getMigrationTemplateFilename() + { + return __DIR__ . '/../../../' . AbstractCommand::DEFAULT_MIGRATION_TEMPLATE; + } +} diff --git a/src/Phinx/Console/Command/Traits/SeedCommandTrait.php b/src/Phinx/Console/Command/Traits/SeedCommandTrait.php new file mode 100644 index 000000000..37600b872 --- /dev/null +++ b/src/Phinx/Console/Command/Traits/SeedCommandTrait.php @@ -0,0 +1,65 @@ +reportPathSet($input, $output, $this->getConfig()->getSeedPaths(), 'seed'); + } + + /** + * Verify that the seed directory exists and is writable. + * + * @param string $path + * @throws \InvalidArgumentException + * @return void + */ + protected function verifySeedDirectory($path) + { + $this->verifyDirectory($path, 'seed'); + } + + /** + * Returns the seed template filename. + * + * @return string + */ + protected function getSeedTemplateFilename() + { + return __DIR__ . '/../../../' . AbstractCommand::DEFAULT_SEED_TEMPLATE; + } +} diff --git a/src/Phinx/Seed/SeedInterface.php b/src/Phinx/Seed/SeedInterface.php index 5ff36bf37..8b868e81b 100644 --- a/src/Phinx/Seed/SeedInterface.php +++ b/src/Phinx/Seed/SeedInterface.php @@ -30,7 +30,6 @@ use Phinx\Db\Adapter\AdapterInterface; use Phinx\Db\Table; -use Phinx\Migration\MigrationInterface; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; diff --git a/src/Phinx/Migration/AbstractTemplateCreation.php b/src/Phinx/Templates/AbstractTemplateCreation.php similarity index 95% rename from src/Phinx/Migration/AbstractTemplateCreation.php rename to src/Phinx/Templates/AbstractTemplateCreation.php index 504212fb4..2a83509ad 100644 --- a/src/Phinx/Migration/AbstractTemplateCreation.php +++ b/src/Phinx/Templates/AbstractTemplateCreation.php @@ -26,12 +26,12 @@ * @package Phinx * @subpackage Phinx\Migration */ -namespace Phinx\Migration; +namespace Phinx\Templates; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -abstract class AbstractTemplateCreation implements CreationInterface +abstract class AbstractTemplateCreation implements TemplateCreationInterface { /** * @var InputInterface diff --git a/src/Phinx/Migration/CreationInterface.php b/src/Phinx/Templates/TemplateCreationInterface.php similarity index 76% rename from src/Phinx/Migration/CreationInterface.php rename to src/Phinx/Templates/TemplateCreationInterface.php index 2c7d91efe..0e5a4358b 100644 --- a/src/Phinx/Migration/CreationInterface.php +++ b/src/Phinx/Templates/TemplateCreationInterface.php @@ -26,20 +26,20 @@ * @package Phinx * @subpackage Phinx\Migration */ -namespace Phinx\Migration; +namespace Phinx\Templates; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** - * Migration interface + * Template creation interface * * @author Richard Quadling */ -interface CreationInterface +interface TemplateCreationInterface { /** - * CreationInterface constructor. + * TemplateCreationInterface constructor. * * @param InputInterface|null $input * @param OutputInterface|null $output @@ -49,14 +49,14 @@ public function __construct(InputInterface $input = null, OutputInterface $outpu /** * @param InputInterface $input * - * @return CreationInterface + * @return TemplateCreationInterface */ public function setInput(InputInterface $input); /** * @param OutputInterface $output * - * @return CreationInterface + * @return TemplateCreationInterface */ public function setOutput(OutputInterface $output); @@ -71,24 +71,25 @@ public function getInput(); public function getOutput(); /** - * Get the migration template. + * Get the template. * - * This will be the content that Phinx will amend to generate the migration file. + * This will be the content that Phinx will amend to generate the template file. * * @return string The content of the template for Phinx to amend. */ - public function getMigrationTemplate(); + public function getTemplate(); /** - * Post Migration Creation. + * Post Template Creation. * - * Once the migration file has been created, this method will be called, allowing any additional + * Once the template file has been created, this method will be called, allowing any additional * processing, specific to the template to be performed. * - * @param string $migrationFilename The name of the newly created migration. - * @param string $className The class name. - * @param string $baseClassName The name of the base class. + * @param string $filename The name of the newly created file. + * @param string $className The class name. + * @param string $baseClassName The name of the base class. + * * @return void */ - public function postMigrationCreation($migrationFilename, $className, $baseClassName); + public function postTemplateCreation($filename, $className, $baseClassName); } diff --git a/tests/Phinx/Config/ConfigFileTest.php b/tests/Phinx/Config/ConfigFileTest.php index 4c48f4896..808bf1f10 100644 --- a/tests/Phinx/Config/ConfigFileTest.php +++ b/tests/Phinx/Config/ConfigFileTest.php @@ -2,11 +2,10 @@ namespace Test\Phinx\Config; -use Phinx\Console\Command\AbstractCommand; -use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\InputOption; +use Test\Phinx\Config\Fixtures\VoidCommand; class ConfigFileTest extends \PHPUnit_Framework_TestCase { @@ -116,16 +115,3 @@ public function notWorkingProvider() ); } } - -/** - * Class VoidCommand : used to expose locateConfigFile To testing - * - * @package Test\Phinx\Config - */ -class VoidCommand extends AbstractCommand -{ - public function locateConfigFile(InputInterface $input) - { - return parent::locateConfigFile($input); - } -} diff --git a/tests/Phinx/Config/Fixtures/VoidCommand.php b/tests/Phinx/Config/Fixtures/VoidCommand.php new file mode 100644 index 000000000..c99328a4d --- /dev/null +++ b/tests/Phinx/Config/Fixtures/VoidCommand.php @@ -0,0 +1,26 @@ + '\Test\Phinx\Console\Command\TemplateGenerators\DoesNotImplementRequiredInterface'), - 'The class "\Test\Phinx\Console\Command\TemplateGenerators\DoesNotImplementRequiredInterface" does not implement the required interface "Phinx\Migration\CreationInterface"', + 'The class "\Test\Phinx\Console\Command\TemplateGenerators\DoesNotImplementRequiredInterface" does not implement the required interface "Phinx\Templates\TemplateCreationInterface"', ), array( array( @@ -174,7 +174,7 @@ public function provideFailingTemplateGenerator() array( '--class' => 'PoorInterface', ), - 'The class "\Test\Phinx\Console\Command\TemplateGenerators\DoesNotImplementRequiredInterface" via the alias "PoorInterface" does not implement the required interface "Phinx\Migration\CreationInterface"', + 'The class "\Test\Phinx\Console\Command\TemplateGenerators\DoesNotImplementRequiredInterface" via the alias "PoorInterface" does not implement the required interface "Phinx\Templates\TemplateCreationInterface"', ), ); } diff --git a/tests/Phinx/Console/Command/TemplateGenerators/DoesNotImplementRequiredInterface.php b/tests/Phinx/Console/Command/TemplateGenerators/DoesNotImplementRequiredInterface.php index d34f1d0b2..f706a3275 100644 --- a/tests/Phinx/Console/Command/TemplateGenerators/DoesNotImplementRequiredInterface.php +++ b/tests/Phinx/Console/Command/TemplateGenerators/DoesNotImplementRequiredInterface.php @@ -1,7 +1,8 @@ Date: Tue, 9 May 2017 18:49:12 +0100 Subject: [PATCH 2/7] Break up the big abstract command class so that specific elements are composed via traits. Refactoring of templates to allow for a more generalised pattern when it comes to processing templates for migrations, repeatables and seeds. This is still be a Work In Progress (WIP) but will act as the basis for repeatable migrations. --- UPGRADE_0.9.md | 24 ++++--- src/Phinx/Console/Command/AbstractCommand.php | 5 ++ src/Phinx/Console/Command/Test.php | 5 +- .../Command/Traits/MigrationCommandTrait.php | 6 ++ .../RepeatableMigrationCommandTrait.php | 71 +++++++++++++++++++ .../Command/Traits/SeedCommandTrait.php | 6 ++ 6 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 src/Phinx/Console/Command/Traits/RepeatableMigrationCommandTrait.php diff --git a/UPGRADE_0.9.md b/UPGRADE_0.9.md index 846cccff2..9016b1a76 100644 --- a/UPGRADE_0.9.md +++ b/UPGRADE_0.9.md @@ -11,25 +11,33 @@ * Interface Phinx 0.8 - `Phinx\Migration\CreationInterface` + + `Phinx\Migration\CreationInterface` Phinx 0.9 - `Phinx\Templates\TemplateCreationInterface` + + `Phinx\Templates\TemplateCreationInterface`. * Class Phinx 0.8 - `Phinx\Migration\AbstractTemplateCreation` + + `Phinx\Migration\AbstractTemplateCreation` Phinx 0.9 - `Phinx\Templates\AbstractTemplateCreation` + + `Phinx\Templates\AbstractTemplateCreation`. * Methods Phinx 0.8: - `Phinx\Migration\CreationInterface\getMigrationTemplate()`, - `Phinx\Migration\CreationInterface\postMigrationCreation($migrationFilename, $className, $baseClassName)` + + `Phinx\Migration\CreationInterface\getMigrationTemplate()` + + `Phinx\Migration\CreationInterface\postMigrationCreation($migrationFilename, $className, $baseClassName)` Phinx 0.9 - `Phinx\Templates\TemplateCreationInterface\getTemplate()`, - `Phinx\Templates\TemplateCreationInterface\postTemplateCreation($filename, $className, $baseClassName)` + + `Phinx\Templates\TemplateCreationInterface\getTemplate()` + + `Phinx\Templates\TemplateCreationInterface\postTemplateCreation($filename, $className, $baseClassName)` diff --git a/src/Phinx/Console/Command/AbstractCommand.php b/src/Phinx/Console/Command/AbstractCommand.php index 54e448727..032cdffba 100644 --- a/src/Phinx/Console/Command/AbstractCommand.php +++ b/src/Phinx/Console/Command/AbstractCommand.php @@ -51,6 +51,11 @@ abstract class AbstractCommand extends Command */ const DEFAULT_MIGRATION_TEMPLATE = 'Migration/Migration.template.php.dist'; + /** + * The location of the default repeatable migration template. + */ + const DEFAULT_REPEATABLE_MIGRATION_TEMPLATE = 'Repeatable/RepeatableMigration.template.php.dist'; + /** * The location of the default seed template. */ diff --git a/src/Phinx/Console/Command/Test.php b/src/Phinx/Console/Command/Test.php index ab6366d9a..df1dfc92d 100644 --- a/src/Phinx/Console/Command/Test.php +++ b/src/Phinx/Console/Command/Test.php @@ -30,6 +30,7 @@ namespace Phinx\Console\Command; use Phinx\Console\Command\Traits\MigrationCommandTrait; +use Phinx\Console\Command\Traits\RepeatableMigrationCommandTrait; use Phinx\Console\Command\Traits\SeedCommandTrait; use Phinx\Migration\Manager\Environment; use Phinx\Util\Util; @@ -42,7 +43,7 @@ */ class Test extends AbstractCommand { - use MigrationCommandTrait, SeedCommandTrait; + use MigrationCommandTrait, RepeatableMigrationCommandTrait, SeedCommandTrait; /** * {@inheritdoc} @@ -84,6 +85,7 @@ protected function execute(InputInterface $input, OutputInterface $output) foreach ( [ 'verifyMigrationDirectory' => $this->getConfig()->getMigrationPaths(), + 'verifyRepeatableMigrationDirectory' => $this->getConfig()->getRepeatableMigrationPaths(), 'verifySeedDirectory' => $this->getConfig()->getSeedPaths(), ] as $verifyDirectoryMethod => $paths) { array_map( @@ -121,6 +123,7 @@ protected function execute(InputInterface $input, OutputInterface $output) protected function reportPaths(InputInterface $input, OutputInterface $output) { $this->reportMigrationPaths($input, $output); + $this->reportRepeatableMigrationPaths($input, $output); $this->reportSeedPaths($input, $output); } } diff --git a/src/Phinx/Console/Command/Traits/MigrationCommandTrait.php b/src/Phinx/Console/Command/Traits/MigrationCommandTrait.php index 85ae3741d..9a7a3590f 100644 --- a/src/Phinx/Console/Command/Traits/MigrationCommandTrait.php +++ b/src/Phinx/Console/Command/Traits/MigrationCommandTrait.php @@ -36,6 +36,12 @@ trait MigrationCommandTrait { use AbstractCommandTrait; + /** + * Report the paths used for migration commands. + * + * @param InputInterface $input + * @param OutputInterface $output + */ protected function reportMigrationPaths(InputInterface $input, OutputInterface $output) { $this->reportPathSet($input, $output, $this->getConfig()->getMigrationPaths(), 'migration'); diff --git a/src/Phinx/Console/Command/Traits/RepeatableMigrationCommandTrait.php b/src/Phinx/Console/Command/Traits/RepeatableMigrationCommandTrait.php new file mode 100644 index 000000000..46b703ef4 --- /dev/null +++ b/src/Phinx/Console/Command/Traits/RepeatableMigrationCommandTrait.php @@ -0,0 +1,71 @@ +reportPathSet($input, $output, $this->getConfig()->getRepeatableMigrationPaths(), 'repeatable migration'); + } + + /** + * Verify that the repeatable migration directory exists and is writable. + * + * @param string $path + * @throws \InvalidArgumentException + * @return void + */ + protected function verifyRepeatableMigrationDirectory($path) + { + $this->verifyDirectory($path, 'repeatable migration'); + } + + /** + * Returns the repeatable migration template filename. + * + * @return string + */ + protected function getRepeatableMigrationTemplateFilename() + { + return __DIR__ . '/../../../' . AbstractCommand::DEFAULT_REPEATABLE_MIGRATION_TEMPLATE; + } +} diff --git a/src/Phinx/Console/Command/Traits/SeedCommandTrait.php b/src/Phinx/Console/Command/Traits/SeedCommandTrait.php index 37600b872..d6ebc7807 100644 --- a/src/Phinx/Console/Command/Traits/SeedCommandTrait.php +++ b/src/Phinx/Console/Command/Traits/SeedCommandTrait.php @@ -36,6 +36,12 @@ trait SeedCommandTrait { use AbstractCommandTrait; + /** + * Report the paths used for migration commands. + * + * @param InputInterface $input + * @param OutputInterface $output + */ protected function reportSeedPaths(InputInterface $input, OutputInterface $output) { $this->reportPathSet($input, $output, $this->getConfig()->getSeedPaths(), 'seed'); From f54f175e65162f56e9c8af9549b32c70b614fc49 Mon Sep 17 00:00:00 2001 From: Richard Quadling Date: Tue, 9 May 2017 18:54:25 +0100 Subject: [PATCH 3/7] Update UPGRADE_0.9.md Slightly better layout --- UPGRADE_0.9.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/UPGRADE_0.9.md b/UPGRADE_0.9.md index 9016b1a76..2a3961ec5 100644 --- a/UPGRADE_0.9.md +++ b/UPGRADE_0.9.md @@ -12,32 +12,30 @@ Phinx 0.8 - `Phinx\Migration\CreationInterface` + Phinx\Migration\CreationInterface Phinx 0.9 - `Phinx\Templates\TemplateCreationInterface`. + Phinx\Templates\TemplateCreationInterface * Class Phinx 0.8 - `Phinx\Migration\AbstractTemplateCreation` + Phinx\Migration\AbstractTemplateCreation Phinx 0.9 - `Phinx\Templates\AbstractTemplateCreation`. + Phinx\Templates\AbstractTemplateCreation * Methods Phinx 0.8: - `Phinx\Migration\CreationInterface\getMigrationTemplate()` - - `Phinx\Migration\CreationInterface\postMigrationCreation($migrationFilename, $className, $baseClassName)` + Phinx\Migration\CreationInterface\getMigrationTemplate()` + Phinx\Migration\CreationInterface\postMigrationCreation($migrationFilename, $className, $baseClassName) Phinx 0.9 - `Phinx\Templates\TemplateCreationInterface\getTemplate()` - - `Phinx\Templates\TemplateCreationInterface\postTemplateCreation($filename, $className, $baseClassName)` + Phinx\Templates\TemplateCreationInterface\getTemplate() + Phinx\Templates\TemplateCreationInterface\postTemplateCreation($filename, $className, $baseClassName) From 724eefa5afb8181257a0be183c163a721042a95e Mon Sep 17 00:00:00 2001 From: Richard Quadling Date: Tue, 9 May 2017 17:59:43 +0100 Subject: [PATCH 4/7] Introduce new repeatable migration path into config Includes updated documentation for the new configuration option and the future of Repeatable Migrations. Also standardises documentation regarding glob'd paths and custom base classes. Various w/s and c/s fixes --- docs/commands.rst | 4 +- docs/configuration.rst | 80 +++++++++++++++++++++++++- phinx.yml | 3 +- src/Phinx/Config/Config.php | 43 ++++++++++++-- src/Phinx/Config/ConfigInterface.php | 23 ++++++++ src/Phinx/Console/PhinxApplication.php | 2 +- 6 files changed, 142 insertions(+), 13 deletions(-) diff --git a/docs/commands.rst b/docs/commands.rst index 1de9e6bf9..85ce0b164 100644 --- a/docs/commands.rst +++ b/docs/commands.rst @@ -148,8 +148,8 @@ breakpoint using the ``--force`` parameter or ``-f`` for short. .. note:: - When rolling back, Phinx orders the executed migrations using - the order specified in the ``version_order`` option of your + When rolling back, Phinx orders the executed migrations using + the order specified in the ``version_order`` option of your ``phinx.yml`` file. Please see the :doc:`Configuration ` chapter for more information. diff --git a/docs/configuration.rst b/docs/configuration.rst index e1c7cb8e8..1a3532d91 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -104,10 +104,65 @@ setting ``migration_base_class`` in your config: migration_base_class: MyMagicalMigration +Repeatable Migration Paths +-------------------------- + +The second option specifies the path to your repeatable migration directory. Phinx uses +``%%PHINX_CONFIG_DIR%%/db/repeatables`` by default. + +.. note:: + + ``%%PHINX_CONFIG_DIR%%`` is a special token and is automatically replaced + with the root directory where your ``phinx.yml`` file is stored. + +In order to overwrite the default ``%%PHINX_CONFIG_DIR%%/db/repeatables``, you +need to add the following to the yaml configuration. + +.. code-block:: yaml + + paths: + repeatables: /your/full/path + +You can also provide multiple repeatable migration paths by using an array in your configuration: + +.. code-block:: yaml + + paths: + repeatables: + - application/module1/repeatables + - application/module2/repeatables + + +You can also use the ``%%PHINX_CONFIG_DIR%%`` token in your path. + +.. code-block:: yaml + + paths: + repeatables: %%PHINX_CONFIG_DIR%%/your/relative/path + +Repeatable migrations are captured with ``glob``, so you can define a pattern for multiple +directories. + +.. code-block:: yaml + + paths: + migrations: %%PHINX_CONFIG_DIR%%/module/*/{views,triggers}/repeatables + +Custom Repeatable Migration Base +-------------------------------- + +By default all repeatable migrations will extend from Phinx's `AbstractRepeatableMigration` class. +This can be set to a custom class that extends from `AbstractRepeatableMigration` by +setting ``repeatable_migration_base_class`` in your config: + +.. code-block:: yaml + + repeatable_migration_base_class: MyMagicalRepeatableMigration + Seed Paths ---------- -The second option specifies the path to your seed directory. Phinx uses +The third option specifies the path to your seed directory. Phinx uses ``%%PHINX_CONFIG_DIR%%/db/seeds`` by default. .. note:: @@ -140,6 +195,25 @@ You can also use the ``%%PHINX_CONFIG_DIR%%`` token in your path. paths: seeds: %%PHINX_CONFIG_DIR%%/your/relative/path +Seeds are captured with ``glob``, so you can define a pattern for multiple +directories. + +.. code-block:: yaml + + paths: + seeds: %%PHINX_CONFIG_DIR%%/module/*/{primary,secondary}/seeds + +Custom Seed Base +---------------- + +By default all seeds will extend from Phinx's `AbstractSeed` class. +This can be set to a custom class that extends from `AbstractSeed` by +setting ``seed_base_class`` in your config: + +.. code-block:: yaml + + seed_base_class: MyMagicalSeeder + Environments ------------ @@ -304,8 +378,8 @@ The aliased classes will still be required to implement the ``Phinx\Templates\Te Version Order ------ -When rolling back or printing the status of migrations, Phinx orders the executed migrations according to the +When rolling back or printing the status of migrations, Phinx orders the executed migrations according to the ``version_order`` option, which can have the following values: * ``creation`` (the default): migrations are ordered by their creation time, which is also part of their filename. -* ``execution``: migrations are ordered by their execution time, also known as start time. \ No newline at end of file +* ``execution``: migrations are ordered by their execution time, also known as start time. diff --git a/phinx.yml b/phinx.yml index 5a7ba85df..a6129e24c 100644 --- a/phinx.yml +++ b/phinx.yml @@ -1,5 +1,6 @@ paths: migrations: %%PHINX_CONFIG_DIR%%/db/migrations + repeatables: %%PHINX_CONFIG_DIR%%/db/repeatables seeds: %%PHINX_CONFIG_DIR%%/db/seeds environments: @@ -32,4 +33,4 @@ environments: port: 3306 charset: utf8 -version_order: creation \ No newline at end of file +version_order: creation diff --git a/src/Phinx/Config/Config.php b/src/Phinx/Config/Config.php index 4a052b21f..eb729d9d8 100644 --- a/src/Phinx/Config/Config.php +++ b/src/Phinx/Config/Config.php @@ -251,10 +251,7 @@ public function getMigrationPaths() } /** - * Gets the base class name for migrations. - * - * @param boolean $dropNamespace Return the base migration class name without the namespace. - * @return string + * {@inheritdoc} */ public function getMigrationBaseClassName($dropNamespace = true) { @@ -263,6 +260,32 @@ public function getMigrationBaseClassName($dropNamespace = true) return $dropNamespace ? substr(strrchr($className, '\\'), 1) ?: $className : $className; } + /** + * {@inheritdoc} + */ + public function getRepeatableMigrationPaths() + { + if (!isset($this->values['paths']['repeatables'])) { + throw new \UnexpectedValueException('Repeatables path missing from config file'); + } + + if (is_string($this->values['paths']['repeatables'])) { + $this->values['paths']['repeatables'] = array($this->values['paths']['repeatables']); + } + + return $this->values['paths']['repeatables']; + } + + /** + * @inheritDoc + */ + public function getRepeatableMigrationBaseClassName($dropNamespace = true) + { + $className = !isset($this->values['repeatable_migration_base_class']) ? 'Phinx\Repeatable\AbstractRepeatableMigration' : $this->values['repeatable_migration_base_class']; + + return $dropNamespace ? substr(strrchr($className, '\\'), 1) ?: $className : $className; + } + /** * {@inheritdoc} */ @@ -279,6 +302,16 @@ public function getSeedPaths() return $this->values['paths']['seeds']; } + /** + * @inheritDoc + */ + public function getSeedBaseClassName($dropNamespace = true) + { + $className = !isset($this->values['seed_base_class']) ? 'Phinx\Seed\AbstractSeed' : $this->values['seed_base_class']; + + return $dropNamespace ? substr(strrchr($className, '\\'), 1) ?: $className : $className; + } + /** * Get the template file name. * @@ -333,8 +366,6 @@ public function isVersionOrderCreationTime() return $versionOrder == self::VERSION_ORDER_CREATION_TIME; } - - /** * Replace tokens in the specified array. * diff --git a/src/Phinx/Config/ConfigInterface.php b/src/Phinx/Config/ConfigInterface.php index 2fa1f4896..6f0515b5a 100644 --- a/src/Phinx/Config/ConfigInterface.php +++ b/src/Phinx/Config/ConfigInterface.php @@ -95,6 +95,13 @@ public function getConfigFilePath(); */ public function getMigrationPaths(); + /** + * Gets the paths to search for repeatable migration files. + * + * @return string[] + */ + public function getRepeatableMigrationPaths(); + /** * Gets the paths to search for seed files. * @@ -137,4 +144,20 @@ public function isVersionOrderCreationTime(); * @return string */ public function getMigrationBaseClassName($dropNamespace = true); + + /** + * Gets the base class name for repeatable migrations. + * + * @param boolean $dropNamespace Return the base repeatable migration class name without the namespace. + * @return string + */ + public function getRepeatableMigrationBaseClassName($dropNamespace = true); + + /** + * Gets the base class name for seeders. + * + * @param boolean $dropNamespace Return the base seeder class name without the namespace. + * @return string + */ + public function getSeedBaseClassName($dropNamespace = true); } diff --git a/src/Phinx/Console/PhinxApplication.php b/src/Phinx/Console/PhinxApplication.php index d641b98df..2246cbd8e 100644 --- a/src/Phinx/Console/PhinxApplication.php +++ b/src/Phinx/Console/PhinxApplication.php @@ -28,10 +28,10 @@ */ namespace Phinx\Console; +use Phinx\Console\Command; use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Phinx\Console\Command; /** * Phinx console application. From c7841f13a68a2d2aa6667227ab1e9488562f6eab Mon Sep 17 00:00:00 2001 From: Richard Quadling Date: Wed, 10 May 2017 20:00:36 +0100 Subject: [PATCH 5/7] Add missing docblocks to traits --- src/Phinx/Console/Command/Test.php | 4 +++- src/Phinx/Console/Command/Traits/MigrationCommandTrait.php | 1 - .../Command/Traits/RepeatableMigrationCommandTrait.php | 1 - src/Phinx/Console/Command/Traits/SeedCommandTrait.php | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Phinx/Console/Command/Test.php b/src/Phinx/Console/Command/Test.php index df1dfc92d..4711e57b1 100644 --- a/src/Phinx/Console/Command/Test.php +++ b/src/Phinx/Console/Command/Test.php @@ -43,7 +43,9 @@ */ class Test extends AbstractCommand { - use MigrationCommandTrait, RepeatableMigrationCommandTrait, SeedCommandTrait; + use MigrationCommandTrait; + use RepeatableMigrationCommandTrait; + use SeedCommandTrait; /** * {@inheritdoc} diff --git a/src/Phinx/Console/Command/Traits/MigrationCommandTrait.php b/src/Phinx/Console/Command/Traits/MigrationCommandTrait.php index 9a7a3590f..13f489af1 100644 --- a/src/Phinx/Console/Command/Traits/MigrationCommandTrait.php +++ b/src/Phinx/Console/Command/Traits/MigrationCommandTrait.php @@ -52,7 +52,6 @@ protected function reportMigrationPaths(InputInterface $input, OutputInterface $ * * @param string $path * @throws \InvalidArgumentException - * @return void */ protected function verifyMigrationDirectory($path) { diff --git a/src/Phinx/Console/Command/Traits/RepeatableMigrationCommandTrait.php b/src/Phinx/Console/Command/Traits/RepeatableMigrationCommandTrait.php index 46b703ef4..7f2f000cd 100644 --- a/src/Phinx/Console/Command/Traits/RepeatableMigrationCommandTrait.php +++ b/src/Phinx/Console/Command/Traits/RepeatableMigrationCommandTrait.php @@ -52,7 +52,6 @@ protected function reportRepeatableMigrationPaths(InputInterface $input, OutputI * * @param string $path * @throws \InvalidArgumentException - * @return void */ protected function verifyRepeatableMigrationDirectory($path) { diff --git a/src/Phinx/Console/Command/Traits/SeedCommandTrait.php b/src/Phinx/Console/Command/Traits/SeedCommandTrait.php index d6ebc7807..13e89395c 100644 --- a/src/Phinx/Console/Command/Traits/SeedCommandTrait.php +++ b/src/Phinx/Console/Command/Traits/SeedCommandTrait.php @@ -37,7 +37,7 @@ trait SeedCommandTrait use AbstractCommandTrait; /** - * Report the paths used for migration commands. + * Report the paths used for seed commands. * * @param InputInterface $input * @param OutputInterface $output @@ -52,7 +52,6 @@ protected function reportSeedPaths(InputInterface $input, OutputInterface $outpu * * @param string $path * @throws \InvalidArgumentException - * @return void */ protected function verifySeedDirectory($path) { From 00f5e08a924a88880f0d832e90c8ee276572e401 Mon Sep 17 00:00:00 2001 From: Richard Quadling Date: Wed, 10 May 2017 20:34:07 +0100 Subject: [PATCH 6/7] Split Util into traits for Migrations, Repeatables and Seeds --- src/Phinx/Console/Command/Create.php | 2 +- src/Phinx/Migration/Manager.php | 12 +- src/Phinx/Util/Traits/MigrationUtilTrait.php | 110 +++++++++++++++ .../Traits/RepeatableMigrationUtilTrait.php | 96 +++++++++++++ src/Phinx/Util/Traits/SeedUtilTrait.php | 96 +++++++++++++ src/Phinx/Util/Util.php | 129 ++---------------- tests/Phinx/Util/UtilTest.php | 4 +- 7 files changed, 323 insertions(+), 126 deletions(-) create mode 100644 src/Phinx/Util/Traits/MigrationUtilTrait.php create mode 100644 src/Phinx/Util/Traits/RepeatableMigrationUtilTrait.php create mode 100644 src/Phinx/Util/Traits/SeedUtilTrait.php diff --git a/src/Phinx/Console/Command/Create.php b/src/Phinx/Console/Command/Create.php index 1100aaf01..4c55f9e38 100644 --- a/src/Phinx/Console/Command/Create.php +++ b/src/Phinx/Console/Command/Create.php @@ -187,7 +187,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } // Compute the file path - $fileName = Util::mapClassNameToFileName($className); + $fileName = Util::mapClassNameToMigrationFileName($className); $filePath = $path . DIRECTORY_SEPARATOR . $fileName; if (is_file($filePath)) { diff --git a/src/Phinx/Migration/Manager.php b/src/Phinx/Migration/Manager.php index 6c7ca9f60..c1271fe79 100644 --- a/src/Phinx/Migration/Manager.php +++ b/src/Phinx/Migration/Manager.php @@ -147,7 +147,7 @@ public function printStatus($environment, $format = null) } if (empty($sortedMigrations) && !empty($missingVersions)) { - // this means we have no up migrations, so we write all the missing versions already so they show up + // this means we have no up migrations, so we write all the missing versions already so they show up // before any possible down migration foreach ($missingVersions as $missingVersionCreationTime => $missingVersion) { $this->printMissingVersion($missingVersion, $maxNameLength); @@ -156,7 +156,7 @@ public function printStatus($environment, $format = null) } } - // any migration left in the migrations (ie. not unset when sorting the migrations by the version order) is + // any migration left in the migrations (ie. not unset when sorting the migrations by the version order) is // a migration that is down, so we add them to the end of the sorted migrations list if (!empty($migrations)) { $sortedMigrations = array_merge($sortedMigrations, $migrations); @@ -174,7 +174,7 @@ public function printStatus($environment, $format = null) } else { if ($missingVersion['start_time'] > $version['start_time']) { break; - } elseif ($missingVersion['start_time'] == $version['start_time'] && + } elseif ($missingVersion['start_time'] == $version['start_time'] && $missingVersion['version'] > $version['version']) { break; } @@ -438,7 +438,7 @@ public function rollback($environment, $target = null, $force = false, $targetMu if (isset($migrations[$versionCreationTime])) { array_unshift($sortedMigrations, $migrations[$versionCreationTime]); } else { - // this means the version is missing so we unset it so that we don't consider it when rolling back + // this means the version is missing so we unset it so that we don't consider it when rolling back // migrations (or choosing the last up version as target) unset($executedVersions[$versionCreationTime]); } @@ -626,7 +626,7 @@ public function setMigrations(array $migrations) } /** - * Gets an array of the database migrations, indexed by migration name (aka creation time) and sorted in ascending + * Gets an array of the database migrations, indexed by migration name (aka creation time) and sorted in ascending * order * * @throws \InvalidArgumentException @@ -651,7 +651,7 @@ public function getMigrations() } // convert the filename to a class name - $class = Util::mapFileNameToClassName(basename($filePath)); + $class = Util::mapMigrationFileNameToClassName(basename($filePath)); if (isset($fileNames[$class])) { throw new \InvalidArgumentException(sprintf( diff --git a/src/Phinx/Util/Traits/MigrationUtilTrait.php b/src/Phinx/Util/Traits/MigrationUtilTrait.php new file mode 100644 index 000000000..7cb1cad12 --- /dev/null +++ b/src/Phinx/Util/Traits/MigrationUtilTrait.php @@ -0,0 +1,110 @@ +format(static::DATE_FORMAT); } - /** - * Gets an array of all the existing migration class names. - * - * @return string[] - */ - public static function getExistingMigrationClassNames($path) - { - $classNames = array(); - - if (!is_dir($path)) { - return $classNames; - } - - // filter the files to only get the ones that match our naming scheme - $phpFiles = glob($path . DIRECTORY_SEPARATOR . '*.php'); - - foreach ($phpFiles as $filePath) { - if (preg_match('/([0-9]+)_([_a-z0-9]*).php/', basename($filePath))) { - $classNames[] = static::mapFileNameToClassName(basename($filePath)); - } - } - - return $classNames; - } - - /** - * Get the version from the beginning of a file name. - * - * @param string $fileName File Name - * @return string - */ - public static function getVersionFromFileName($fileName) - { - $matches = array(); - preg_match('/^[0-9]+/', basename($fileName), $matches); - return $matches[0]; - } - - /** - * Turn migration names like 'CreateUserTable' into file names like - * '12345678901234_create_user_table.php' or 'LimitResourceNamesTo30Chars' into - * '12345678901234_limit_resource_names_to_30_chars.php'. - * - * @param string $className Class Name - * @return string - */ - public static function mapClassNameToFileName($className) - { - $arr = preg_split('/(?=[A-Z])/', $className); - unset($arr[0]); // remove the first element ('') - $fileName = static::getCurrentTimestamp() . '_' . strtolower(implode($arr, '_')) . '.php'; - return $fileName; - } - - /** - * Turn file names like '12345678901234_create_user_table.php' into class - * names like 'CreateUserTable'. - * - * @param string $fileName File Name - * @return string - */ - public static function mapFileNameToClassName($fileName) - { - $matches = array(); - if (preg_match(static::MIGRATION_FILE_NAME_PATTERN, $fileName, $matches)) { - $fileName = $matches[1]; - } - - return str_replace(' ', '', ucwords(str_replace('_', ' ', $fileName))); - } - - /** - * Check if a migration class name is unique regardless of the - * timestamp. - * - * This method takes a class name and a path to a migrations directory. - * - * Migration class names must be in CamelCase format. - * e.g: CreateUserTable or AddIndexToPostsTable. - * - * Single words are not allowed on their own. - * - * @param string $className Class Name - * @param string $path Path - * @return boolean - */ - public static function isUniqueMigrationClassName($className, $path) - { - $existingClassNames = static::getExistingMigrationClassNames($path); - return !(in_array($className, $existingClassNames)); - } - /** * Check if a migration/seed class name is valid. * @@ -164,33 +83,9 @@ public static function isValidPhinxClassName($className) return (bool) preg_match('/^([A-Z][a-z0-9]+)+$/', $className); } - /** - * Check if a migration file name is valid. - * - * @param string $fileName File Name - * @return boolean - */ - public static function isValidMigrationFileName($fileName) - { - $matches = array(); - return preg_match(static::MIGRATION_FILE_NAME_PATTERN, $fileName, $matches); - } - - /** - * Check if a seed file name is valid. - * - * @param string $fileName File Name - * @return boolean - */ - public static function isValidSeedFileName($fileName) - { - $matches = array(); - return preg_match(static::SEED_FILE_NAME_PATTERN, $fileName, $matches); - } - /** * Expands a set of paths with curly braces (if supported by the OS). - * + * * @param array $paths * @return array */ diff --git a/tests/Phinx/Util/UtilTest.php b/tests/Phinx/Util/UtilTest.php index 2e5dfb656..2f94a4b73 100644 --- a/tests/Phinx/Util/UtilTest.php +++ b/tests/Phinx/Util/UtilTest.php @@ -55,7 +55,7 @@ public function testMapClassNameToFileName() ); foreach ($expectedResults as $input => $expectedResult) { - $this->assertRegExp($expectedResult, Util::mapClassNameToFileName($input)); + $this->assertRegExp($expectedResult, Util::mapClassNameToMigrationFileName($input)); } } @@ -67,7 +67,7 @@ public function testMapFileNameToClassName() ); foreach ($expectedResults as $input => $expectedResult) { - $this->assertEquals($expectedResult, Util::mapFileNameToClassName($input)); + $this->assertEquals($expectedResult, Util::mapMigrationFileNameToClassName($input)); } } From a1c632d7d8816bc39c6ca4a9af91964e110d94f1 Mon Sep 17 00:00:00 2001 From: Richard Quadling Date: Wed, 10 May 2017 20:46:05 +0100 Subject: [PATCH 7/7] Abstract aspects of 'create' for migrations, repeatable migrations and seeders --- src/Phinx/Console/Command/AbstractCommand.php | 1 + .../Console/Command/AbstractCreateCommand.php | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/Phinx/Console/Command/AbstractCreateCommand.php diff --git a/src/Phinx/Console/Command/AbstractCommand.php b/src/Phinx/Console/Command/AbstractCommand.php index 032cdffba..d9556d479 100644 --- a/src/Phinx/Console/Command/AbstractCommand.php +++ b/src/Phinx/Console/Command/AbstractCommand.php @@ -81,6 +81,7 @@ abstract class AbstractCommand extends Command */ protected function configure() { + parent::configure(); $this->addOption('--configuration', '-c', InputOption::VALUE_REQUIRED, 'The configuration file to load'); $this->addOption('--parser', '-p', InputOption::VALUE_REQUIRED, 'Parser used to read the config file. Defaults to YAML'); } diff --git a/src/Phinx/Console/Command/AbstractCreateCommand.php b/src/Phinx/Console/Command/AbstractCreateCommand.php new file mode 100644 index 000000000..8157de875 --- /dev/null +++ b/src/Phinx/Console/Command/AbstractCreateCommand.php @@ -0,0 +1,82 @@ + + */ +abstract class AbstractCreateCommand extends AbstractCommand +{ + /** + * The name of the interface that any external template creation class is required to implement. + */ + const CREATION_INTERFACE = 'Phinx\Templates\TemplateCreationInterface'; + + /** + * @inheritDoc + */ + protected function configure() + { + parent::configure(); + + // An alternative template. + $this->addOption( + 'template', + 't', + InputOption::VALUE_REQUIRED, + 'Use an alternative template' + ); + + // A classname to be used to gain access to the template content as well as the ability to + // have a callback once the migration file has been created. + $this->addOption( + 'class', + 'l', + InputOption::VALUE_REQUIRED, + 'Use a class implementing "'.self::CREATION_INTERFACE.'" to generate the template' + ); + + // Allow the migration path to be chosen non-interactively. + $this->addOption( + 'path', + null, + InputOption::VALUE_REQUIRED, + sprintf( + 'Specify the path in which to %s', + lcfirst($this->getDescription()) + ) + ); + + } +}