Browse Source

Enh: Migrate command now supports foreign keys

Fixes #11207: migrate command can create foreign keys
tags/2.0.8
Angel Guevara 9 years ago committed by Alexander Makarov
parent
commit
49aec24ae1
  1. 232
      docs/guide/db-migrations.md
  2. 1
      framework/CHANGELOG.md
  3. 93
      framework/console/controllers/BaseMigrateController.php
  4. 2
      framework/console/controllers/MigrateController.php
  5. 14
      framework/views/_addColumns.php
  6. 19
      framework/views/_addForeignKeys.php
  7. 22
      framework/views/_createTable.php
  8. 10
      framework/views/_dropColumns.php
  9. 14
      framework/views/_dropForeignKeys.php
  10. 13
      framework/views/_dropTable.php
  11. 14
      framework/views/_foreignTables.php
  12. 34
      framework/views/addColumnMigration.php
  13. 2
      framework/views/createJunctionMigration.php
  14. 21
      framework/views/createTableMigration.php
  15. 33
      framework/views/dropColumnMigration.php
  16. 20
      framework/views/dropTableMigration.php
  17. 190
      tests/framework/console/controllers/MigrateControllerTestTrait.php

232
docs/guide/db-migrations.md

@ -198,8 +198,14 @@ yii migrate/create create_post
generates generates
```php ```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration class m150811_220037_create_post extends Migration
{ {
/**
* @inheritdoc
*/
public function up() public function up()
{ {
$this->createTable('post', [ $this->createTable('post', [
@ -207,6 +213,9 @@ class m150811_220037_create_post extends Migration
]); ]);
} }
/**
* @inheritdoc
*/
public function down() public function down()
{ {
$this->dropTable('post'); $this->dropTable('post');
@ -223,22 +232,32 @@ yii migrate/create create_post --fields="title:string,body:text"
generates generates
```php ```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration class m150811_220037_create_post extends Migration
{ {
/**
* @inheritdoc
*/
public function up() public function up()
{ {
$this->createTable('post', [ $this->createTable('post', [
'id' => $this->primaryKey(), 'id' => $this->primaryKey(),
'title' => $this->string(), 'title' => $this->string(),
'body' => $this->text() 'body' => $this->text(),
]); ]);
} }
/**
* @inheritdoc
*/
public function down() public function down()
{ {
$this->dropTable('post'); $this->dropTable('post');
} }
} }
``` ```
You can specify more field parameters. You can specify more field parameters.
@ -250,8 +269,14 @@ yii migrate/create create_post --fields="title:string(12):notNull:unique,body:te
generates generates
```php ```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration class m150811_220037_create_post extends Migration
{ {
/**
* @inheritdoc
*/
public function up() public function up()
{ {
$this->createTable('post', [ $this->createTable('post', [
@ -261,6 +286,9 @@ class m150811_220037_create_post extends Migration
]); ]);
} }
/**
* @inheritdoc
*/
public function down() public function down()
{ {
$this->dropTable('post'); $this->dropTable('post');
@ -271,6 +299,126 @@ class m150811_220037_create_post extends Migration
> Note: primary key is added automatically and is named `id` by default. If you want to use another name you may > 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"`. > specify it explicitly like `--fields="name:primaryKey"`.
#### Foreign keys
Since 2.0.8 the generator supports foreign keys using the `foreignKey` keyword.
```php
yii migrate/create create_post --fields="author_id:integer:notNull:foreignKey(user),category_id:integer:defaultValue(1):foreignKey,title:string,body:text"
```
generates
```php
/**
* Handles the creation for table `post`.
* Has foreign keys to the tables:
*
* - `user`
* - `category`
*/
class m160328_040430_create_post extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post', [
'id' => $this->primaryKey(),
'author_id' => $this->integer()->notNull(),
'category_id' => $this->integer()->defaultValue(1),
'title' => $this->string(),
'body' => $this->text(),
]);
// creates index for column `author_id`
$this->createIndex(
'idx-post-author_id',
'post',
'author_id'
);
// add foreign key for table `user`
$this->addForeignKey(
'fk-post-author_id',
'post',
'author_id',
'user',
'id',
'CASCADE'
);
// creates index for column `category_id`
$this->createIndex(
'idx-post-category_id',
'post',
'category_id'
);
// add foreign key for table `category`
$this->addForeignKey(
'fk-post-category_id',
'post',
'category_id',
'category',
'id',
'CASCADE'
);
}
/**
* @inheritdoc
*/
public function down()
{
// drops foreign key for table `user`
$this->dropForeignKey(
'fk-post-author_id',
'post'
);
// drops index for column `author_id`
$this->dropIndex(
'idx-post-author_id',
'post'
);
// drops foreign key for table `category`
$this->dropForeignKey(
'fk-post-category_id',
'post'
);
// drops index for column `category_id`
$this->dropIndex(
'idx-post-category_id',
'post'
);
$this->dropTable('post');
}
}
```
The position of the `foreignKey` keyword in the column description doesn't
change the generated code. That means:
- `author_id:integer:notNull:foreignKey(user)`
- `author_id:integer:foreignKey(user):notNull`
- `author_id:foreignKey(user):integer:notNull`
All generate the same code.
The `foreignKey` keyword can take a parameter between parenthesis which will be
the name of the related table for the generated foreign key. If no parameter
is passed then the table name will be deduced from the column name.
In the
example above `author_id:integer:notNull:foreignKey(user)` will generate a
column named `author_id` with a foreign key to the `user` table while
`category_id:integer:default(1):foreignKey` will generate a column `category_id`
with a foreign key to the `category` table.
### Drop Table ### Drop Table
@ -359,31 +507,97 @@ If the migration name is in if the form of `create_junction_xxx_and_yyy` then co
will be generated. will be generated.
```php ```php
yii migrate/create create_junction_post_and_tag yii migrate/create create_junction_post_and_tag --fields="created_at:dateTime"
``` ```
generates generates
```php ```php
class m150811_220037_create_junction_post_and_tag extends Migration /**
* Handles the creation for table `post_tag`.
* Has foreign keys to the tables:
*
* - `post`
* - `tag`
*/
class m160328_041642_create_junction_post_and_tag extends Migration
{ {
/**
* @inheritdoc
*/
public function up() public function up()
{ {
$this->createTable('post_tag', [ $this->createTable('post_tag', [
'post_id' => $this->integer(), 'post_id' => $this->integer(),
'tag_id' => $this->integer(), 'tag_id' => $this->integer(),
'PRIMARY KEY(post_id, tag_id)' 'created_at' => $this->dateTime(),
'PRIMARY KEY(post_id, tag_id)',
]); ]);
$this->createIndex('idx-post_tag-post_id', 'post_tag', 'post_id'); // creates index for column `post_id`
$this->createIndex('idx-post_tag-tag_id', 'post_tag', 'tag_id'); $this->createIndex(
'idx-post_tag-post_id',
$this->addForeignKey('fk-post_tag-post_id', 'post_tag', 'post_id', 'post', 'id', 'CASCADE'); 'post_tag',
$this->addForeignKey('fk-post_tag-tag_id', 'post_tag', 'tag_id', 'tag', 'id', 'CASCADE'); 'post_id'
);
// add foreign key for table `post`
$this->addForeignKey(
'fk-post_tag-post_id',
'post_tag',
'post_id',
'post',
'id',
'CASCADE'
);
// creates index for column `tag_id`
$this->createIndex(
'idx-post_tag-tag_id',
'post_tag',
'tag_id'
);
// add foreign key for table `tag`
$this->addForeignKey(
'fk-post_tag-tag_id',
'post_tag',
'tag_id',
'tag',
'id',
'CASCADE'
);
} }
/**
* @inheritdoc
*/
public function down() public function down()
{ {
// drops foreign key for table `post`
$this->dropForeignKey(
'fk-post_tag-post_id',
'post_tag'
);
// drops index for column `post_id`
$this->dropIndex(
'idx-post_tag-post_id',
'post_tag'
);
// drops foreign key for table `tag`
$this->dropForeignKey(
'fk-post_tag-tag_id',
'post_tag'
);
// drops index for column `tag_id`
$this->dropIndex(
'idx-post_tag-tag_id',
'post_tag'
);
$this->dropTable('post_tag'); $this->dropTable('post_tag');
} }
} }

1
framework/CHANGELOG.md

@ -50,6 +50,7 @@ Yii Framework 2 Change Log
- Enh #11187: migrate command now generates phpdoc for table migrations (Faryshta) - Enh #11187: migrate command now generates phpdoc for table migrations (Faryshta)
- Enh #11254: Added ability to attach RBAC rule using class name (mdmunir) - Enh #11254: Added ability to attach RBAC rule using class name (mdmunir)
- Enh: Added `StringHelper::countWords()` that given a string returns number of words in it (samdark) - Enh: Added `StringHelper::countWords()` that given a string returns number of words in it (samdark)
- Enh #11207: migrate command can create foreign keys. (faryshta)
- Chg: HTMLPurifier dependency updated to `~4.6` (samdark) - Chg: HTMLPurifier dependency updated to `~4.6` (samdark)
- Chg #10726: Added `yii\rbac\ManagerInterface::canAddChild()` (dkhlystov, samdark) - Chg #10726: Added `yii\rbac\ManagerInterface::canAddChild()` (dkhlystov, samdark)
- Chg #10921: Inverts responsibility of database specific column schema builder classes (df2) - Chg #10921: Inverts responsibility of database specific column schema builder classes (df2)

93
framework/console/controllers/BaseMigrateController.php

@ -62,6 +62,11 @@ abstract class BaseMigrateController extends Controller
*/ */
public $fields = []; public $fields = [];
/**
* @var array columns which have a foreign key and their related table.
* @since 2.0.8
*/
protected $foreignKeys = [];
/** /**
* @inheritdoc * @inheritdoc
@ -498,49 +503,60 @@ abstract class BaseMigrateController extends Controller
$className = 'm' . gmdate('ymd_His') . '_' . $name; $className = 'm' . gmdate('ymd_His') . '_' . $name;
$file = $this->migrationPath . DIRECTORY_SEPARATOR . $className . '.php'; $file = $this->migrationPath . DIRECTORY_SEPARATOR . $className . '.php';
if ($this->confirm("Create new migration '$file'?")) { if ($this->confirm("Create new migration '$file'?")) {
$table = null;
if (preg_match('/^create_junction_(.+)_and_(.+)$/', $name, $matches)) { if (preg_match('/^create_junction_(.+)_and_(.+)$/', $name, $matches)) {
$this->templateFile = $this->generatorTemplateFiles['create_junction'];
$firstTable = mb_strtolower($matches[1], Yii::$app->charset); $firstTable = mb_strtolower($matches[1], Yii::$app->charset);
$secondTable = mb_strtolower($matches[2], Yii::$app->charset); $secondTable = mb_strtolower($matches[2], Yii::$app->charset);
$content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['create_junction']), [ $this->fields = array_merge(
'className' => $className, [
'table' => $firstTable . '_' . $secondTable, [
'field_first' => $firstTable, 'property' => $firstTable . '_id',
'field_second' => $secondTable, 'decorators' => 'integer()',
]); ],
[
'property' => $secondTable . '_id',
'decorators' => 'integer()',
],
],
$this->fields,
[
[
'property' => 'PRIMARY KEY(' .
$firstTable . '_id, ' .
$secondTable . '_id)',
],
]
);
$this->foreignKeys[$firstTable . '_id'] = $firstTable;
$this->foreignKeys[$secondTable . '_id'] = $secondTable;
$table = $firstTable . '_' . $secondTable;
} elseif (preg_match('/^add_(.+)_to_(.+)$/', $name, $matches)) { } elseif (preg_match('/^add_(.+)_to_(.+)$/', $name, $matches)) {
$content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['add_column']), [ $this->templateFile = $this->generatorTemplateFiles['add_column'];
'className' => $className, $table = mb_strtolower($matches[2], Yii::$app->charset);
'table' => mb_strtolower($matches[2], Yii::$app->charset),
'fields' => $this->fields
]);
} elseif (preg_match('/^drop_(.+)_from_(.+)$/', $name, $matches)) { } elseif (preg_match('/^drop_(.+)_from_(.+)$/', $name, $matches)) {
$content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['drop_column']), [ $this->templateFile = $this->generatorTemplateFiles['drop_column'];
'className' => $className, $table = mb_strtolower($matches[2], Yii::$app->charset);
'table' => mb_strtolower($matches[2], Yii::$app->charset),
'fields' => $this->fields
]);
} elseif (preg_match('/^create_(.+)$/', $name, $matches)) { } elseif (preg_match('/^create_(.+)$/', $name, $matches)) {
$this->addDefaultPrimaryKey(); $this->addDefaultPrimaryKey();
$content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['create_table']), [ $this->templateFile = $this->generatorTemplateFiles['create_table'];
'className' => $className, $table = mb_strtolower($matches[1], Yii::$app->charset);
'table' => mb_strtolower($matches[1], Yii::$app->charset),
'fields' => $this->fields
]);
} elseif (preg_match('/^drop_(.+)$/', $name, $matches)) { } elseif (preg_match('/^drop_(.+)$/', $name, $matches)) {
$this->addDefaultPrimaryKey(); $this->addDefaultPrimaryKey();
$content = $this->renderFile(Yii::getAlias($this->generatorTemplateFiles['drop_table']), [ $this->templateFile = $this->generatorTemplateFiles['drop_table'];
'className' => $className, $table = mb_strtolower($matches[1], Yii::$app->charset);
'table' => mb_strtolower($matches[1], Yii::$app->charset),
'fields' => $this->fields
]);
} else {
$content = $this->renderFile(Yii::getAlias($this->templateFile), ['className' => $className]);
} }
file_put_contents($file, $content); file_put_contents($file, $this->renderFile($this->templateFile, [
'className' => $className,
'name' => $name,
'table' => $table,
'fields' => $this->fields,
'foreignKeys' => $this->foreignKeys,
]));
$this->stdout("New migration created successfully.\n", Console::FG_GREEN); $this->stdout("New migration created successfully.\n", Console::FG_GREEN);
} }
} }
@ -708,12 +724,25 @@ abstract class BaseMigrateController extends Controller
$chunks = preg_split('/\s?:\s?/', $field, null); $chunks = preg_split('/\s?:\s?/', $field, null);
$property = array_shift($chunks); $property = array_shift($chunks);
foreach ($chunks as &$chunk) { foreach ($chunks as $i => &$chunk) {
if (strpos($chunk, 'foreignKey') === 0) {
preg_match('/foreignKey\((\w*)\)/', $chunk, $matches);
$this->foreignKeys[$property] = isset($matches[1])
? $matches[1]
: preg_replace('/_id$/', '', $property);
unset($chunks[$i]);
continue;
}
if (!preg_match('/^(.+?)\(([^)]+)\)$/', $chunk)) { if (!preg_match('/^(.+?)\(([^)]+)\)$/', $chunk)) {
$chunk .= '()'; $chunk .= '()';
} }
} }
$this->fields[$index] = ['property' => $property, 'decorators' => implode('->', $chunks)]; $this->fields[$index] = [
'property' => $property,
'decorators' => implode('->', $chunks),
];
} }
} }

2
framework/console/controllers/MigrateController.php

@ -72,7 +72,7 @@ class MigrateController extends BaseMigrateController
'drop_table' => '@yii/views/dropTableMigration.php', 'drop_table' => '@yii/views/dropTableMigration.php',
'add_column' => '@yii/views/addColumnMigration.php', 'add_column' => '@yii/views/addColumnMigration.php',
'drop_column' => '@yii/views/dropColumnMigration.php', 'drop_column' => '@yii/views/dropColumnMigration.php',
'create_junction' => '@yii/views/createJunctionMigration.php' 'create_junction' => '@yii/views/createTableMigration.php'
]; ];
/** /**
* @var Connection|array|string the DB connection object or the application component ID of the DB connection to use * @var Connection|array|string the DB connection object or the application component ID of the DB connection to use

14
framework/views/_addColumns.php

@ -0,0 +1,14 @@
<?php foreach ($fields as $field): ?>
$this->addColumn('<?=
$table
?>', '<?=
$field['property']
?>', $this-><?=
$field['decorators']
?>);
<?php endforeach;
echo $this->render('_addForeignKeys', [
'table' => $table,
'foreignKeys' => $foreignKeys,
]);

19
framework/views/_addForeignKeys.php

@ -0,0 +1,19 @@
<?php foreach ($foreignKeys as $column => $relatedTable): ?>
// creates index for column `<?= $column ?>`
$this->createIndex(
'<?= "idx-$table-$column" ?>',
'<?= $table ?>',
'<?= $column ?>'
);
// add foreign key for table `<?= $relatedTable ?>`
$this->addForeignKey(
'<?= "fk-$table-$column" ?>',
'<?= $table ?>',
'<?= $column ?>',
'<?= $relatedTable ?>',
'id',
'CASCADE'
);
<?php endforeach;

22
framework/views/_createTable.php

@ -0,0 +1,22 @@
<?php
/**
* Creates a call for the method `yii\db\Migration::createTable()`
*/
/* @var $table string the name table */
/* @var $fields array the fields */
/* @var $foreignKeys array the foreign keys */
?> $this->createTable('<?= $table ?>', [
<?php foreach ($fields as $field):
if (empty($field['decorators'])): ?>
'<?= $field['property'] ?>',
<?php else: ?>
<?= "'{$field['property']}' => \$this->{$field['decorators']}" ?>,
<?php endif;
endforeach; ?>
]);
<?= $this->render('_addForeignKeys', [
'table' => $table,
'foreignKeys' => $foreignKeys,
]);

10
framework/views/_dropColumns.php

@ -0,0 +1,10 @@
<?php
echo $this->render('_dropForeignKeys', [
'table' => $table,
'foreignKeys' => $foreignKeys,
]);
foreach ($fields as $field): ?>
$this->dropColumn('<?= $table ?>', '<?= $field['property'] ?>');
<?php endforeach;

14
framework/views/_dropForeignKeys.php

@ -0,0 +1,14 @@
<?php foreach ($foreignKeys as $column => $relatedTable): ?>
// drops foreign key for table `<?= $relatedTable ?>`
$this->dropForeignKey(
'<?= "fk-$table-$column" ?>',
'<?= $table ?>'
);
// drops index for column `<?= $column ?>`
$this->dropIndex(
'<?= "idx-$table-$column" ?>',
'<?= $table ?>'
);
<?php endforeach;

13
framework/views/_dropTable.php

@ -0,0 +1,13 @@
<?php
/**
* Creates a call for the method `yii\db\Migration::dropTable()`
*/
/* @var $table string the name table */
/* @var $foreignKeys array the foreign keys */
echo $this->render('_dropForeignKeys', [
'table' => $table,
'foreignKeys' => $foreignKeys,
]) ?>
$this->dropTable('<?= $table ?>');

14
framework/views/_foreignTables.php

@ -0,0 +1,14 @@
<?php
/**
* Creates a call for the method `yii\db\Migration::createTable()`
*/
/* @var $foreignKeys array the foreign keys */
if (!empty($foreignKeys)):?>
* Has foreign keys to the tables:
*
<?php foreach ($foreignKeys as $relatedTable): ?>
* - `<?= $relatedTable ?>`
<?php endforeach;
endif;

34
framework/views/addColumnMigration.php

@ -7,21 +7,19 @@
/* @var $table string the name table */ /* @var $table string the name table */
/* @var $fields array the fields */ /* @var $fields array the fields */
preg_match('/^add_(.+)_to_(.+)$/', $name, $matches);
$columns = $matches[1];
echo "<?php\n"; echo "<?php\n";
?> ?>
use yii\db\Migration; use yii\db\Migration;
/** /**
* Handles adding the columns <?php * Handles adding <?= $columns ?> to table `<?= $table ?>`.
foreach ($fields as $field): <?= $this->render('_foreignTables', [
if ($field == end($fields)): 'foreignKeys' => $foreignKeys
echo "`{$field['property']}`\n"; ]) ?>
else:
echo "`{$field['property']}`, ";
endif;
endforeach;?>
* for table `<?= $table ?>`.
*/ */
class <?= $className ?> extends Migration class <?= $className ?> extends Migration
{ {
@ -30,9 +28,12 @@ class <?= $className ?> extends Migration
*/ */
public function up() public function up()
{ {
<?php foreach ($fields as $field): ?> <?= $this->render('_addColumns', [
$this->addColumn(<?= "'$table', '" . $field['property'] . "', \$this->" . $field['decorators'] ?>); 'table' => $table,
<?php endforeach; ?> 'fields' => $fields,
'foreignKeys' => $foreignKeys,
])
?>
} }
/** /**
@ -40,8 +41,11 @@ class <?= $className ?> extends Migration
*/ */
public function down() public function down()
{ {
<?php foreach ($fields as $field): ?> <?= $this->render('_dropColumns', [
$this->dropColumn(<?= "'$table', '" . $field['property'] . "'" ?>); 'table' => $table,
<?php endforeach; ?> 'fields' => $fields,
'foreignKeys' => $foreignKeys,
])
?>
} }
} }

2
framework/views/createJunctionMigration.php

@ -2,6 +2,8 @@
/** /**
* This view is used by console/controllers/MigrateController.php * This view is used by console/controllers/MigrateController.php
* The following variables are available in this view: * The following variables are available in this view:
* @since 2.0.7
* @deprecated since 2.0.8
*/ */
/* @var $className string the new migration class name */ /* @var $className string the new migration class name */
/* @var $table string the name table */ /* @var $table string the name table */

21
framework/views/createTableMigration.php

@ -6,6 +6,7 @@
/* @var $className string the new migration class name */ /* @var $className string the new migration class name */
/* @var $table string the name table */ /* @var $table string the name table */
/* @var $fields array the fields */ /* @var $fields array the fields */
/* @var $foreignKeys array the foreign keys */
echo "<?php\n"; echo "<?php\n";
?> ?>
@ -14,6 +15,9 @@ use yii\db\Migration;
/** /**
* Handles the creation for table `<?= $table ?>`. * Handles the creation for table `<?= $table ?>`.
<?= $this->render('_foreignTables', [
'foreignKeys' => $foreignKeys
]) ?>
*/ */
class <?= $className ?> extends Migration class <?= $className ?> extends Migration
{ {
@ -22,11 +26,12 @@ class <?= $className ?> extends Migration
*/ */
public function up() public function up()
{ {
$this->createTable('<?= $table ?>', [ <?= $this->render('_createTable', [
<?php foreach ($fields as $field): ?> 'table' => $table,
<?= "'{$field['property']}' => \$this->{$field['decorators']},\n" ?> 'fields' => $fields,
<?php endforeach; ?> 'foreignKeys' => $foreignKeys,
]); ])
?>
} }
/** /**
@ -34,6 +39,10 @@ class <?= $className ?> extends Migration
*/ */
public function down() public function down()
{ {
$this->dropTable('<?= $table ?>'); <?= $this->render('_dropTable', [
'table' => $table,
'foreignKeys' => $foreignKeys,
])
?>
} }
} }

33
framework/views/dropColumnMigration.php

@ -6,6 +6,8 @@
/* @var $className string the new migration class name */ /* @var $className string the new migration class name */
/* @var $table string the name table */ /* @var $table string the name table */
/* @var $fields array the fields */ /* @var $fields array the fields */
preg_match('/^drop_(.+)_from_(.+)$/', $name, $matches);
$columns = $matches[1];
echo "<?php\n"; echo "<?php\n";
?> ?>
@ -13,15 +15,10 @@ echo "<?php\n";
use yii\db\Migration; use yii\db\Migration;
/** /**
* Handles dropping columns <?php * Handles dropping <?= $columns ?> from table `<?= $table ?>`.
foreach ($fields as $field): <?= $this->render('_foreignTables', [
if ($field == end($fields)): 'foreignKeys' => $foreignKeys
echo "`{$field['property']}`\n"; ]) ?>
else:
echo "`{$field['property']}`, ";
endif;
endforeach;?>
* for table `<?= $table ?>`.
*/ */
class <?= $className ?> extends Migration class <?= $className ?> extends Migration
{ {
@ -30,9 +27,12 @@ class <?= $className ?> extends Migration
*/ */
public function up() public function up()
{ {
<?php foreach ($fields as $field): ?> <?= $this->render('_dropColumns', [
$this->dropColumn(<?= "'$table', '" . $field['property'] . "'" ?>); 'table' => $table,
<?php endforeach; ?> 'fields' => $fields,
'foreignKeys' => $foreignKeys,
])
?>
} }
/** /**
@ -40,8 +40,11 @@ class <?= $className ?> extends Migration
*/ */
public function down() public function down()
{ {
<?php foreach ($fields as $field): ?> <?= $this->render('_addColumns', [
$this->addColumn(<?= "'$table', '" . $field['property'] . "', \$this->" . $field['decorators'] ?>); 'table' => $table,
<?php endforeach; ?> 'fields' => $fields,
'foreignKeys' => $foreignKeys,
])
?>
} }
} }

20
framework/views/dropTableMigration.php

@ -14,6 +14,9 @@ use yii\db\Migration;
/** /**
* Handles the dropping for table `<?= $table ?>`. * Handles the dropping for table `<?= $table ?>`.
<?= $this->render('_foreignTables', [
'foreignKeys' => $foreignKeys
]) ?>
*/ */
class <?= $className ?> extends Migration class <?= $className ?> extends Migration
{ {
@ -22,7 +25,11 @@ class <?= $className ?> extends Migration
*/ */
public function up() public function up()
{ {
$this->dropTable('<?= $table ?>'); <?= $this->render('_dropTable', [
'table' => $table,
'foreignKeys' => $foreignKeys,
])
?>
} }
/** /**
@ -30,10 +37,11 @@ class <?= $className ?> extends Migration
*/ */
public function down() public function down()
{ {
$this->createTable('<?= $table ?>', [ <?= $this->render('_createTable', [
<?php foreach ($fields as $field): ?> 'table' => $table,
<?= "'{$field['property']}' => \$this->{$field['decorators']},\n" ?> 'fields' => $fields,
<?php endforeach; ?> 'foreignKeys' => $foreignKeys,
]); ])
?>
} }
} }

190
tests/framework/console/controllers/MigrateControllerTestTrait.php

@ -371,6 +371,143 @@ class {$class} extends Migration
CODE; CODE;
$this->assertEqualsWithoutLE($code, $file); $this->assertEqualsWithoutLE($code, $file);
$class = 'm' . gmdate('ymd_His') . '_' . $migrationName;
$this->runMigrateControllerAction('create', [
$migrationName,
'fields' => 'user_id:integer:foreignKey,
product_id:foreignKey:integer:unsigned:notNull,
order_id:integer:foreignKey(user_order):notNull,
created_at:dateTime:notNull',
]);
$file = $this->parseNameClassMigration($class);
$code = <<<CODE
<?php
use yii\db\Migration;
/**
* Handles the creation for table `test`.
* Has foreign keys to the tables:
*
* - `user`
* - `product`
* - `user_order`
*/
class {$class} extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
\$this->createTable('test', [
'id' => \$this->primaryKey(),
'user_id' => \$this->integer(),
'product_id' => \$this->integer()->unsigned()->notNull(),
'order_id' => \$this->integer()->notNull(),
'created_at' => \$this->dateTime()->notNull(),
]);
// creates index for column `user_id`
\$this->createIndex(
'idx-test-user_id',
'test',
'user_id'
);
// add foreign key for table `user`
\$this->addForeignKey(
'fk-test-user_id',
'test',
'user_id',
'user',
'id',
'CASCADE'
);
// creates index for column `product_id`
\$this->createIndex(
'idx-test-product_id',
'test',
'product_id'
);
// add foreign key for table `product`
\$this->addForeignKey(
'fk-test-product_id',
'test',
'product_id',
'product',
'id',
'CASCADE'
);
// creates index for column `order_id`
\$this->createIndex(
'idx-test-order_id',
'test',
'order_id'
);
// add foreign key for table `user_order`
\$this->addForeignKey(
'fk-test-order_id',
'test',
'order_id',
'user_order',
'id',
'CASCADE'
);
}
/**
* @inheritdoc
*/
public function down()
{
// drops foreign key for table `user`
\$this->dropForeignKey(
'fk-test-user_id',
'test'
);
// drops index for column `user_id`
\$this->dropIndex(
'idx-test-user_id',
'test'
);
// drops foreign key for table `product`
\$this->dropForeignKey(
'fk-test-product_id',
'test'
);
// drops index for column `product_id`
\$this->dropIndex(
'idx-test-product_id',
'test'
);
// drops foreign key for table `user_order`
\$this->dropForeignKey(
'fk-test-order_id',
'test'
);
// drops index for column `order_id`
\$this->dropIndex(
'idx-test-order_id',
'test'
);
\$this->dropTable('test');
}
}
CODE;
$this->assertEqualsWithoutLE($code, $file);
} }
public function testGenerateDropMigration() public function testGenerateDropMigration()
@ -471,8 +608,7 @@ CODE;
use yii\db\Migration; use yii\db\Migration;
/** /**
* Handles adding the columns `title`, `body`, `price`, `created_at` * Handles adding columns to table `test`.
* for table `test`.
*/ */
class {$class} extends Migration class {$class} extends Migration
{ {
@ -519,8 +655,7 @@ CODE;
use yii\db\Migration; use yii\db\Migration;
/** /**
* Handles dropping columns `title`, `body`, `price`, `created_at` * Handles dropping columns from table `test`.
* for table `test`.
*/ */
class {$class} extends Migration class {$class} extends Migration
{ {
@ -566,8 +701,11 @@ CODE;
use yii\db\Migration; use yii\db\Migration;
/** /**
* Handles the creation of table `post_tag` which is a junction between * Handles the creation for table `post_tag`.
* table `post` and table `tag`. * Has foreign keys to the tables:
*
* - `post`
* - `tag`
*/ */
class {$class} extends Migration class {$class} extends Migration
{ {
@ -582,18 +720,14 @@ class {$class} extends Migration
'PRIMARY KEY(post_id, tag_id)', 'PRIMARY KEY(post_id, tag_id)',
]); ]);
// creates index for column `post_id`
\$this->createIndex( \$this->createIndex(
'idx-post_tag-post_id', 'idx-post_tag-post_id',
'post_tag', 'post_tag',
'post_id' 'post_id'
); );
\$this->createIndex( // add foreign key for table `post`
'idx-post_tag-tag_id',
'post_tag',
'tag_id'
);
\$this->addForeignKey( \$this->addForeignKey(
'fk-post_tag-post_id', 'fk-post_tag-post_id',
'post_tag', 'post_tag',
@ -603,6 +737,14 @@ class {$class} extends Migration
'CASCADE' 'CASCADE'
); );
// creates index for column `tag_id`
\$this->createIndex(
'idx-post_tag-tag_id',
'post_tag',
'tag_id'
);
// add foreign key for table `tag`
\$this->addForeignKey( \$this->addForeignKey(
'fk-post_tag-tag_id', 'fk-post_tag-tag_id',
'post_tag', 'post_tag',
@ -618,6 +760,30 @@ class {$class} extends Migration
*/ */
public function down() public function down()
{ {
// drops foreign key for table `post`
\$this->dropForeignKey(
'fk-post_tag-post_id',
'post_tag'
);
// drops index for column `post_id`
\$this->dropIndex(
'idx-post_tag-post_id',
'post_tag'
);
// drops foreign key for table `tag`
\$this->dropForeignKey(
'fk-post_tag-tag_id',
'post_tag'
);
// drops index for column `tag_id`
\$this->dropIndex(
'idx-post_tag-tag_id',
'post_tag'
);
\$this->dropTable('post_tag'); \$this->dropTable('post_tag');
} }
} }

Loading…
Cancel
Save