Search code examples
phpzend-frameworkplaceholderzend-viewzend-layout

Zend Framework - clear a custom placeholder from a viewscript


I'm trying to clear a custom placeholder from a viewscript, let's say I have a controller plugin that creates a sidebar:

    $bootstrap = Zend_Controller_Front::getInstance()->getParam('bootstrap');
    $view = $bootstrap->getResource('view');
    $partial = $view->render('partials/_sidebar.phtml');
    $view->placeholder('sidebar')->append($partial);

My partial contains my submenu (rendered through Zend_Navigation view helper).

In order to render that sidebar, I have this in my layout:

<?= $this->placeholder('sidebar'); ?>

But what if in some pages I don't want to display my sidebar (login page for example) ? How can I handle these cases?

I thought I could reset/clear my placeholder using $this->placeholder('sidebar')->exchangeArray(array()); but it seems that I can't access my placeholder from a viewscript:

// in /application/modules/default/views/account/login.phtml
<?php $placeholder = $this->placeholder('sidebar');
Zend_Debug::dump($placeholder); ?>

// output:

object(Zend_View_Helper_Placeholder_Container)#217 (8) {
  ["_prefix":protected] => string(0) ""
  ["_postfix":protected] => string(0) ""
  ["_separator":protected] => string(0) ""
  ["_indent":protected] => string(0) ""
  ["_captureLock":protected] => bool(false)
  ["_captureType":protected] => NULL
  ["_captureKey":protected] => NULL
  ["storage":"ArrayObject":private] => array(0) {
  }
}

Any idea how to do such a thing?

Thanks.

Edit:

My problem was very simple actually, since my plugin was registered and executed in the postDispatch() method, then my viewscript was executed before the plugin and the layout was executed after the plugin.

From now on, what are my options? I can't really declare my sidebar in the preDispatch method because there won't be any script directory set, and therefore I won't be able to determine which view script to execute at this step.

I could also use an action() helper, what do you think? A question has been already asked about it. I still feel like this is not the proper way to do it, and it sounds overkilling to me.

Also, another idea would be to move my plugin into a the preDispatch() method of my controller, but that would lead me to copy/paste on every controller my sidebar, or create a baseController, but I still don't like this idea, I feel like I'm doing it wrong.

Any idea?


Solution

  • You were pretty close actually. You just needed to add the name of your placeholder, sidebar in this case:

    $this->placeholder('sidebar')->exchangeArray(array()); should work.

    See http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.placeholder

    EDIT:

    That's strange that the above did not work for you. I tested this out on my own ZF website and it worked. Possibly different scenario. I don't know.

    Here is another alternative, albeit more involved.

    //Get the placeholder object directly
    $placeholderObj = $this->getHelper('placeholder')
    
    //This may be why you were getting null in your example above. Since your were using the magic method in the View class to call the placeholder view helper method directly.
    
    //For example you could call the placeholder like so:
    $placeholderObj->placeholder('sidebar')->set("Some value");
    
    //Now the alternative way to remove the placeholder value is as follows.
    $registry = $placeholderObj->getRegistry()
    $registry->deleteContainer('sidebar');
    

    EDIT3

    It should work as a Zend_Controller_Plugin using preDispatch hook. I think the only you need to make sure of is that you order that plugin after you setting your view script/helper paths and layout paths. This can be done in the same plugin or in another plugin.

    Here is a code example based on something I use on my website. The relevant part is just the stuff in preDispatch where I set the view script paths, etc

    class RT_Theme extends Zend_Controller_Plugin_Abstract
    {
        private $_sitename;
        private $_assets;
        private $_appPath;
        private $_appLibrary;
    
        /**
         * Constructor
         * 
         * @param string $sitename
         * @param SM_Assets $assets
         * @param string $appPath
         * @param string $appLibrary
         */
        public function __construct($sitename, $assets, $appPath, $appLibrary)
        {
            $this->_sitename = $sitename;
            $this->_assets = $assets;
            $this->_appPath = $appPath;
            $this->_appLibrary = $appLibrary;
        }
    
        /**
         * Sets up theme
         * 
         * Sets up theme template directory and assets locations (js, css, images)
         * 
         * @param Zend_Controller_Request_Abstract $request
         */
        public function preDispatch(Zend_Controller_Request_Abstract $request)
        {
            $module = $request->getModuleName();
            $controller = $request->getControllerName();
            $action = $request->getActionName();
    
            $layout = Zend_Layout::getMvcInstance();
            $view = $layout->getView();
    
            $view->sitename = $this->_sitename;
            $view->headTitle()->setSeparator(' - ')->headTitle($view->sitename);
    
            $layout->setLayoutPath($this->_appPath . "/html/$module/layout/");
    
            $view->setScriptPath($this->_appPath . "/html/$module/view/");
            $view->addScriptPath($this->_appPath . "/html/$module/view/_partials/");
    
            $view->addScriptPath($this->_appLibrary . '/RT/View/Partials/');
            $view->addHelperPath('RT/View/Helper', 'RT_View_Helper');
    
            $view->addHelperPath($this->_appPath . '/html/view/helpers','My_View_Helper');
    
            $viewRenderer =
                Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
            $viewRenderer->setView($view); 
    
    
            //Ignore this line. Not relevant to the question                 
            $this->_assets->loadFor($controller, $action);
    
            //Example: Now I can set the placeholder.
            $view->placeholder('header_title')->set($view->sitename);
        }
    }