编程语言
首页 > 编程语言> > php-如何让Phalcon将动作委派给其他控制器?

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