Added support for specifying aliases for migrationNamespaces

This is used to specify pathes to migrations that do not have
namespaces.

While not directly supported by the migration command provideded by the
framework, these migrations exist in a lot of extensions because custom implementations
of migration controllers out of the framework were using this approach
to load multiple migrations from multiple paths.

Even the framework itself currently ships non-namespaced migrations:

- 17a1d91e4a/framework/rbac/migrations/m140506_102106_rbac_init.php
- 17a1d91e4a/framework/caching/migrations/m150909_153426_cache_init.php
- 17a1d91e4a/framework/log/migrations/m141106_185632_log_init.php

This change allows existing applications to adopt the new namespace-based approach
while keeping existing migrations. While it would be possible to add
namespaces to migrations in the application itself, it is not easily possible
to add namespaces to migrations that come from external sources like
extensions.
This commit is contained in:
Carsten Brandt
2017-06-01 18:13:38 +02:00
parent 4b9e48b8dc
commit cb9462b224
2 changed files with 22 additions and 3 deletions

View File

@ -40,6 +40,7 @@ abstract class BaseMigrateController extends Controller
*
* If you have set up [[migrationNamespaces]], you may set this field to `null` in order
* to disable usage of migrations that are not namespaced.
* @see $migrationNamespaces
*/
public $migrationPath = '@app/migrations';
/**
@ -58,7 +59,12 @@ abstract class BaseMigrateController extends Controller
* ]
* ```
*
* Since version 2.0.12 you may also specify [aliases](guide:concept-aliases) to directories that contain
* migrations without namespace. This is mainly useful to support old extensions that provide migrations
* without namespace and to adopt the new feature of namespaced migrations while keeping existing migrations.
*
* @since 2.0.10
* @see $migrationPath
*/
public $migrationNamespaces = [];
/**
@ -594,6 +600,9 @@ abstract class BaseMigrateController extends Controller
if ($this->migrationPath === null) {
$migrationNamespaces = $this->migrationNamespaces;
$namespace = array_shift($migrationNamespaces);
if (strncmp($namespace, '@', 1) === 0) {
$namespace = str_replace('/', '\\', substr($namespace, 1));
}
}
}
@ -619,7 +628,8 @@ abstract class BaseMigrateController extends Controller
return $this->migrationPath;
}
if (!in_array($namespace, $this->migrationNamespaces, true)) {
if (!in_array($namespace, $this->migrationNamespaces, true) &&
!in_array('@' . str_replace('\\', '/', $namespace), $this->migrationNamespaces, true)) {
throw new Exception("Namespace '{$namespace}' not found in `migrationNamespaces`");
}
@ -634,7 +644,11 @@ abstract class BaseMigrateController extends Controller
*/
private function getNamespacePath($namespace)
{
return str_replace('/', DIRECTORY_SEPARATOR, Yii::getAlias('@' . str_replace('\\', '/', $namespace)));
if (strncmp($namespace, '@', 1) === 0) {
return Yii::getAlias($namespace);
} else {
return str_replace('/', DIRECTORY_SEPARATOR, Yii::getAlias('@' . str_replace('\\', '/', $namespace)));
}
}
/**
@ -796,7 +810,7 @@ abstract class BaseMigrateController extends Controller
$path = $migrationPath . DIRECTORY_SEPARATOR . $file;
if (preg_match('/^(m(\d{6}_?\d{6})\D.*?)\.php$/is', $file, $matches) && is_file($path)) {
$class = $matches[1];
if (!empty($namespace)) {
if (!empty($namespace) && strncmp($namespace, '@', 1) !== 0) {
$class = $namespace . '\\' . $class;
}
$time = str_replace('_', '', $matches[2]);