php-如何让Phalcon将动作委派给其他控制器?
作者:互联网
问题
我希望能够编写类似控制器的类,并将其作为最终应用程序的供应商来提供.然后,最终应用程序控制器可以仅实例化我的类并调用其操作方法.
关键是我希望它们被自动调用.我必须避免在终端控制器中重复每种操作方法.
第一种方法
我已经试过了:
码
class IndexController
{
protected $vendorController;
public function initialize()
{
$this->vendorController = new VendorController();
}
public function __call($name, $args)
{
call_user_func_args([$this->vendorController, $name], $args);
}
}
VendorController类如下所示:
class VendorController
{
public function testAction()
{
die("this is test action");
}
}
结果
但这给了我
Action 'test' was not found on handler 'index'
我假设I’ve checked Phalcon内部进行如下检查:
if (method_exists($controller, $actionName)) { // ...
结果导致找不到动作.
也许我可以以某种方式覆盖此行为?我正在使用自己的调度程序类,如果有任何帮助,它可以扩展Phalcon的本机调度程序.但是我试图重写诸如getHandlerName()之类的方法,但没有成功.
第二种方法
我还尝试使用特征:
码
trait TVendorController
{
public function testAction()
{
die("this is test action");
}
}
class IndexController
{
use TVendorController;
}
这种方法有效,但有一个主要缺陷:
缺陷
如果IndexController扩展了包含诸如initialize()或beforeExecuteRoute()之类的方法的BaseController(通常是这种情况),那么忘记调用它们就太容易了.这里的威胁是BaseController方法可能包含例如身份验证逻辑:
trait TVendorController
{
public function beforeExecuteRoute()
{
// silently overrides the BaseController::beforeExecuteRoute()
}
public function testAction()
{
die("this is test action");
}
}
abstract class BaseController
{
public function beforeExecuteRoute()
{
// OOPS: this is never called
$username = $this->session->get('username', null);
if (!$username) {
$this->response->redirect('index/login');
}
}
}
class IndexController extends BaseController
{
use TVendorController;
}
问题
在第一种方法的情况下:如何告诉Phalcon的事件循环该动作实际上存在于控制器中?
或者,如果无法完成,则:
>如何编写我的供应商控制器?
>如何将它们组合到最终应用程序控制器中,以便自动调用操作?
解决方法:
您可以尝试添加带有dispatch:beforeDispatch附件的EventManager.在dispatch:beforeDispatch时刻,您知道动作名称,但是应该可以在检查动作是否确实存在之前将其击中.
在beforeDispatch函数中,您可能需要检查,是否可以在控制器中调用传递的动作名称,如果不能,则应该能够转发给execvendorAction方法之王.
编辑:
我已经完成了此事件的管理:
$di->setShared('dispatcher', function() {
$dispatcher = new Dispatcher();
$eventsManager = new EventsManager();
$eventsManager->attach("dispatch:beforeDispatch", function($event, $dispatcher) {
$controllerName = $dispatcher->getControllerClass();
$action = $dispatcher->getActionName();
if(!method_exists($controllerName, $action . 'Action')) {
$dispatcher->forward(array(
// not delivering 'controller' param to make it stay
// in current one
'action' => 'vendor',
'params' => array(
'name' => $action,
'params' => $dispatcher->getParams()
)
));
}
});
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
然后,我在controllerBase中添加了以下操作:
public function vendorAction($name, $arguments) {
var_dump(array(
'name' => $name,
'arguments' => $arguments
));
// $name .= 'Action';
if(method_exists(array($this->vendorController, $name))) {
call_user_func_args(array($this->vendorController, $name), $arguments);
} else {
// work it out
}
}
并使其工作.从controllerBase扩展的每个控制器都将在vendorController中交付的方法中运行您的方法.您将必须制定自己的方法来处理notFound异常,因为这是非常不标准的实现.
在Phalcon上使用经典路由器/调度程序/所有工具进行了测试.
标签:event-loop,phalcon,php 来源: https://codeday.me/bug/20191119/2035273.html