diff --git a/docs/guide/db-migrations.md b/docs/guide/db-migrations.md index 5349a07..5c83cea 100644 --- a/docs/guide/db-migrations.md +++ b/docs/guide/db-migrations.md @@ -181,17 +181,20 @@ class m150101_185401_create_news_table extends Migration A list of all available methods for defining the column types is available in the API documentation of [[yii\db\SchemaBuilderTrait]]. -## Creating Migrations with Generators +## Generating Migrations -Since version 2.0.7 migration console which provides convenient way creating migrations. +Since version 2.0.7 migration console provides a convenient way to create migrations. -If the migration name is of the form "create_xxx" or "drop_xxx" then a migration creating the table xxx with the columns listed will be generated. For example: +If the migration name is of a special form including but not limited to `create_xxx` or `drop_xxx` then migration +file would contain extra code when generated. + +### Create Table ```php yii migrate/create create_post ``` -generates +generates ```php class m150811_220037_create_post extends Migration @@ -210,13 +213,13 @@ class m150811_220037_create_post extends Migration } ``` -For create column schema you may use fields option with as follows: +To create table fields right away, specify them via `--fields` option. ```php yii migrate/create create_post --fields=title:string,body:text ``` -generates +generates ```php class m150811_220037_create_post extends Migration @@ -237,7 +240,7 @@ class m150811_220037_create_post extends Migration } ``` -You are not limited to one magically generated column. For example: +You can specify more field parameters. ```php yii migrate/create create_post --fields=title:string(12):notNull:unique,body:text @@ -264,10 +267,11 @@ class m150811_220037_create_post extends Migration } ``` -> Note: primary Key is added automatically, if you want to use another name for primary key, you -may specify in fields options, for example "--fields=name:primaryKey" +> Note: primary key is added automatically and is named `id` by default. If you want to use another name you may +> specify it explicitly like `--fields=name:primaryKey`. + -Similarly, you can generate a migration to drop table from the command line: +### Drop Table ```php yii migrate/create drop_post @@ -291,16 +295,21 @@ class m150811_220037_drop_post extends Migration } ``` -If the migration name is of the form "add_xxx_from_yyy" or "drop_xxx_from_yyy" then a migration containing the appropriate addColumn and dropColumn statements will be created. +### Add Column + +If the migration name is of the form `add_xxx_to_yyy` then the file content would contain `addColumn` and `dropColumn` +statements necessary. + +To add column: ```php -yii migrate/create add_position_from_post --fields=position:integer +yii migrate/create add_position_to_post --fields=position:integer ``` generates ```php -class m150811_220037_add_position_from_post extends Migration +class m150811_220037_add_position_to_post extends Migration { public function up() { @@ -314,7 +323,10 @@ class m150811_220037_add_position_from_post extends Migration } ``` -Similarly, you can generate a migration to remove a column from the command line: +### Drop Column + +If the migration name is of the form `drop_xxx_from_yyy` then the file content would contain `addColumn` and `dropColumn` +statements necessary. ```php yii migrate/create drop_position_from_post --fields=position:integer @@ -337,16 +349,19 @@ class m150811_220037_remove_position_from_post extends Migration } ``` -There is also a generator which will produce join tables If the migration name is of the form "create_join_xxx_and_yyy" +### Add Junction Table + +If the migration name is in if the form of `create_junction_xxx_and_yyy` then code necessary to create junction table +will be generated. ```php -yii create/migration create_join_post_and_tag +yii create/migration create_junction_post_and_tag ``` generates ```php -class m150811_220037_create_join_post_and_tag extends Migration +class m150811_220037_create_junction_post_and_tag extends Migration { public function up() { @@ -370,7 +385,6 @@ class m150811_220037_create_join_post_and_tag extends Migration } ``` - ### Transactional Migrations While performing complex DB migrations, it is important to ensure each migration to either succeed or fail as a whole @@ -599,17 +613,18 @@ The migration command comes with a few command-line options that can be used to or a path [alias](concept-aliases.md). The template file is a PHP script in which you can use a predefined variable named `$className` to get the migration class name. -* `generatorTemplateFile`: array (defaults to `[ +* `generatorTemplateFiles`: array (defaults to `[ 'create' => '@yii/views/createMigration.php', 'drop' => '@yii/views/dropMigration.php', 'add' => '@yii/views/addMigration.php', 'remove' => '@yii/views/removeMigration.php', - 'create_join' => '@yii/views/createJoinMigration.php' - ]`), specifies template files for generating migration code automatically. See [Creating Migrations with Generators](#creating-migrations-with-generators) + 'create_junction' => '@yii/views/createJunctionMigration.php' + ]`), specifies template files for generating migration code. See "[Generating Migrations](#generating-migrations)" for more details. -* `fields`: array (defaults to `[]`), specifies the fields column use to creating migration automatically. The format that it use when declaring any applicable schema it is -`COLUMN_NAME:COLUMN_TYPE:COLUMN_DECORATOR`, for example `--fields=name:string(12):notNull`, it specify string column with 12 size and not null. +* `fields`: array of column definition strings used for creating migration code. Defaults to `[]`. The format of each + definition is `COLUMN_NAME:COLUMN_TYPE:COLUMN_DECORATOR`. For example, `--fields=name:string(12):notNull` produces + a string column of size 12 which is not null. The following example shows how you can use these options. diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index b4ecf23..ea2e709 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -48,6 +48,7 @@ Yii Framework 2 Change Log - Enh #8649: Added total applied migrations to final report (vernik91) - Enh #9282: Improved JSON error handling to support PHP 5.5 error codes (freezy-sk) - Enh #9337: Added `yii\db\ColumnSchemaBuilder::defaultExpression()` to support DB Expression as default value (kotchuprik) +- Enh #9465: ./yii migrate/create now generates code based on migration name and --fields (pana1990) - Enh #9476: Added DI injection via controller action method signature (mdmunir) - Enh #9635: Added default CSS class for `\yii\grid\ActionColumn` header (arogachev, dynasource) - Enh #9643: Added migrations for DB cache (mdmunir) diff --git a/framework/console/controllers/BaseMigrateController.php b/framework/console/controllers/BaseMigrateController.php index d8f3c72..48c8df6 100644 --- a/framework/console/controllers/BaseMigrateController.php +++ b/framework/console/controllers/BaseMigrateController.php @@ -42,12 +42,12 @@ abstract class BaseMigrateController extends Controller */ public $templateFile; /** - * @var array the template file for generating migration code automatically. - * This can be either a path alias (e.g. "@app/migrations/template.php") + * @var array a set of template files for generating migration code automatically. + * Each one can be either a path alias (e.g. "@app/migrations/template.php") * or a file path. * @since 2.0.7 */ - public $generatorTemplateFile; + public $generatorTemplateFiles; /** * @var array Fields to be generated * @since 2.0.7 @@ -63,9 +63,7 @@ abstract class BaseMigrateController extends Controller return array_merge( parent::options($actionID), ['migrationPath'], // global for all actions - ($actionID === 'create') - ? ['templateFile', 'templateFileGenerators', 'fields'] - : [] // action create + $actionID === 'create' ? ['templateFile', 'templateFileGenerators', 'fields'] : [] // action create ); } @@ -87,7 +85,7 @@ abstract class BaseMigrateController extends Controller FileHelper::createDirectory($path); } $this->migrationPath = $path; - $this->parseField(); + $this->parseFields(); $version = Yii::getVersion(); $this->stdout("Yii Migration Tool (based on Yii v{$version})\n\n"); @@ -494,36 +492,39 @@ abstract class BaseMigrateController extends Controller $file = $this->migrationPath . DIRECTORY_SEPARATOR . $className . '.php'; if ($this->confirm("Create new migration '$file'?")) { - if (preg_match('/^create_join_(.+)_and_(.+)$/', $name, $matches)) { - $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFile['create_join']), [ + if (preg_match('/^create_junction_(.+)_and_(.+)$/', $name, $matches)) { + $firstTable = mb_strtolower($matches[1], Yii::$app->charset); + $secondTable = mb_strtolower($matches[2], Yii::$app->charset); + + $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['create_junction']), [ 'className' => $className, - 'table' => mb_strtolower($matches[1]) . '_' . mb_strtolower($matches[2]), - 'field_first' => mb_strtolower($matches[1]), - 'field_second' => mb_strtolower($matches[2]), + 'table' => $firstTable . '_' . $secondTable, + 'field_first' => $firstTable, + 'field_second' => $secondTable, ]); - } elseif (preg_match('/^add_(.+)from_(.+)$/', $name, $matches)) { - $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFile['add']), [ + } elseif (preg_match('/^add_(.+)_to_(.+)$/', $name, $matches)) { + $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['add']), [ 'className' => $className, - 'table' => mb_strtolower($matches[2]), + 'table' => mb_strtolower($matches[2], Yii::$app->charset), 'fields' => $this->fields ]); - } elseif (preg_match('/^drop_(.+)from_(.+)$/', $name, $matches)) { - $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFile['remove']), [ + } elseif (preg_match('/^drop_(.+)_from_(.+)$/', $name, $matches)) { + $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['remove']), [ 'className' => $className, - 'table' => mb_strtolower($matches[2]), + 'table' => mb_strtolower($matches[2], Yii::$app->charset), 'fields' => $this->fields ]); } elseif (preg_match('/^create_(.+)$/', $name, $matches)) { - $this->checkPrimaryKey(); - $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFile['create']), [ + $this->addDefaultPrimaryKey(); + $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['create']), [ 'className' => $className, - 'table' => mb_strtolower($matches[1]), + 'table' => mb_strtolower($matches[1], Yii::$app->charset), 'fields' => $this->fields ]); } elseif (preg_match('/^drop_(.+)$/', $name, $matches)) { - $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFile['drop']), [ + $content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['drop']), [ 'className' => $className, - 'table' => mb_strtolower($matches[1]), + 'table' => mb_strtolower($matches[1], Yii::$app->charset), 'fields' => $this->fields ]); } else { @@ -689,10 +690,10 @@ abstract class BaseMigrateController extends Controller } /** - * Parse the command line migration fields. + * Parse the command line migration fields * @since 2.0.7 */ - protected function parseField() + protected function parseFields() { if ($this->fields === null) { $this->fields = []; @@ -704,7 +705,7 @@ abstract class BaseMigrateController extends Controller foreach ($chunks as &$chunk) { if (!preg_match('/(.+?)\(([^)]+)\)/', $chunk)) { - $chunk = $chunk . '()'; + $chunk .= '()'; } } $this->fields[$index] = ['property' => $property, 'decorators' => implode('->', $chunks)]; @@ -712,20 +713,17 @@ abstract class BaseMigrateController extends Controller } /** - * Check fields option contain primaryKey, if fields do not contain primary key it is added + * Adds default primary key to fields list if there's no primary key specified * @since 2.0.7 */ - protected function checkPrimaryKey() + protected function addDefaultPrimaryKey() { - $exitsPk = false; foreach ($this->fields as $field) { if ($field['decorators'] === 'primaryKey()') { - $exitsPk = true; + return; } } - if (!$exitsPk) { - array_unshift($this->fields, ['property' => 'id', 'decorators' => 'primaryKey()']); - } + array_unshift($this->fields, ['property' => 'id', 'decorators' => 'primaryKey()']); } /** diff --git a/framework/console/controllers/MigrateController.php b/framework/console/controllers/MigrateController.php index 8e6f833..8359979 100644 --- a/framework/console/controllers/MigrateController.php +++ b/framework/console/controllers/MigrateController.php @@ -66,12 +66,12 @@ class MigrateController extends BaseMigrateController /** * @inheritdoc */ - public $generatorTemplateFile = [ + public $generatorTemplateFiles = [ 'create' => '@yii/views/createMigration.php', 'drop' => '@yii/views/dropMigration.php', 'add' => '@yii/views/addColumnMigration.php', 'remove' => '@yii/views/dropColumnMigration.php', - 'create_join' => '@yii/views/createJoinMigration.php' + 'create_junction' => '@yii/views/createJunctionMigration.php' ]; /** * @var Connection|array|string the DB connection object or the application component ID of the DB connection to use diff --git a/framework/views/createJoinMigration.php b/framework/views/createJunctionMigration.php similarity index 100% rename from framework/views/createJoinMigration.php rename to framework/views/createJunctionMigration.php diff --git a/tests/framework/console/controllers/MigrateControllerTestTrait.php b/tests/framework/console/controllers/MigrateControllerTestTrait.php index aa8dfaf..e2d4325 100644 --- a/tests/framework/console/controllers/MigrateControllerTestTrait.php +++ b/tests/framework/console/controllers/MigrateControllerTestTrait.php @@ -363,14 +363,14 @@ CODE; public function testGenerateAddColumnMigration() { - $migrationName = 'add_columns_from_test'; + $migrationName = 'add_columns_to_test'; $class = 'm' . gmdate('ymd_His') . '_' . $migrationName; $this->runMigrateControllerAction('create', [ $migrationName, 'fields' => [ 'title:string(10):notNull', 'body:text:notNull', - 'create_at:dateTime' + 'created_at:dateTime' ] ]); $files = FileHelper::findFiles($this->migrationPath); @@ -386,14 +386,14 @@ class {$class} extends Migration { \$this->addColumn('test', 'title', \$this->string(10)->notNull()); \$this->addColumn('test', 'body', \$this->text()->notNull()); - \$this->addColumn('test', 'create_at', \$this->dateTime()); + \$this->addColumn('test', 'created_at', \$this->dateTime()); } public function down() { \$this->dropColumn('test', 'title'); \$this->dropColumn('test', 'body'); - \$this->dropColumn('test', 'create_at'); + \$this->dropColumn('test', 'created_at'); } } @@ -410,7 +410,7 @@ CODE; 'fields' => [ 'title:string(10):notNull', 'body:text:notNull', - 'create_at:dateTime' + 'created_at:dateTime' ] ]); $files = FileHelper::findFiles($this->migrationPath); @@ -426,14 +426,14 @@ class {$class} extends Migration { \$this->dropColumn('test', 'title'); \$this->dropColumn('test', 'body'); - \$this->dropColumn('test', 'create_at'); + \$this->dropColumn('test', 'created_at'); } public function down() { \$this->addColumn('test', 'title', \$this->string(10)->notNull()); \$this->addColumn('test', 'body', \$this->text()->notNull()); - \$this->addColumn('test', 'create_at', \$this->dateTime()); + \$this->addColumn('test', 'created_at', \$this->dateTime()); } } @@ -446,7 +446,7 @@ CODE; 'fields' => [ 'title:string(10):notNull', 'body:text:notNull', - 'create_at:dateTime' + 'created_at:dateTime' ] ]); $files = FileHelper::findFiles($this->migrationPath); @@ -462,14 +462,14 @@ class {$class} extends Migration { \$this->dropColumn('test', 'title'); \$this->dropColumn('test', 'body'); - \$this->dropColumn('test', 'create_at'); + \$this->dropColumn('test', 'created_at'); } public function down() { \$this->addColumn('test', 'title', \$this->string(10)->notNull()); \$this->addColumn('test', 'body', \$this->text()->notNull()); - \$this->addColumn('test', 'create_at', \$this->dateTime()); + \$this->addColumn('test', 'created_at', \$this->dateTime()); } } @@ -477,9 +477,9 @@ CODE; $this->assertEqualsWithoutLE($code, file_get_contents($files[0])); } - public function testGenerateCreateJoinMigration() + public function testGenerateCreateJunctionMigration() { - $migrationName = 'create_join_post_and_tag'; + $migrationName = 'create_junction_post_and_tag'; $class = 'm' . gmdate('ymd_His') . '_' . $migrationName; $this->runMigrateControllerAction('create', [ $migrationName,