mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-26 14:26:54 +08:00
Fixes #11280 migrate autogenerate breaks MongoDB migration
Fixes #11280: Descendants of `yii\console\controllers\BaseMigrateController`, like the one for MongoDB, unable to create new migration
This commit is contained in:

committed by
Alexander Makarov

parent
f5c4407993
commit
b72524d490
@ -26,6 +26,7 @@ Yii Framework 2 Change Log
|
||||
- Bug #11188: Fixed wrong index usage in `CaptchaAction` when calling `imagefilledrectangle` (alsopub)
|
||||
- Bug #11221: Boolean validator generates incorrect error message (azaikin, githubjeka)
|
||||
- Bug #11223: Fixed returning an empty array when DbManager::getRolesByUser() was called on a user with user id 0 (VirtualRJ)
|
||||
- Bug #11280: Descendants of `yii\console\controllers\BaseMigrateController`, like the one for MongoDB, unable to create new migration (klimov-paul)
|
||||
- Bug: SQlite querybuilder did not create primary key with bigint for `TYPE_BIGPK` (cebe)
|
||||
- Enh #5469: Add mimetype validation by mask in FileValidator (kirsenn, samdark, silverfire)
|
||||
- Enh #8145, #8139, #10234 #11153: `yii\validators\Validator::$attributes` property now supports `!attribute` notation to validate attribute, but do not mark it as safe (mdmunir)
|
||||
|
@ -41,32 +41,7 @@ abstract class BaseMigrateController extends Controller
|
||||
* or a file path.
|
||||
*/
|
||||
public $templateFile;
|
||||
/**
|
||||
* @var array a set of template paths for generating migration code automatically.
|
||||
*
|
||||
* The key is the template type, the value is a path or the alias. Supported types are:
|
||||
* - `create_table`: table creating template
|
||||
* - `drop_table`: table dropping template
|
||||
* - `add_column`: adding new column template
|
||||
* - `drop_column`: dropping column template
|
||||
* - `create_junction`: create junction template
|
||||
*
|
||||
* @since 2.0.7
|
||||
*/
|
||||
public $generatorTemplateFiles;
|
||||
/**
|
||||
* @var array column definition strings used for creating migration code.
|
||||
* 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.
|
||||
* @since 2.0.7
|
||||
*/
|
||||
public $fields = [];
|
||||
|
||||
/**
|
||||
* @var array columns which have a foreign key and their related table.
|
||||
* @since 2.0.8
|
||||
*/
|
||||
protected $foreignKeys = [];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@ -76,7 +51,7 @@ abstract class BaseMigrateController extends Controller
|
||||
return array_merge(
|
||||
parent::options($actionID),
|
||||
['migrationPath'], // global for all actions
|
||||
$actionID === 'create' ? ['templateFile', 'fields'] : [] // action create
|
||||
$actionID === 'create' ? ['templateFile'] : [] // action create
|
||||
);
|
||||
}
|
||||
|
||||
@ -98,7 +73,6 @@ abstract class BaseMigrateController extends Controller
|
||||
FileHelper::createDirectory($path);
|
||||
}
|
||||
$this->migrationPath = $path;
|
||||
$this->parseFields();
|
||||
|
||||
$version = Yii::getVersion();
|
||||
$this->stdout("Yii Migration Tool (based on Yii v{$version})\n\n");
|
||||
@ -504,59 +478,11 @@ abstract class BaseMigrateController extends Controller
|
||||
$className = 'm' . gmdate('ymd_His') . '_' . $name;
|
||||
$file = $this->migrationPath . DIRECTORY_SEPARATOR . $className . '.php';
|
||||
if ($this->confirm("Create new migration '$file'?")) {
|
||||
$table = null;
|
||||
if (preg_match('/^create_junction_(.+)_and_(.+)$/', $name, $matches)) {
|
||||
$this->templateFile = $this->generatorTemplateFiles['create_junction'];
|
||||
$firstTable = mb_strtolower($matches[1], Yii::$app->charset);
|
||||
$secondTable = mb_strtolower($matches[2], Yii::$app->charset);
|
||||
|
||||
$this->fields = array_merge(
|
||||
[
|
||||
[
|
||||
'property' => $firstTable . '_id',
|
||||
'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)) {
|
||||
$this->templateFile = $this->generatorTemplateFiles['add_column'];
|
||||
$table = mb_strtolower($matches[2], Yii::$app->charset);
|
||||
} elseif (preg_match('/^drop_(.+)_from_(.+)$/', $name, $matches)) {
|
||||
$this->templateFile = $this->generatorTemplateFiles['drop_column'];
|
||||
$table = mb_strtolower($matches[2], Yii::$app->charset);
|
||||
} elseif (preg_match('/^create_(.+)$/', $name, $matches)) {
|
||||
$this->addDefaultPrimaryKey();
|
||||
$this->templateFile = $this->generatorTemplateFiles['create_table'];
|
||||
$table = mb_strtolower($matches[1], Yii::$app->charset);
|
||||
} elseif (preg_match('/^drop_(.+)$/', $name, $matches)) {
|
||||
$this->addDefaultPrimaryKey();
|
||||
$this->templateFile = $this->generatorTemplateFiles['drop_table'];
|
||||
$table = mb_strtolower($matches[1], Yii::$app->charset);
|
||||
}
|
||||
|
||||
file_put_contents($file, $this->renderFile($this->templateFile, [
|
||||
'className' => $className,
|
||||
$content = $this->generateMigrationSourceCode([
|
||||
'name' => $name,
|
||||
'table' => $table,
|
||||
'fields' => $this->fields,
|
||||
'foreignKeys' => $this->foreignKeys,
|
||||
]));
|
||||
'className' => $className,
|
||||
]);
|
||||
file_put_contents($file, $content);
|
||||
$this->stdout("New migration created successfully.\n", Console::FG_GREEN);
|
||||
}
|
||||
}
|
||||
@ -715,49 +641,19 @@ abstract class BaseMigrateController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the command line migration fields
|
||||
* @since 2.0.7
|
||||
* Generates new migration source PHP code.
|
||||
* Child class may override this method, adding extra logic or variation to the process.
|
||||
* @param array $params generation parameters, usually following parameters are present:
|
||||
*
|
||||
* - name: string migration base name
|
||||
* - className: string migration class name
|
||||
*
|
||||
* @return string generated PHP code.
|
||||
* @since 2.0.8
|
||||
*/
|
||||
protected function parseFields()
|
||||
protected function generateMigrationSourceCode($params)
|
||||
{
|
||||
foreach ($this->fields as $index => $field) {
|
||||
$chunks = preg_split('/\s?:\s?/', $field, null);
|
||||
$property = array_shift($chunks);
|
||||
|
||||
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)) {
|
||||
$chunk .= '()';
|
||||
}
|
||||
}
|
||||
$this->fields[$index] = [
|
||||
'property' => $property,
|
||||
'decorators' => implode('->', $chunks),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds default primary key to fields list if there's no primary key specified
|
||||
* @since 2.0.7
|
||||
*/
|
||||
protected function addDefaultPrimaryKey()
|
||||
{
|
||||
foreach ($this->fields as $field) {
|
||||
if ($field['decorators'] === 'primaryKey()') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
array_unshift($this->fields, ['property' => 'id', 'decorators' => 'primaryKey()']);
|
||||
return $this->renderFile(Yii::getAlias($this->templateFile), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,7 +64,15 @@ class MigrateController extends BaseMigrateController
|
||||
*/
|
||||
public $templateFile = '@yii/views/migration.php';
|
||||
/**
|
||||
* @inheritdoc
|
||||
* @var array a set of template paths for generating migration code automatically.
|
||||
*
|
||||
* The key is the template type, the value is a path or the alias. Supported types are:
|
||||
* - `create_table`: table creating template
|
||||
* - `drop_table`: table dropping template
|
||||
* - `add_column`: adding new column template
|
||||
* - `drop_column`: dropping column template
|
||||
* - `create_junction`: create junction template
|
||||
*
|
||||
* @since 2.0.7
|
||||
*/
|
||||
public $generatorTemplateFiles = [
|
||||
@ -74,6 +82,13 @@ class MigrateController extends BaseMigrateController
|
||||
'drop_column' => '@yii/views/dropColumnMigration.php',
|
||||
'create_junction' => '@yii/views/createTableMigration.php'
|
||||
];
|
||||
/**
|
||||
* @var array column definition strings used for creating migration code.
|
||||
* 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.
|
||||
* @since 2.0.7
|
||||
*/
|
||||
public $fields = [];
|
||||
/**
|
||||
* @var Connection|array|string the DB connection object or the application component ID of the DB connection to use
|
||||
* when applying migrations. Starting from version 2.0.3, this can also be a configuration array
|
||||
@ -81,6 +96,12 @@ class MigrateController extends BaseMigrateController
|
||||
*/
|
||||
public $db = 'db';
|
||||
|
||||
/**
|
||||
* @var array columns which have a foreign key and their related table.
|
||||
* @since 2.0.8
|
||||
*/
|
||||
protected $foreignKeys = [];
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@ -89,7 +110,8 @@ class MigrateController extends BaseMigrateController
|
||||
{
|
||||
return array_merge(
|
||||
parent::options($actionID),
|
||||
['migrationTable', 'db'] // global for all actions
|
||||
['migrationTable', 'db'], // global for all actions
|
||||
$actionID === 'create' ? ['fields'] : [] // action create
|
||||
);
|
||||
}
|
||||
|
||||
@ -198,4 +220,113 @@ class MigrateController extends BaseMigrateController
|
||||
'version' => $version,
|
||||
])->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function generateMigrationSourceCode($params)
|
||||
{
|
||||
$this->parseFields();
|
||||
|
||||
$name = $params['name'];
|
||||
|
||||
$templateFile = $this->templateFile;
|
||||
$table = null;
|
||||
if (preg_match('/^create_junction_(.+)_and_(.+)$/', $name, $matches)) {
|
||||
$templateFile = $this->generatorTemplateFiles['create_junction'];
|
||||
$firstTable = mb_strtolower($matches[1], Yii::$app->charset);
|
||||
$secondTable = mb_strtolower($matches[2], Yii::$app->charset);
|
||||
|
||||
$this->fields = array_merge(
|
||||
[
|
||||
[
|
||||
'property' => $firstTable . '_id',
|
||||
'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)) {
|
||||
$templateFile = $this->generatorTemplateFiles['add_column'];
|
||||
$table = mb_strtolower($matches[2], Yii::$app->charset);
|
||||
} elseif (preg_match('/^drop_(.+)_from_(.+)$/', $name, $matches)) {
|
||||
$templateFile = $this->generatorTemplateFiles['drop_column'];
|
||||
$table = mb_strtolower($matches[2], Yii::$app->charset);
|
||||
} elseif (preg_match('/^create_(.+)$/', $name, $matches)) {
|
||||
$this->addDefaultPrimaryKey();
|
||||
$templateFile = $this->generatorTemplateFiles['create_table'];
|
||||
$table = mb_strtolower($matches[1], Yii::$app->charset);
|
||||
} elseif (preg_match('/^drop_(.+)$/', $name, $matches)) {
|
||||
$this->addDefaultPrimaryKey();
|
||||
$templateFile = $this->generatorTemplateFiles['drop_table'];
|
||||
$table = mb_strtolower($matches[1], Yii::$app->charset);
|
||||
}
|
||||
|
||||
return $this->renderFile(Yii::getAlias($templateFile), array_merge($params, [
|
||||
'table' => $table,
|
||||
'fields' => $this->fields,
|
||||
'foreignKeys' => $this->foreignKeys,
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the command line migration fields
|
||||
* @since 2.0.7
|
||||
*/
|
||||
protected function parseFields()
|
||||
{
|
||||
foreach ($this->fields as $index => $field) {
|
||||
$chunks = preg_split('/\s?:\s?/', $field, null);
|
||||
$property = array_shift($chunks);
|
||||
|
||||
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)) {
|
||||
$chunk .= '()';
|
||||
}
|
||||
}
|
||||
$this->fields[$index] = [
|
||||
'property' => $property,
|
||||
'decorators' => implode('->', $chunks),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds default primary key to fields list if there's no primary key specified
|
||||
* @since 2.0.7
|
||||
*/
|
||||
protected function addDefaultPrimaryKey()
|
||||
{
|
||||
foreach ($this->fields as $field) {
|
||||
if ($field['decorators'] === 'primaryKey()') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
array_unshift($this->fields, ['property' => 'id', 'decorators' => 'primaryKey()']);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user