diff --git a/framework/core/CHANGELOG.md b/framework/core/CHANGELOG.md index faa1b4cc9..868b2d627 100644 --- a/framework/core/CHANGELOG.md +++ b/framework/core/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - External authentication (social login) API. - API to set asset compiler filename. +- Migration generator, available via generate:migration console command. ### Changed - Migrations must be namespaced under `Flarum\Migrations\{Core|ExtensionName}`. ([#422](https://github.com/flarum/core/issues/422)) diff --git a/framework/core/src/Console/GenerateMigrationCommand.php b/framework/core/src/Console/GenerateMigrationCommand.php new file mode 100644 index 000000000..7e934480f --- /dev/null +++ b/framework/core/src/Console/GenerateMigrationCommand.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Console; + +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Question\Question; +use Flarum\Migrations\MigrationCreator; + +class GenerateMigrationCommand extends Command +{ + /** + * @var MigrationCreator + */ + protected $creator; + + public function __construct(MigrationCreator $creator) + { + parent::__construct(); + + $this->creator = $creator; + } + + protected function configure() + { + $this + ->setName('generate:migration') + ->setDescription("Generate a migration.") + ->addArgument( + 'name', + InputArgument::REQUIRED, + 'The name of the migration.' + ) + ->addOption( + 'extension', + null, + InputOption::VALUE_REQUIRED, + 'The extension to generate the migration for.' + ) + ->addOption( + 'create', + null, + InputOption::VALUE_REQUIRED, + 'The table to be created.' + ) + ->addOption( + 'table', + null, + InputOption::VALUE_REQUIRED, + 'The table to migrate.' + ); + } + + /** + * Execute the console command. + * + * @return void + */ + protected function fire() + { + $name = $this->input->getArgument('name'); + + $extension = $this->input->getOption('extension'); + + $table = $this->input->getOption('table'); + + $create = $this->input->getOption('create'); + + if (! $table && is_string($create)) { + $table = $create; + } + + $this->writeMigration($name, $extension, $table, $create); + } + + /** + * Write the migration file to disk. + * + * @param string $name + * @param string $extension + * @param string $table + * @param bool $create + * @return string + */ + protected function writeMigration($name, $extension, $table, $create) + { + $path = $this->creator->create($name, $extension, $table, $create); + + $file = pathinfo($path, PATHINFO_FILENAME); + + $this->info("Created migration: $file"); + } +} diff --git a/framework/core/src/Migrations/MigrationCreator.php b/framework/core/src/Migrations/MigrationCreator.php new file mode 100755 index 000000000..ed7789694 --- /dev/null +++ b/framework/core/src/Migrations/MigrationCreator.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Migrations; + +use Illuminate\Support\Str; +use Illuminate\Filesystem\Filesystem; + +class MigrationCreator +{ + /** + * The filesystem instance. + * + * @var Filesystem + */ + protected $files; + + /** + * Create a new migrator instance. + * + * @param Filesystem $files + */ + public function __construct(Filesystem $files) + { + $this->files = $files; + } + + /** + * Create a new migration for the given extension. + * + * @param string $name + * @param string $path + * @param string $table + * @param bool $create + * @return string + */ + public function create($name, $extension = null, $table = null, $create = false) + { + $migrationPath = $this->getMigrationPath($extension); + + $path = $this->getPath($name, $migrationPath); + + $stub = $this->getStub($table, $create); + + $this->files->put($path, $this->populateStub($extension, $name, $stub, $table)); + + return $path; + } + + /** + * Get the migration stub file. + * + * @param string $table + * @param bool $create + * @return string + */ + protected function getStub($table, $create) + { + if (is_null($table)) { + return $this->files->get($this->getStubPath().'/blank.stub'); + } + + // We also have stubs for creating new tables and modifying existing tables + // to save the developer some typing when they are creating a new tables + // or modifying existing tables. We'll grab the appropriate stub here. + $stub = $create ? 'create.stub' : 'update.stub'; + + return $this->files->get($this->getStubPath()."/{$stub}"); + } + + /** + * Populate the place-holders in the migration stub. + * + * @param string $name + * @param string $stub + * @param string $table + * @return string + */ + protected function populateStub($extension, $name, $stub, $table) + { + $replacements = [ + '{{extension}}' => Str::studly($extension) ?: 'Core', + '{{name}}' => Str::studly($name), + '{{table}}' => $table + ]; + + return str_replace(array_keys($replacements), array_values($replacements), $stub); + } + + /** + * Get the full path name to the migration directory. + * + * @param string $extension + * @return string + */ + protected function getMigrationPath($extension) + { + $parent = $extension ? public_path().'/extensions/'.$extension : __DIR__.'/../..'; + + return $parent.'/migrations'; + } + + /** + * Get the full path name to the migration. + * + * @param string $name + * @param string $path + * @return string + */ + protected function getPath($name, $path) + { + return $path.'/'.$this->getDatePrefix().'_'.$name.'.php'; + } + + /** + * Get the date prefix for the migration. + * + * @return string + */ + protected function getDatePrefix() + { + return date('Y_m_d_His'); + } + + /** + * Get the path to the stubs. + * + * @return string + */ + protected function getStubPath() + { + return __DIR__.'/../../stubs/migrations'; + } +} diff --git a/framework/core/stubs/migrations/blank.stub b/framework/core/stubs/migrations/blank.stub new file mode 100644 index 000000000..af4c5dfe3 --- /dev/null +++ b/framework/core/stubs/migrations/blank.stub @@ -0,0 +1,29 @@ +schema->create('{{table}}', function (Blueprint $table) { + $table->increments('id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $this->schema->drop('{{table}}'); + } +} diff --git a/framework/core/stubs/migrations/update.stub b/framework/core/stubs/migrations/update.stub new file mode 100644 index 000000000..a68cae48c --- /dev/null +++ b/framework/core/stubs/migrations/update.stub @@ -0,0 +1,33 @@ +schema->table('{{table}}', function (Blueprint $table) { + // + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $this->schema->table('{{table}}', function (Blueprint $table) { + // + }); + } +}