如何使 Zend 自动切换视图和布局与上下文


How to make Zend automatically switch view and layout with contexts?

我有一个移动网站,我为iPhone和其他iOS设备添加了检测功能。 iOS 页面需要与常规页面(实际上适用于较旧的移动设备(不同的布局和视图。 所以,我有一些代码可以进行移动检测,这部分很容易。 我想做的是使Zend在检测到iOS设备时自动查找并使用正确的布局和视图,但事实证明这非常困难......

我需要它尽快启动并运行,所以我做了一个快速而肮脏的黑客:在每个动作函数中,我有一个简单的 If 语句来检测是否已设置 iOS 布尔标志(这发生在控制器的 init 中(,如果是这样,则显式覆盖布局和视图。 现有代码(在操作中(:

if ($_SESSION['user']['iPhone']) {
    $this->_helper->layout->setLayout('osriphone'); // 'osr' is the name of the app
    $this->_helper->viewRenderer->setRender('iphone/index');
}

所以这很有效,但它有点丑陋和笨拙,必须放在每个动作中,并且必须设置每个动作的渲染器,等等。 我开始阅读有关Zend ContextSwitch的信息,这似乎正是我应该使用的那种东西(我对Zend仍然很陌生(,所以我开始弄乱它,但不能完全弄清楚。

在控制器的初始化中,我正在初始化ContextSwitch,为"iphone"添加上下文并将后缀设置为"iphone",现在我想做的是有一个地方来检测用户是否是iOS设备并将上下文设置为"iphone",这应该使其自动使用正确的布局和视图。 新代码(在控制器的初始化中(:

$this->_helper->contextSwitch()->initContext();
$contextSwitch = $this->_helper->getHelper('contextSwitch');
$contextSwitch->addContext('iphone', array('suffix' => 'iphone'));
$contextSwitch->setAutoDisableLayout(false);
if ($_SESSION['user']['iPhone']) {
    //$this->_currentContext = 'iphone'; // Doesn't work.
    //$contextSwitch->initContext('iphone'); // Doesn't work.
    //$contextSwitch->setContext('iPhone'); // Not the function I'm looking for...
    // What to put here, or am I barking up the wrong tree?
}

我在contextSwitcher上做了一些阅读,似乎有很多东西,例如将其设置为特定于每个特定操作(我不需要;这需要发生在我应用程序中的每个操作上(,并浏览并修改所有指向/osr/format/iphone之类的链接以切换上下文(我也并不真正需要或想要;它已经是一个移动网站, 我希望布局/视图开关对用户完全透明,并且只能从后端处理,就像我的快速而肮脏的黑客一样(。 这些似乎与我的快速和肮脏的黑客基本上是等量的代码。 所以。。。有人有什么建议吗? 我真的希望只有像"$contextSwitch->setContext('iphone'(;"这样的一行,我可以在我的控制器的init中的If语句中使用,但是Zend文档很糟糕,我似乎找不到任何人们在Google或SO上做这样的事情的例子。

好的,

我想我想出了如何将其放入插件中:

插件:

//This is my own namespace for ZF 1.x library, use your own
class My_Controller_Plugin_Ios extends Zend_Controller_Plugin_Abstract {
    public function preDispatch(Zend_Controller_Request_Abstract $request) {
        parent::preDispatch($request);
        if ($_SESSION['user']['iPhone']) {
            $this->_helper->layout->setLayout('osriphone');
            $this->_helper->viewRenderer->setRender('iphone/index');
        }
    }
}

在应用程序中注册插件.ini

resources.frontController.plugins.ios = "My_Controller_Plugin_Ios"

我认为这就是它的全部内容。虽然你可能想看看用户代理插件

ContextSwitch 关闭请求对象中的 "format" 属性(默认情况下(。您需要将其设置在应用中的某个位置

$requestObject->setParam('format', 'iphone').

我会将其设置为引导程序,或者更恰当地说,设置控制器插件,但它的去向实际上取决于您的应用程序。

我不使用 Zend ContextSwitch,所以我真的帮不上忙,但你可以在控制器中使用一些继承来设置所有布局。即使它可能仍然被归类为"黑客",但这是一种更好的黑客方式

现在,每当你执行一个动作时,Zend首先会首先触发框架中的许多其他函数,比如路由、preDispatch、Action助手等。它还会在操作后触发许多东西,例如PostDispatch。这可以用于您的优势。

首先创建一个名为"mainController"的控制器,让它扩展Zend_Controller_action并在此控制器中创建一个名为predispatch((的函数第二。将普通控制器扩展到主控制器。由于我们现在有一个名为predispatch((的函数,Zend将自动在每个控制器上触发它,如果你在那里进行iPhone/iOS检查,它将自动在每个控制器上的每个操作上执行,只要你不覆盖控制器中的方法(你可以使此方法最终防止这种情况(。您可以在维护者中使用许多不同的非 Zend 函数和/或辅助程序,以使代码尽可能紧凑和可重用 Se 示例代码如下:

<?php
/**
*Maincontroller
*/
class MainController extends Zend_Controller_Action
{
    /**
    * Predispatch function is called everytime an action is called
    */
    final public function preDispatch(){
        //for security reasons, make sure that no one access mainController directly
        $this->request = $this->getRequest();
        if (strtolower($this->request->controller)=='main')
            $this->_redirect('/index/index/');
        //Check for iPhone
        if ($_SESSION['user']['iPhone']) {
            $this->_helper->layout->setLayout('osriphone'); // 'osr' is the name of the app
            $this->_helper->viewRenderer->setRender('iphone/index');
        }
    }
 }

<?php
/**
*Othercontroller
*/
class OtherController extends MainController
{
    /**
    * The correct layout for IndexAction is already set by the inherited preDispatch
    */
    public function indexAction(){
        /* YOUR CODE HERE */
    }
 }

要很好地概述调度过程,请查看以下链接(两个链接中的图片相同(:http://nethands.de/download/zenddispatch_en.pdf

http://img.docstoccdn.com/thumb/orig/22437345.png