在Zend Framework中转发并返回一个动作

时间:2010-11-04 13:19:58

标签: php zend-framework

在Zend Framework中,我们可以使用_forward()

转发到另一个控制器的动作

E.g。

// Inside controller1
$this->_forward('foo', "controller2");
echo $this->getResponse(); // Echo the response of foo action at this point

但_forward是在请求周期结束时采取的,如果我想立即转发并立即回应响应怎么办?

8 个答案:

答案 0 :(得分:2)

你应该做

$this->_forward('foo', "controller2");
return;

答案 1 :(得分:1)

我个人建议使用Action plugin或View Helper来解决您的问题。我过去曾做过很多很多这样的事情,而且他们可以非常有帮助和强大。

或者,如果您只是想获取您网站的模块,例如登录/类别部分,可能需要将视图助手视为“部分”。

查看助手:http:// framework.zend.com/manual/en/zend.view.helpers.html

答案 2 :(得分:0)

_forward函数在当前操作运行后转发,以防您知道。

答案 3 :(得分:0)

听起来你正在重复代码,在这种情况下,这个逻辑应放在模型上。这样,您可以在需要时调用该功能

答案 4 :(得分:0)

它认为您正在寻找HMVC pattern。我之前曾问过question与此类似的问题,但似乎只有Zend Framework才有可能。有一个名为DotKernel的框架,它是Zend Framework的扩展。他们说它实现了(简化版)HMVC,但我从未使用它。

切换到Kohana 3。这个框架对HMVC有原生支持,可以做你想要的。

答案 5 :(得分:0)

正如这里的许多答案所述,您的设计很可能会使用某些评论,并且某些逻辑应该重构为模型类或操作助手。这两个最大的警告信号是:

  • 你正试图在你的“外部”行动发生时操纵其他“内在”行动的反应
  • 您正在尝试操作共享对象/模型

这两种情况都会在一个或两个方向上产生不良的相互依赖性,并导致代码重用,从长远来看很难维护。

但是,在某些常见情况下,我发现“内部”操作对于彻底重用控制器操作非常有用。最常见的是当你在外部动作的视图中真正只需要内部动作的响应时。在您的视图中,您可以轻松使用Zend_View_Helper_Action:

print $this->action('foo', 'controller2');

例如,当包含由另一个视图创建的一些javascript时,这可能很有用。例如,MenuController :: viewAction可能有这样的响应:

(function() { 
  var menuComponent = new MenuObject({dynamicOptions: ...}); 
  return menuComponent;
})()

现在在DefaultController :: indexAction的视图脚本中,您可以执行以下操作:

var mainmenu = <?php print $this->action('view', 'menu'); ?>;
navigationBar.add(mainmenu);

此外,在SpecificModule_DefaultController :: indexAction的视图脚本中,您可以执行以下操作:

var modulemenu = <?php 
  print $this->action('view', 'menu', 'default', array(
    'Module' => 'SpecificModule'
  ));
?>;
moduleWidgetMenu.add(modulemenu);

这可以是重用动作的强大技术,实质上是创建嵌套的MVC请求(请参阅此处有关HMVC的其他答案)。在上面的示例中,我们将菜单集中呈现为一个动作,并且我们能够以各种方式使用它。此外,我们在执行该操作时具有更大的灵活性,因为我们在单独的执行上下文中获得完整的操作生命周期(dispatch / plugins / etc.),而不是将逻辑重载到大视图和/或操作帮助程序中。

确保这一点的两个非常关键的事情将有助于您的设计在使用此方法时保持安全和理智:

  • “内部”请求(动作及其相关视图)应该没有“外部”请求的概念,甚至根本不知道它的存在。
  • “外部”请求(操作及其关联视图)应该无法控制内部请求,除非作为参数传递给 $ this-&gt;操作($ actionName,$ controllerName,$ moduleName,$ paramsArray) call。

当不修改ZF实现的标准MVC生命周期时,这种方法通常最好地进行必要的维护,包括使用ViewRenderer动作帮助程序的两步视图方法。

答案 6 :(得分:0)

以下是我使用的内容:

class MyController extends Zend_Controller_Action {

    public function indexAction() {
       $response = $this->_redispatch('world');
       echo 'hello '.$response->getBody() // outputs 'hello world'
    }

    public function worldAction() {
       echo 'world';
    }

    protected function _redispatch($action, $controller = null, $module = null, array $params = null) {
        $request = new Zend_Controller_Request_Simple;
        $response = new Zend_Controller_Response_Http;

        $request->setActionName($action);

        if (isset($controller)) {
            $request->setControllerName($controller);   
        } else {
            $request->setControllerName($this->_request->getControllerName());
        }

        if (isset($module)) {
            $request->setModuleName($module);   
        } else {
            $request->setModuleName($this->_request->getModuleName());
        }

        if (!empty($params)) {
            foreach ($params as $key => $value) {
                $request->setParam($key, $value);   
            }
        }

        $dispatcher = $this->getFrontController()->getDispatcher();
        $dispatcher->dispatch($request, $response);

        return $response;
    }

}

答案 7 :(得分:0)

Zend_Controller_Dispatcher_Standard :: dispatch()可能会更好地满足您的需求。传递请求(Zend_Controller_Front :: getRequest())和Zend_Controller_Response对象。当方法返回时,您可以通过Zend_Controller_Front :: getResponse()捕获响应。

以下是Zend / Test / PHPUnit / ControllerTestCaseTest.php的示例:

$this->testCase->getFrontController()->setControllerDirectory(dirname(__FILE__) . '/_files/application/controllers');
$this->testCase->dispatch('/zend-test-php-unit-foo/bar');
$request  = $this->testCase->getRequest();
$response = $this->testCase->getResponse();
$content  = $response->getBody();
$this->assertEquals('zend-test-php-unit-foo', $request->getControllerName(), $content);
$this->assertEquals('bar', $request->getActionName());
$this->assertContains('FooController::barAction', $content, $content);