0

我有一个移动网站,我为 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”,这应该使其自动使用正确的布局和视图。新代码(在控制器的初始化中):

$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');” 我可以在控制器初始化中的 If 语句中使用,

4

3 回答 3

0

我不使用 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

于 2012-05-21T19:47:35.353 回答
0

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

插件:

//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 插件

于 2012-05-22T07:53:28.623 回答
0

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

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

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

于 2012-05-21T20:03:03.397 回答