dongyu3967 2012-05-21 16:06
浏览 25

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

I have a mobile site that I added detection to for iPhones and other iOS devices. The iOS page needs a different layout and views than the regular pages (which are actually for older mobile devices). So, I have some code that does mobile detection, that part was easy. What I'd like to do is make it so that Zend automagically finds and uses the correct layout and view when an iOS device is detected, but that has turned out to be surprisingly hard...

I needed it to be up and running ASAP, so I did a quick and dirty hack that worked: in each action function, I have a simple If statement that detects if the iOS boolean flag has been set (which happens in the controller's init), and if so, overrides the layout and view explicitly. Existing code (in the actions):

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

So this works, but it's kinda ugly and hacky and has to be put in each action, and each action's Renderer has to be set, etc. I got to reading about the Zend ContextSwitch, and that seemed like exactly the kind of thing I should use (I'm still kind of new to Zend), so I started messing around with it, but can't quite figure it out.

In the controller's init, I'm initializing the ContextSwitch, adding a context for 'iphone' and setting the suffix to 'iphone', and now what I'd like to do is have a single place where it detects if the user is an iOS device and sets the context to 'iphone', and that should make it automatically use the correct layout and view. New code (in the controller's 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?
}

I did some reading on the contextSwitcher, and it seems like there is a lot of stuff on, e.g. setting it to be specific to each particular action (which I don't need; this needs to happen on every action in my app), and going through and modifying all the links to something like /osr/format/iphone to switch the context (which I also don't really need or want; it's already a mobile site, and I'd like the layout/view switch to be totally transparent to the user and handled only from the backend as it is with my quick and dirty hack). These seem like basically an equal amount of code to my quick and dirty hack. So... Anyone have some suggestions? I'm really hoping for just a single line like "$contextSwitch->setContext('iphone');" that I could use in an If statement in my controller's init, but the Zend documentation is awful, and I can't seem to find any examples of people doing something like this on Google or SO.

  • 写回答

3条回答 默认 最新

  • douhuan1257 2012-05-21 19:47
    关注

    I don't use Zend ContextSwitch so I can't really help there, but you could use some inheritance in your controllers to set all layouts in just a couple of lines. Even though it might still be classed as a "hack" it is a way better hack

    Now whenever you execute a action Zend first fires a number of other functions within the framework first, such as the routing, the preDispatch, Action helpers and so on. It also fires a number of things after the action such as PostDispatch. This can be used to your advantage.

    First create a controller called something like "mainController" and let it extend Zend_Controller_action and in this controller create a function called predispatch() Second. Extend your normal controllers to mainController. Since we now have a function called predispatch() Zend will automatically fire this on every controller, and if you do your iPhone/iOS check there it will automagically be performed on every action on every controller, as long as you don't overwrite the method in your controller (you can make this method final to prevent this). You can offcourse use a multitude of different non-Zend functions and/or helpers within the mainctroller to make the code as compact and reusable as possible Se example code below:

    <?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 */
        }
     }
    

    For a good overview of the dispatch process check these links (same picture in both): http://nethands.de/download/zenddispatch_en.pdf

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

    评论

报告相同问题?

悬赏问题

  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥15 想问一下树莓派接上显示屏后出现如图所示画面,是什么问题导致的
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)
  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化