Yii2 以编程方式迁移命令

Yii2 Migrate Command Programmatically

我想 migrate up/down 数据库使用 code 而不是控制台 window。我调查了 framework。我试过以下代码:

$runner = new yii\console\Application([
                                          'id'       => 'auto-migrate',
                                          'basePath' => dirname(__DIR__)
                                      ]);        

    $runner->runAction('migrate');
    ob_start();
    return htmlentities(ob_get_clean(), null, Yii::$app->charset);

给出了Internal Server Error。甚至不将文件迁移到数据库。 但如果该目录不存在,它会创建该目录。它的行为方式应该如此,但如果迁移文件存在于同一目录中,它会给出 Internal Server Error.

我可能会在 php 函数 exec 上这样做,但如果您真的想通过创建新的应用程序实例来做到这一点,那么您应该可以这样做。

案例 1 - 不是很好的主意

//Define, if you want to capture output
defined('STDIN') or define('STDIN', fopen('php://input', 'r'));
defined('STDOUT') or define('STDOUT', fopen('php://output', 'w'));
//Create new console app, if you do not run it from root namespace you should use '\yii\console\Application'
$runner = new \yii\console\Application([
    'id'       => 'auto-migrate',
    'controllerNamespace' => 'console\controllers', //for migrate command it should not matter but for other cases you must specify otherwise applocation cannot find your controllers
    'basePath' => dirname(__DIR__ . '/../../console/config'), //This must point to your console config directory, when i run this in frontend sitecontroller i must add '/../../console/config',
    'components' => [
                'db' => [//If you want to call migrate you probably need some database component
                    'class' => 'yii\db\Connection',
                    'dsn' => 'mysql:host=localhost;dbname=mydb',
                    'username' => 'root',
                    'password' => '',
                    'charset' => 'utf8',
                ],
            ],
]);        
ob_start();
try
{
    $runner->runAction('migrate/up');
}
catch(\Exception $ex)
{
    echo $ex->getMessage();
}
return htmlentities(ob_get_clean(), null, Yii::$app->charset);

我的结果是:

Yii Migration Tool (based on Yii v2.0.1) No new migration found. Your system is up-to-date.

案例二

    ob_start();
    try
    {
        $output = Array();
        exec(__DIR__ . '/../../yii migrate/up', $output);
        echo implode("\n", $output);
    }
    catch(\Exception $ex)
    {
        echo $ex->getMessage();
    }
    return htmlentities(ob_get_clean(), null, Yii::$app->charset);

我的结果是:

Yii Migration Tool (based on Yii v2.0.1) No new migration found. Your system is up-to-date.
\Yii::$app->runAction('migrate', ['migrationPath' => '@yii/rbac/migrations/']);

您可以通过将控制台配置加载到 运行 迁移来创建控制台应用程序:

public function actionMigrate()
{
    // Keep current application
    $oldApp = \Yii::$app;
    // Load Console Application config
    $config = require \Yii::getAlias('@app'). '/config/console.php';
    new \yii\console\Application($config);
    $result = \Yii::$app->runAction('migrate', ['migrationPath' => '@app/migrations/', 'interactive' => false]);
    // Revert application
    \Yii::$app = $oldApp;
    return;
}

以上示例代码适用于 yii2-app-basic 模板,您可以更改 yii2-app-advanced 模板的路径。

对于这种情况,我使用这个解决方案。我只实现了 migrate/up 案例。要执行任何其他 migrate 命令,您必须配置 runAction().

的参数
use yii\console\controllers\MigrateController;

/*Suppose that config is an array with the following structure
[
    'class' => 'yii\db\Connection',
    'dsn' => "$dsn",
    'username' => "$username",
    'password' => "$password",
    'charset' => 'utf8',
]
*/
public function migrateUp($config){
    $migrate = new MigrateController('migrate', \Yii::$app);
    /*The name of the table for keeping applied migration information*/
    $migrate->migrationTable = 'migration';
    /*At least one of `migrationPath` or `migrationNamespaces` should be specified.
    For this example I use `migrationNamespaces` to find a specific set of migrations I want to execute.*/
    $migrate->migrationNamespaces = [
        'app\modules\v1\migrations'
    ];
    $migrate->migrationPath = null;
    /*The DB connection object to use when applying migrations*/
    $migrate->db = $config;
    /*Run migrations without asking questions*/
    $migrate->interactive = false;
    /*The individual commands ran within the migration will not be output to the console*/
    $migrate->compact = true;
    /*php://temp is a read-write stream that allow temporary data to be stored in a file-like wrapper */
    define('STDOUT', $fp= fopen('php://temp', 'r+'));
    /*run migrate/up */
    $status = $migrate->runAction('up');
    /*Rewind the position of the file pointer*/
    rewind($fp);
    $migrationOutput = stream_get_contents($fp);
    if (isset($status)){
        ob_get_clean();
        return ['Errors when executing migrations', $migrationOutput];
    }
    return ['Everything ok', $migrationOutput];
}

使用 Yii2 的高级模板的共享主机 - Web 应用程序中的控制台应用程序 我已经通过一些调整成功地应用了上面的代码。

带有子文件夹的单域 multi/web,例如。 company1/web

multi/web/index.php
         /.htaccess
         /assets
         /common/config/main.php
         /common/config/bootstrap.php
         /config/main-local.php has 
                /only db and urlManager baseUrl=''
         /console/config/main.php
         /frontend/config/main.php
         /images
         /company1/web/assets
         /company1/web/images
         /company1/web/.htaccess
         /company1/web/index.php
         /company1/config/main-local.php

         /company2/web/assets
         /company2/web/images
         /company2/web/.htaccess
         /company2/web/index.php
         /company2/config/main-local.php 

         /company3/web/assets
         /company3/web/images
         /company3/web/.htaccess
         /company3/web/index.php
         /company3/config/main-local.php         
         /vendor

每个公司配置 main-local 仅包含 db 和 UrlManager 组件。 UrlManager 的 baseUrl 例如。 '/company3/web/'

multi/web index.php配置如下:

<?php

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
defined('YII_CONSOLE') or define('YII_CONSOLE', false);

//vendors from composer.json
require (__DIR__ . '/vendor/autoload.php');

//yii framework
require(__DIR__  . '/vendor/yiisoft/yii2/Yii.php');

//common frontend bower and installer aliases
require(__DIR__ . '/common/config/bootstrap.php');

//empty
require(__DIR__ . '/frontend/config/bootstrap.php');

$config = yii\helpers\ArrayHelper::merge(
    //vendor path, twilio, paypal
    require(__DIR__ . '/common/config/main.php'),

    //db=installer , urlmanager swiftmailer
    require(__DIR__ . '/common/config/main-local.php'),

    //etc... db and UrlManager Removed into above
    require(__DIR__ . '/frontend/config/main.php'),

    //cookie validation key
    require(__DIR__ . '/frontend/config/main-local.php')
);
(new yii\web\Application($config))->run();
?>

各公司子文件夹的index.php配置如下:

<?php

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
defined('YII_CONSOLE') or define('YII_CONSOLE', false);

require(dirname(dirname(__DIR__)) . '/vendor/autoload.php');
require(dirname(dirname(__DIR__))  . '/vendor/yiisoft/yii2/Yii.php');
//aliases eg. common frontend bower
require(dirname(dirname(__DIR__)) . '/common/config/bootstrap.php');
$config = yii\helpers\ArrayHelper::merge(

    //vendor path components ...rbac
    require(dirname(dirname(__DIR__)) . '/common/config/main.php'),

    //customer's  database and urlmanager and swiftmailer taken out of frontend/config/main.php
    require(dirname(__DIR__) . '/config/main-local.php'),

    //excluding components db and urlmanager included in above
    require(dirname(dirname(__DIR__)) . '/frontend/config/main.php'),

    //cookie validation key
    require(dirname(dirname(__DIR__)) . '/frontend/config/main-local.php')
);
//
(new yii\web\Application($config))->run();
``````
I have created an action in my Site controller to perform the console migration within the actionMigrateto_company_database.


<?php

public function actionMigrateto_company_database()
    {
        ob_start();
        defined('STDIN') or define('STDIN', fopen('php://input', 'r'));
        defined('STDOUT') or define('STDOUT', fopen('php://output', 'w'));
        defined('STDERR') or define('STDERR', fopen('php://stderr', 'w'));
        $oldApp = \Yii::$app;
        // Load Console Application config
        $config = yii\helpers\ArrayHelper::merge(
        //migration namespaces and 
        //namespaces included in individual
        //migration files
        require \Yii::getAlias('@console'). '/config/main.php',    
        //vendor path components ...rbac
        require \Yii::getAlias('@common').'/config/main.php',
        //database
        require (dirname(dirname(__DIR__)) .dirname(Yii::$app->urlManager->baseUrl). '/config/main-local.php'));    
        $runner = new \yii\console\Application($config);
        $runner->runAction('migrate',['db','interactive' => 0]);
        fclose(\STDOUT);
        fclose(\STDIN);
        fclose(\STDERR);
        \Yii::$app = $oldApp;
        return ob_get_clean();
      }
?>

Adjust the frontend\views\layouts\main.php with 

if (Yii::$app->UrlManager->baseUrl === '') and 
 if (Yii::$app->UrlManager->baseUrl <> '') statements.

.htaccess files are all as follows: 
`````
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php
`````