【问题标题】:How to make Zend automatically switch view and layout with contexts?如何让 Zend 根据上下文自动切换视图和布局?
【发布时间】:2012-05-21 16:06:38
【问题描述】:

我有一个移动网站,我为 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');
}

所以这行得通,但它有点丑陋和hacky,必须放在每个动作中,并且必须设置每个动作的渲染器等等。我开始阅读有关 Zend ContextSwitch 的内容,这似乎正是那种我应该使用的东西(我对 Zend 还是有点陌生​​),所以我开始弄乱它,但不太明白。

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

$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 之类的内容以切换上下文(我也不需要或想要它;它已经是一个移动站点,我希望布局/视图开关对用户完全透明,并且只能从后端处理,因为它是我快速而肮脏的黑客)。对于我的快速而肮脏的 hack,这些似乎基本上是等量的代码。所以...有人有什么建议吗?我真的希望只有一行像“$contextSwitch->setContext('iphone');”我可以在控制器的 init 中的 If 语句中使用它,但 Zend 文档很糟糕,而且我似乎找不到任何人在 Google 或 SO 上做类似事情的例子。

【问题讨论】:

  • 这似乎是一个使用Plugin 的好地方,但我还没有弄清楚。如果我发现任何更有用的信息,我会回复您。

标签: php iphone zend-framework mobile


【解决方案1】:

好的,我想我知道如何将它放入插件中:

插件:

//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');
        }
    }
}

在您的 application.ini 中注册插件

resources.frontController.plugins.ios = "My_Controller_Plugin_Ios"

我想这就是它的全部。虽然您可能想查看userAgent plugin

【讨论】:

    【解决方案2】:

    ContextSwitch 对请求对象中的“格式”属性进行操作(默认情况下)。你需要在你的应用中设置它

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

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

    【讨论】:

      【解决方案3】:

      我不使用 Zend ContextSwitch,所以我真的帮不上忙,但是您可以在控制器中使用一些继承来设置所有布局,只需几行。尽管它可能仍被归类为“黑客”,但它是一种更好的黑客

      现在,每当您执行一个动作时,Zend 首先会首先触发框架内的许多其他函数,例如路由、preDispatch、动作助手等。它还会在动作之后触发一些事情,例如 PostDispatch。这可以为您所用。

      首先创建一个类似于“mainController”的控制器,让它扩展 Zend_Controller_action 并在这个控制器中创建一个名为 predispatch() 的函数 第二。将您的普通控制器扩展到 mainController。由于我们现在有一个名为 predispatch() 的函数,Zend 会在每个控制器上自动触发它,如果你在那里进行 iPhone/iOS 检查,它将自动在每个控制器上的每个操作上执行,只要你不覆盖控制器中的方法(您可以将此方法设为最终方法以防止这种情况发生)。您当然可以在 maincroller 中使用大量不同的非 Zend 函数和/或帮助程序,以使代码尽可能紧凑和可重用,请参阅下面的示例代码:

      <?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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多