unchanged
Title
pass variables or content block from view file to layout file
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")