Difference between #3 and #2 of pass variables or content block from view file to layout file

unchanged
Title
pass variables or content block from view file to layout file
unchanged
Category
How-tos
unchanged
Tags
CClipWidget, layouts
changed
Content
if you use yiic to generate webApplication there will exists a layouts dir under
the protected/views/,  and the Controller class under protected/components which
will default use these layouts files .

all your controllers may extends the Controller base class directly or
indirectly . please look at this class you may find this lines :

~~~
[php]
  /**
     * @var string the default layout for the controller view. Defaults to
'//layouts/column1',
     * meaning using a single column layout. See
'protected/views/layouts/column1.php'.
     */
    public $layout = '//layouts/column1';
    /**
     * @var array context menu items. This property will be assigned to {@link
CMenu::items}.
     */
    public $menu = array();
    /**
     * @var array the breadcrumbs of the current page. The value of this
property will
     * be assigned to {@link CBreadcrumbs::links}. Please refer to {@link
CBreadcrumbs::links}
     * for more details on how to specify this property.
     */
    public $breadcrumbs = array();
~~~
these variables will be shared by all its subClasses (may be you whole
XXXController of your project ) . except the $layout variable the other two
usually used to pass variables to layout files :

~~~
[php]
$this->breadcrumbs=array(
	'Albums'=>array('index'),
	'Manage',
);

$this->menu=array(
	array('label'=>'List Album','url'=>array('index')),
	array('label'=>'Create Album','url'=>array('create')),
);

~~~
if you use gii to generate crud functionality you may see such code in the  top
section of file (admin.php,index.php,create.php,update.php,view....).
"$this" represent the current controller , so "breadcrumbs"
and "menu" are the member variables of controller and 
it defined in "Controller" class .   now lets take look at layout file
"column2":


~~~
[php]
<?php $this->beginContent('//layouts/main'); ?>
<div class="container">
	<div class="span-19">
		<div id="content">
			<?php echo $content; ?>
		</div><!-- content -->
	</div>
	<div class="span-5 last">
		<div id="sidebar">
		<?php
			$this->beginWidget('zii.widgets.CPortlet', array(
				'title'=>'Operations',
			));
			$this->widget('zii.widgets.CMenu', array(
				'items'=>$this->menu,
				'htmlOptions'=>array('class'=>'operations'),
			));
			$this->endWidget();
		?>
		</div><!-- sidebar -->
	</div>
</div>
<?php $this->endContent(); ?>
//  and layout main.php:
..
<?php if(isset($this->breadcrumbs)):?>
		<?php $this->widget('zii.widgets.CBreadcrumbs', array(
			'links'=>$this->breadcrumbs,
		)); ?><!-- breadcrumbs -->
	<?php endif?>
..

~~~
so you can see the "$this->menu " and
"$this->breadcrumbs" are assigned in view files (create.php,
index.php, admin.php ....)   ; 

 in yii when some route be executed , lets say (default manner) :
"user/create"   , UserController::actionCreate function will be called
, and in the actionCreate function it
 will render the create.php view file and using some specified layout file .  so
the execution order will be :  create.php(<<view
file>>)create.php(view file) ---->
column2.php(<<layout file>>)----> main.php(<<layout
file>>)column2.php(layout file)----> main.php(layout
file) .  all these file can refer to "$this" variable , so you
can pass variable by defining some public var in the "Controller"
class . and give it some value in view file then fetch it in layouts file .
all above method may be the normal way :) ;

you may notice the file render order : view-->column2--->main ; these just
the view files if look it further :
webapp->userModule->..UserController--->actionCreate-->view--->column2...main.php
 .  any point before the layout files can assign variable and fetch if from
layout file . these execution points are in the same php thread and in same
request scope .  so you can use any global variable to pass value to the
following point ($_GET, $_POST ,$_REQUEST, $_COOKIE;
Yii::app()->params['xx']='value to be passed to following point ').   in my
opinion , do not use $_GET|$_POST|$_COOKIE to pass value , $_GET may affect url
creation (Contorller::createUrl() or CWebApplication::createUrl())  , using
$_POST|$_COOKIE are strange so i prefer use $_REQUEST (because they are in same
"request" scope ) , you can freely use anther method to do that , such
as a singleton Registry class :

~~~
[php]
class Registry /*extends ArrayObject*/
{
    /**
     * @var Registry
     */
    private static  $_instance;

    protected function __construct(){
        //parent::__construt(array(),ArrayObject::...);
    }

    protected function __clone(){
        parent::__clone();
    }

    /**
     * @var array
     *
     */
    private  $_store = array();

    /**
     * @static
     * @return Registry
     */
    public static function instance(){
       if(isset(self::$_instance)){
           return self::$_instance;
       }else{
           return self::$_instance =  new self();
       }
    }

    /**
     * @param $key
     * @param $value
     */
    public function set($key, $value){

        $this->_store[$key] =   $value;
    }

    /**
     * @param $key
     * @param null $default
     * @return null
     */
    public function get($key,$default = null){
      if(isset($this->_store[$key])){
          return $this->_store[$key];
      }else{
          return $default;

      }
    }

    /**
     * @param $key
     * @return bool
     */
    function isValid($key) {
        return  isset($this->_store[$key]) ||
array_key_exists($key,$this->_store) ;
    }
}

~~~
i have create a extension which will be used by some lazy people who don't want
to define variables in "Controller" root class (include me :)  ): 


~~~
[php]
class ExtraAttribute extends CBehavior{
  private $_attributes;

 public function __get($name){
     try{
         return parent::__get($name);
     }catch(CException $e){
         if(isset($this->_attributes[$name])){
             return $this->_attributes[$name];
         }else{
             throw $e;
         }
     }
 }

    public function __set($name,$value){
        try{
           // echo __METHOD__;
            parent::_set($name,$value);
        }catch(CException $e){
            $this->_attributes[$name] = $value;
           // YiiUtil::dumpObject($this);
        }
    }

    public function canSetProperty($name){
        //echo __METHOD__;
        return true;
    }
    public function canGetProperty($name){
       // echo __METHOD__;
        if(parent::canGetProperty($name)){
            return true;
        }elseif(isset($this->_attributes[$name])){
            return true;
        }else{
           return false;
        }
    }

}

~~~
**
usage  **  
in you base controller :


~~~
[php]
class Controller extends CController
{
    public function behaviors(){
        return array(
            'extraAttribute'=>array(
                'class'=>'application.components.ExtraAttribute',
            )
        );
    }

~~~
then you can pass any unPreDefined variable in you view file or you actionXXX
method :


~~~
[php]
// actionXXX()  or someView file:
$this->anyVariableName = "someValue";

// in your layout file :
if(isset($this->anyVariableName)){
  // do by $this->anyVariableName value here ...
}
~~~




above is about how pass variables to layout file , sometimes the content box in
layout file will be different for different views , and we don't want to define
variable in "Controller" class  , the CClipWidget class come to us
just need you define some placeholders in you layout file :

~~~
[php]
// in your  layout file :
 if(isset($this->clips['someSpecMenu'])){

        echo $this->clips['someSpecMenu'];
      }


// and pass clips in some view file  or actionXXX method :

 $this->beginClip('someSpecMenu');
   // echo  any content block here ;
$this->endClip();

~~~


that's all !  hope help some body ;

here are some topic about it: [Yii

 [Yii - On what circumstances should we use clips?
](http://www.yiiframework.com/forum/index.php/topic/31889-yii-on-what-circumstances-should-we-use-clips/
"Yii - On what circumstances should we use clips? ")

[Render Cgridview Pager
Separately](http://www.yiiframework.com/forum/index.php/topic/36547-render-cgridview-pager-separately/
"Render Cgridview Pager Separately")