Conditional main layout zones diplay based on the rendered view

Hi,

Is there a way to display (or hide) some parts of the main layout depending on the rendered view ?

Regards.

Is it not based on the action? Then you could simply do:




if ($this->action->id === 'example') {

// show something special



Hi, Thanks for the answer. This is a good idea but when i try this in the layout


echo $this->action->id

to see it’s content, I don’t see anything, I’ve also tried this


echo Yii::app()->viewRenderer; 

but nothing is displayed.

Regards,

xav

Did you end up finding a resolution?

Based on Y!!'s suggestion, I have verified that the following code does behave as expected, using the current stable version of Yii (i.e. 1.1.3) and when placed in the protected/views/layouts/main.php file of a newly generated webapp application:


<?php if($this->action->id == "index"): ?>

        <h1>DISPLAY SOMETHING SPECIAL</h1>

<?php else: ?>

        <h1>DISPLAY SOMETHING ORDINARY</h1>

<?php endif; ?> 

When viewing the url:

http://localhost/ind...hp?r=site/index

"DISPLAY SOMETHING SPECIAL" is displayed. However, viewing a url for another action, e.g.:

http://localhost/index.php?r=site/contact

results in "DISPLAY SOMETHING ORDINARY" being displayed.

Maybe you could provide more information on the exact code you are executing.

I created a helper that does this in a very nice way.

http://www.yiiframework.com/forum/index.php?/topic/10960-layout-extension/

I’ve been meaning to add some documentation for it, but i’ve been really busy. I updated it since my last post so this is what it is now.




<?php


class LayoutBlock

{

	private $_id;

	private $_content;

	private $_weight;

	private $_visible;

	private $_htmlOptions = array();

	private $_tagName;

	

	private $_defaultHtmlOptions = array(

		'class'=>'block',

	);

	

	const DEFAULT_BLOCK_TAG = 'div';

	

	public function __construct($id, $content, $weight = 0, $visible = true, $htmlOptions = array(), $tagName = self::DEFAULT_BLOCK_TAG)

	{

		$this->setId($id);

		$this->setContent($content);

		$this->setWeight($weight);

		$this->setVisible($visible);

		$this->setHtmlOptions($htmlOptions);

		$this->setTagName($tagName);

	}

	

	public function getId()

	{

		return $this->_id;

	}

	

	public function getContent()

	{

		return $this->_content;

	}

	

	public function getWeight()

	{

		return $this->_weight;

	}

	

	public function getVisible()

	{

		return $this->_visible;

	}

	

	public function getTagName()

	{

		return $this->_tagName;

	}

	

	public function setId($id)

	{

		if(!is_string($id))

		{

			throw new CException(Yii::t('application','The block id must be a string.'));

		}

		$this->_id = $id;

		return $this;

	}

	

	public function setContent($content)

	{

		if(!is_string($content))

		{

			throw new CException(Yii::t('application','The block content must be a string.'));

		}

		$this->_content = $content;

		return $this;

	}

	

	public function setWeight($weight)

	{

		if(!is_numeric($weight))

		{

			throw new CException(Yii::t('application','The block weight must be a number.'));

		}

		$this->_weight = (int)$weight;

		return $this;

	}

	

	public function setHtmlOptions($htmlOptions, $mergeOld = false)

	{

		if(!is_array($htmlOptions))

		{

			throw new CException(Yii::t('application','The block html options must be a number.'));

		}

		if($mergeOld)

		{

			$this->_htmlOptions = CMap::mergeArray($this->_htmlOptions, $htmlOptions);

		}else{

			$this->_htmlOptions = $htmlOptions;

		}

		return $this;

	}

	

	public function setTagName($tagName)

	{

		if(!is_string($tagName))

		{

			throw new CException(Yii::t('application','The block tag name must be a string.'));

		}

		$this->_tagName = $tagName;

		return $this;

	}

	

	public function setVisible($visible)

	{

		if(!is_bool($visible))

		{

			throw new CException(Yii::t('application','The block visibility must be set to a boolean value.'));

		}

		$this->_visible = $visible;

		return $this;

	}

	

	public function render($return = false, $renderTag = true)

	{

		$block = $this->_content;

		if($renderTag)

		{

			$block = CHtml::openTag($this->_tagName, CMap::mergeArray($this->_defaultHtmlOptions, $this->_htmlOptions)).$block.CHtml::closeTag($this->_tagName);

		}

		if($return === true)

		{

			return $block;

		}else{

			echo $block;

		}

	}

}


class Layout

{

	private static $_instance;

	

	protected $regions;

	

	public function __construct()

	{

		$this->regions = new CMap;

	}

	

	public static function getInstance()

	{

		if(self::$_instance === null)

		{

			self::$_instance = new self;

		}

		return self::$_instance;

	}

	

	protected static function compareBlocks($blockA, $blockB)

	{

		if($blockA instanceof LayoutBlock && $blockB instanceof LayoutBlock)

		{

			if($blockA->getWeight() === $blockB->getWeight())

			{

				return 0;

			}

			return ($blockA->getWeight() <= $blockB->getWeight()) ? -1 : 1;

		}else{

			throw new CException(Yii::t('application','Both blocks must be instances of LayoutBlock or one of it\'s children.'));

		}

	}

	

	protected static function sortBlocks($blocks)

	{		

		$blocks = $blocks->toArray();

		

		uasort($blocks, array(__CLASS__,'compareBlocks'));

		

		return new CMap($blocks);

	}

	

	public function getBlocks($regionId, $visibleOnly = true)

	{

		$instance = self::getInstance();

		

		$blocks   = new CMap;

		

		if($instance->regions->contains($regionId))

		{			

			foreach($instance->regions[$regionId] as $blockId => $block)

			{

				if($visibleOnly)

				{

					if($block->getVisible() === false)

					{

						continue;

					}

				}

				$blocks->add($blockId, $block);

			}

		}

		

		return self::sortBlocks($blocks);

	}

	

	public static function addBlock($regionId, $blockData)

	{

		if(isset($blockData['id']))

		{

			$instance    = self::getInstance();

			

			$blockId     = $blockData['id'];

			$content     = $blockData['content'];

			

			$weight      = isset($blockData['weight'])      ? $blockData['weight']      : 0;

			$visible     = isset($blockData['visible'])     ? $blockData['visible']     : true;

			$htmlOptions = isset($blockData['htmlOptions']) ? $blockData['htmlOptions'] : array();

			$tagName     = isset($blockData['tagName'])     ? $blockData['tagName']     : LayoutBlock::DEFAULT_BLOCK_TAG;

			

			$block       = new LayoutBlock($blockId, $content, $weight, $visible, $htmlOptions);

			

			if(!$instance->regions->contains($regionId))

			{

				$instance->regions[$regionId] = new CMap;

			}

			$instance->regions[$regionId]->add($blockId, $block);

		}else{

			throw new CException(Yii::t('application','A block must have at least an id.'));

		}

	}

	

	public static function addBlocks($blocks = array())

	{

		foreach($blocks as $blockData)

		{

			if(isset($blockData['regionId']))

			{

				$regionId = $blockData['regionId'];

				unset($blockData['regionId']);

				self::addBlock($regionId, $blockData);

			}

		}

	}

	

	public static function getBlock($regionId, $blockId)

	{

		$instance = self::getInstance();

		if(($region = self::getRegion($regionId)) !== null)

		{

			if($region->contains($blockId))

			{

				return $region[$blockId];

			}

		}

		return null;

	}

	

	public static function hasBlock($regionId, $blockId)

	{

		return self::getBlock($regionId, $blockId) !== null;

	}

	

	public static function removeBlock($regionId, $blockId)

	{

		if(($region = self::getRegion($regionId)) !== null)

		{

			if($region->contains($blockId))

			{

				$region->remove($blockId);

			}

		}

	}

	

	public static function getRegion($regionId)

	{

		$instance = self::getInstance();

		return $instance->regions->contains($regionId) ? $instance->regions[$regionId] : null;

	}

	

	public static function hasRegion($regionId)

	{

		return self::getRegion($regionId) !== null;

	}

	

	public static function hasRegions()

	{

		$args = func_get_args();

		if(count($args))

		{

			foreach($args as $regionId)

			{

				if(!self::hasRegion($regionId))

				{

					return false;

				}

			}

			return true;

		}

		throw new CException(Yii::t('application','No region id was specified.'));

	}

	

	public static function renderRegion($regionId, $return = false)

	{

		$regionContent = '';

		

		if(self::hasRegion($regionId))

		{

			$blocks = self::getBlocks($regionId);

			

			foreach($blocks as $block)

			{

				if($block instanceof LayoutBlock)

				{

					$regionContent .= $block->render(true);

				}

			}

		}

		

		if($return)

		{

			return $regionContent;

		}else{

			echo $regionContent;

		}

	}

	

	public static function removeRegion($regionId)

	{

		$instance = self::getInstance();

		

		if($instance->regions->contains($regionId))

		{

			$instance->regions->remove($regionId);

		}

	}

}



And this is an example layout file.




<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo Yii::app()->getLocale()->getId(); ?>" dir="<?php echo Yii::app()->getLocale()->getOrientation(); ?>">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=<?php echo Yii::app()->charset; ?>" />

<meta name="language" content="<?php echo Yii::app()->getLocale()->getId(); ?>" />

<script type="text/javascript">

        var baseUrl = '<?php echo Yii::app()->getBaseUrl(true); ?>';

</script>

<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->getBaseUrl(); ?>/css/common.css" />

<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->getBaseUrl(); ?>/css/layout.css" />

<title><?php echo CHtml::encode($this->pageTitle); ?></title>

<!--[if lt IE 8]>

<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->getBaseUrl(); ?>/css/ie.css" />

<![endif]-->

</head>

<body<?php echo Layout::hasRegions('sidebar.left','sidebar.right') 

? ' class="sidebars"' : Layout::hasRegions('sidebar.left') 

? ' class="sidebar-left"' : Layout::hasRegions('sidebar.right') 

? ' class="sidebar-right"' : ''; ?>>

	<div id="page-container">

		<div id="page">

			<div id="header-container">

				<!-- header -->

				<div id="header">

					<div id="header-content">

					</div>

				</div>

				<!-- /header -->

			</div>

			

			<div id="canvas-container">

				<!-- canvas -->

				<div id="canvas">

					<div id="canvas-content" class="clearfix">

						<?php if(Layout::hasRegion('sidebar.left')): ?>

							<!-- sidebar-left -->

							<div id="sidebar-left" class="sidebar">

								<div class="sidebar-content">

									<?php Layout::renderRegion('sidebar.left'); ?>

								</div>

							</div>

							<!-- /sidebar-left -->

						<?php endif; ?>

								

						<div id="content-container">

							<!-- content -->

							<div id="content">

								<?php echo $content; ?>

							</div>

							<!-- /content -->

						</div>

							

						<?php if(Layout::hasRegion('sidebar.right')): ?>

							<!-- sidebar-right -->

							<div id="sidebar-right" class="sidebar">

								<div class="sidebar-content">

									<?php Layout::renderRegion('sidebar.right'); ?>

								</div>

							</div>

							<!-- /sidebar-right -->

						<?php endif; ?>

					</div>

				</div>

				<!-- /canvas -->

			</div>

			

			<div id="footer-container">

				<!-- footer -->

				<div id="footer">

					<div id="footer-content">

					</div>

				</div>

				<!-- /footer -->

			</div>

		</div>

	</div>

</body>

</html>



In your views or actions, you can specify the contents of the regions as blocks where there is Layout::renderRegion(‘region id’);

like




Layout::addBlock('sidebar.left',array(

    'id'=>'unique block id',

    'content'=>$this->renderPartial('certain view file',array(), true); // this content can be any string, in this case the string returned by renderPartial, u can render a widget, write static data etc...

));



at minimum, you only need to specify the id to define a block

but these are the components of a block




	private $_id;

	private $_content;

	private $_weight;

	private $_visible;

	private $_htmlOptions = array();

	private $_tagName;



I think these properties are self explanatory.

lighter blocks will appear before heavier blocks.

$_tagName is the container tag that the block is rendered in, by default this is ‘div’.

If you decide to use this and have any trouble, feel free to contact me for assistance.

Hi, jeff, many thanks for your answer. I’ve tried your code snippet and it worked and that’s when I figured out why the echo wasn’t working for me and, of course, it is as stupid as placing the code somewhere that doesn’t display in the layout. So thanks to you my problem is solved :slight_smile:

Regards,

xavier

Hi Jayrulez,

This is a very elegant solution and I’m going to give it a try as this is a feature that if often needed during developments.

Many thanks.

Xav

ps:

In my quest for the framework that fits the more my needs, Yii has just become the number one ! It is the framework itself but also the high activity of this forum that pushes this techno to the top level. In a few days I managed to develop something clean and working. So, I’m going to stick to it. Thank you again members of the Yii forum :)

No problem. Glad it helped.