如何列举某个控制器下的所有可用的action

技巧库 · yiqing · 于 4年前 发布 · 4758 次阅读

yii1.x 控制器是有一个missingAction 方法的 ,此方法是一个机会方法,表示在解析跟当前控制器相关的actionId 没有匹配时的一个回调钩子。

比如 XxxController 我们设计了方法actionYyy , actionZzz ,但我们的路由是 xxx/mmm 而我们并没有提供对应的actionMmm方法 或者在

         actions() { return ['mmm'=>[.... ]] } 

配置动作处理类. 对于这种情况默认会报错的:

'Unable to resolve the request ...

yii2中貌似取消了这个missingAction 方法。

我们自己实现其实也不难。需要费点脑细胞而已!

今天要说的其实并不是这个missingAction方法 ,我在一个控制器下面有很多actionXxx 是搞测试用的 ,我需要的一个功能就是列举出所有可用的action(对了 rbac中动态发现所有的action 也有此中需求的)。然后我在调试情况可以发现所有可以用的连接。

通过扩展Application类 可以做到这个,下面给出做法:

<?php
namespace frontend\components ;
/**
 * Created by PhpStorm.
 * User: yiqing
 * Date: 2015/10/4
 * Time: 15:16
 */
class WebApplication extends \yii\web\Application
{

    /**
     * @param string $route
     * @param array $params
     * @return string
     * @throws Exception
     * @throws \yii\base\InvalidRouteException
     */
    public function runAction($route, $params = [])
    {
        try {
           return  parent::runAction($route, $params);
        } catch (\yii\base\InvalidRouteException $ex) {
            //  print all available actions in debug mode !
            if (YII_DEBUG == true) {
                $controller = $this->controller;
                 // if failed to resolve the $route , no controller will be created !
                 if(empty($controller)){
                         // re throw it
                         throw $ex;
                }
                //  $availableActions = $this->controller->actions();
                $availableActions = [];
                $rc = new \ReflectionClass($controller);
                foreach ($rc->getMethods() as $reflectionMethod) {
                    if ($reflectionMethod->isPublic()) {
                        $controllerMethodName = $reflectionMethod->name ;
                        if (($controllerMethodName !== 'actions') && \yii\helpers\StringHelper::startsWith($reflectionMethod->name, 'action')) {
                              $availableActions[] = substr($controllerMethodName,strlen('action'));
                        }
                    }
                }
                array_walk($availableActions,function(&$item1, $key){
                      $item1 = \yii\helpers\Inflector::camel2id($item1) ;
                });
                $availableActions = \yii\helpers\ArrayHelper::merge(
                  $availableActions ,
                    array_keys($controller->actions())
                );

                $content = [] ;
                $controllerId = $controller->getUniqueId() ;
                foreach($availableActions as $actionId){
                    $actionRoute = $controllerId . '/' .$actionId  ;
                    $content[] =  \yii\helpers\Html::a($actionRoute,['/'.$actionRoute]) ;
                }

              return $controller->renderContent(
                  'available action : '.
                  implode('<br/>',$content)
                  .'<br/>'. \yii\helpers\VarDumper::dumpAsString($ex)
              );
            } else {
                // re throw it
                throw $ex;
            }
        }
    }
}

然后 你想看看某个控制器有什么action 只需要瞎输入一个不存在的路由(my-controller-id/any-wrong-action-id) 就可以看到能够访问的action列表了。

我是在高级版中用的 , index.php 使用上面的类即可

require(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/../../common/config/bootstrap.php');
require(__DIR__ . '/../config/bootstrap.php');

/*
$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/../../common/config/main.php'),
    require(__DIR__ . '/../config/main.php')
);
*/
$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/../../common/config/main.php'),
    // 本地的配置文件 可以排除到git提交中
    is_file(__DIR__ . '/../../common/config/main-local.php')? require(__DIR__ . '/../../common/config/main-local.php'):[],
    require(__DIR__ . '/../config/main.php'),
    // 本地的配置文件 可以排除到git提交中
    is_file(__DIR__ . '/../config/main-local.php')? require(__DIR__ . '/../config/main-local.php'):[]
);

// $app = (new yii\web\Application($config)) ;
$app = (new \frontend\components\WebApplication($config)) ;
require(__DIR__ . '/../../common/helpers/functions.php');
    $app->run();

后话

通过上面的代码例子 其实要实现missingAction 就不难了 这个留做练习了 ^_^

本帖已被设为精华帖!
共收到 1 条回复 controller
linphy#14年前 0 个赞

评论一下看看好像不错的样子

添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册