Yii 2虽然提供了ConsoleApplication的结构,为了让部分逻辑在命令行下运行,就需要编写继承自ConsoleController的控制器及其动作,这也是比较繁琐而重复的工作。作了一些处理,使用基于web的MVC也可以在命令行下运行。
1. 编写一个自定义UrlManager类,假设这个类位于vendor/org/zhangxugg目录中,代码:
<?php
/**
* org\zhangxugg\UrlManager class file.
* @package org\zhangxugg
* @author zhangxugg@163.com 2017-2-28
* @var 2.1
*
* This class is used for CLI route parse. you can run the web-based controller and action.
* usage: php index.php [path-or-module/controllerId/actionId] [arg1=value1] [arg2=value2] ...
* php index.php path/controllerId/action foo=a bar=b => /index.php?r=path/controllerId/action&foo=a&bar=b
*
*/
namespace org\zhangxugg;
use yii;
class UrlManager extends \yii\web\UrlManager {
public function parseRequest($request) {
if(PHP_SAPI !== 'cli') {
return parent::parseRequest($request);
}
if(!isset($_SERVER['argv'][1])) {
echo "yii CLI Interface Usage:\n";
echo $_SERVER['argv'][0]." controllerId/ActionId [param1=val1 param2=val2 ...]\n\n";
echo "above params parsed to:\n\$_GET=array(\n\tparam1=>val1,\n\tparam2=>val2\n);";
Yii::$app->end();
}
$route = $_SERVER['argv'][1] ;
$parts = array();
foreach(array_slice($_SERVER['argv'],2) as $ps) {
if(preg_match("/(\w+?)=(.+)/",$ps,$parts)) {
$_GET[$parts[1]] = $parts[2];
}
}
$_SERVER['REQUEST_URI'] = $_SERVER['argv'][0].'?r='.$_SERVER['argv'][1].'&'.http_build_query($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
Yii::$app->request->setIsConsoleRequest(true);
return [$route, []];
}
}
2. 想办法让这个类实现自动加载,如果使用composer, 修改项目根目录下的composer.josn,加入以下代码段:
"autoload":{
"classmap":["vendor/org/zhangxugg"]
}
命令行下运行:composer dump-autoload, 这是将自定义的类加入到自动加载映射表中,请参阅vendor/composer/autoload_classmap.php文件的变化。
3. 修改项目主配置文件config/web.php,指定urlManager组件使用的class。
'components' => [
'urlManager'=>[
'class' => 'org\\zhangxugg\\UrlManager',
],
4. 命令行下测试运行:
php index.php
php index.php site/index
设置REQUEST_URI 是为了“骗”过框架,不产生异常情况,设置IP,使CheckAccess组件不产生无法取得IP的异常,设置为AJAX标识,避免出错时在命令行下输出HTML代码。
setIsConsoleRequest的作用未知。