实现目标:路由自动匹配:模块/控制器/方法,主要参考了以下两个地址
https://github.com/walkor/webman/issues/54
https://www.workerman.net/q/6685
目前碰到问题,在路由中匹配完成后,通过call_user_func来调用方法,而在方法中我原先使用了自动注入,现在两者冲突了。
路由匹配实现
Route::group('/{module}', function () {
Route::group("/{controller}", function () {
Route::post("/{action}", function ($request, $module, $controller, $action) {
return toRoute($request, $module, $controller, $action, 'create');
});
Route::delete("/{action}", function ($request, $module, $controller, $action) {
return toRoute($request, $module, $controller, $action, 'delete');
});
Route::get("/{action}", function ($request, $module, $controller, $action) {
return toRoute($request, $module, $controller, $action, 'get');
});
Route::put("/{action}", function ($request, $module, $controller, $action) {
return toRoute($request, $module, $controller, $action, 'update');
});
});
});
function toRoute($request, $module, $controller, $action, $method = 'get') {
$class_name = 'app\\api\\controller\\'.$module.'\\'.ucfirst($controller).'Controller';
if(!class_exists($class_name)){
return json(['code'=>404,'msg'=>config('app.debug')?'控制器:'.$class_name.' 不存在':'请求资源不存在']);
}
$action = $method . ucfirst($action);
if (!method_exists($class_name, $action)) {
return json(['code'=>404,'msg'=>config('app.debug')?'控制器方法:'.$action.' 不存在':'请求资源不存在']);
}
$controller = new $class_name;
$request->controller = $class_name;
return call_user_func([$controller, $action], $request);
}
方法部分代码
public function getListData ($request, Student $student)
{
return $this->success();
}
Too few arguments to function app\api\controller\student\StudentController::getListData()
webman : 1.4.7
php-di: 6.3
https://www.workerman.net/doc/webman/di.html#%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E6%B3%A8%E5%85%A5
手册有讲,必须是由框架或者php-di创建的实例才能完成依赖自动注入,手动new的实例无法完成依赖自动注入,如需注入,需要使用support\Container接口替换new语句
改了通过:
$controller = Container::get($class_name);
$request->controller = $class_name;
$request->action = $action;
return call_user_func([$controller, $action], $request);
结果还是报错:
Too few arguments to function app\api\controller\ding\ApiController::getListData(), 1 passed
是我的用法错了吗?请老大指点,从thinkphp转webman,还在适应中!
call_user_func属于手动调用,手动调用需要传完整参数,无法自动注入,这个任何框架都一样。
还有webman现在支持复杂的路由匹配,包括模块/控制器/方法这种,不需要手动设置路由。
老大,因为我有一些特殊需求,根据用户的请求类型,然后在方法前自动带上请求类型,比如访问路由为:system/api/menu,请求方法为get,那么该路由定位的控制器应该是:app/api/controller/system/Apicontroller,方法是:getMenu。内置的路由应该无法满足我的需求,所以需要自己做下处理。
现在我改为:
function toRoute($request, $module, $controller, $action, $method = 'get') {
$class_name = "app\api\controller\".$module."\".ucfirst($controller)."Controller";
if(!class_exists($class_name)){
return json(['code'=>404,'msg'=>config('app.debug')?'控制器:'.$class_name.' 不存在':'请求资源不存在']);
}
$action = $method . ucfirst($action);
if (!method_exists($class_name, $action)) {
return json(['code'=>404,'msg'=>config('app.debug')?'控制器方法:'.$action.' 不存在':'请求资源不存在']);
}
return Container::get($class_name);
}
但是又出现了新的问题:
Object of class app\api\controller\***** could not be converted to string
控制器返回的数据必须时reposne对象,不能是其他对象
老大,我控制器返回的就是Response对象呀,目前我确实不清楚该怎么去修改代码,才能使用,还请老大能指点迷津,谢谢!
return Container::get($class_name); 返回的是控制器实例,不是response实例。
以注入的方式手动调用类方法可以参考这里 https://github.com/walkor/webman-framework/blob/0babc5a57306c21c52f0d6166ce078939ecbbd45/src/App.php#L286
谢谢老大,目前我用:https://www.workerman.net/q/9059;这里的方法经过改写,已实现我的需求。再次感谢,祝愿webman workerman 越来越好!