Layout extension

Layout.php




<?php


class Layout

{

	private static $_instance;

	private static $_regions = array();

	private static $_blocks = array();

	

	public function __construct()

	{

	}

	

	public function init()

	{

	}

	

	public static function getInstance()

	{

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

			self::$_instance = new self;

		return self::$_instance;

	}

	

	public static function hasRegion($regionId)

	{

		$clips = Yii::app()->controller->clips;

		if($clips->contains($regionId))

		{

			if(!empty($clips[$regionId]))

				return true;

		}

		return false;

	}

	

	public function hasRegions($regionIds=array())

	{

		foreach($regionIds as $regionId)

		{

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

				return false;

		}

		return true;

	}

	

	public static function getRegionBlocks($regionId)

	{

		$blocks = array();

		

		$clips = Yii::app()->controller->clips;

		

		if($clips->contains($regionId))

		{

			foreach($clips[$regionId] as $blockId => $content)

				$blocks[$blockId] = $content;

		}

		//asort($blocks);

		return $blocks;

	}

	

	public static function renderRegion($regionId)

	{

		if(self::hasRegion($regionId))

		{

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

			

			if(is_array($blocks))

			{

				self::renderRecursive($blocks);

			}

		}

	}	

	

	public static function renderRecursive($blocks)

	{

		if(is_array($blocks))

		{

			foreach($blocks as $blockId => $content)

			{

				if(is_array($content))

					self::renderRecursive($content);

				else if(is_string($content))

				{

					echo $content;

				}

			}

		}else if(is_string($blocks))

		{

			echo $blocks;

		}

	}

	

	public static function openBodyTag()

	{

		$htmlOptions = array();

		if(self::hasRegions(array('sidebar.left','sidebar.right')))

			$htmlOptions['class'] = 'sidebars';

		else if(self::hasRegion('sidebar.left'))

			$htmlOptions['class'] = 'sidebar-left';

		else if(self::hasRegion('sidebar.right'))

			$htmlOptions['class'] = 'sidebar-right';

		return CHtml::openTag('body', $htmlOptions);

	}

	

	public static function addBlock($regionId, $blockId, $content)

	{

		$clips = Yii::app()->controller->clips;

		

		if($clips->contains($regionId))

		{

			$newClips = array();

			foreach($clips[$regionId] as $key => $clip)

			{

				$newClips[$key] = $clip;

			}

			$newClips[$blockId] = $content;

			$clips[$regionId] = $newClips;

		}else{

			$clips[$regionId] = array(

				$blockId => $content,

			);

		}

	}

	

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

	{

		if(is_array($blocks))

		{

			foreach($blocks as $blockId => $content)

			{

				self::addBlock($regionId, $blockId, $content);

			}

		}

	}

	

	public static function removeRegion($regionId)

	{

		$clips = Yii::app()->controller->clips;

		

		if($clips->contains($regionId))

			$clips->remove($regionId);

	}

	

	public static function hasBlock($regionId, $blockId)

	{

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

		return array_key_exists($blockId, $blocks);

	}

	

	public static function removeBlock($regionId, $blockId)

	{

		$clips = Yii::app()->controller->clips;

		

		if($clips->contains($regionId))

		{

			$blocks = $clips[$regionId];

			foreach($block as $key => $value)

			{

				if($key == $blockId)

					unset($blocks[$key]);

			}

			Yii::app()->controller->clips[$regionId] = $blocks;

		}

	}

}



example usage: layout file,main.php




<?php

$app = Yii::app();

Layout::addBlock('header.content','main',$this->widget('core.widgets.HeaderWidget', array(), true));

Layout::addBlock('footer.content','main',$this->widget('core.widgets.FooterWidget', array(), true));

?>

<!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 $app->locale->getId(); ?>" dir="<?php echo $app->locale->getOrientation(); ?>">

<head>

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

<meta name="language" content="<?php echo $app->locale->getId(); ?>" />

<script type="text/javascript">

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

</script>

<link rel="stylesheet" type="text/css" href="<?php echo $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 $app->getBaseUrl(); ?>/css/ie.css" />

<![endif]-->

</head>


<?php echo Layout::openBodyTag(); ?>

	<div id="page-container">

		<div id="page">

		

			<!-- header container -->

			<div id="header-container">

				<div id="header">

					<?php if(Layout::hasRegion('header.top')): ?>

						<div id="header-top">

							<?php Layout::renderRegion('header.top'); ?>

						</div>

					<?php endif; ?>

					<div id="header-content">

						<?php Layout::renderRegion('header.content'); ?>

					</div>

					<?php if(Layout::hasRegion('header.bottom')): ?>

						<div id="header-bottom">

							<?php Layout::renderRegion('header.bottom'); ?>

						</div>

					<?php endif; ?>

				</div>

			</div>

			<!-- /header-container -->

			

			<!-- content-container -->

			<div id="content-container">

				<div id="content">

					<?php if(Layout::hasRegion('content.top')): ?>

						<div id="content-top">

							<?php Layout::renderRegion('content.top'); ?>

						</div>

					<?php endif?>

					<div id="content-inner">

					

						<?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; ?>

						

						<!-- canvas -->

						<div id="canvas">

							<?php if(Layout::hasRegion('canvas.top')): ?>

							<div id="canvas-top">

								<?php Layout::renderRegion('canvas.top'); ?>

							</div>

							<?php endif; ?>

							<div id="canvas-content">

								<?php echo $content; ?>

							</div>

							<?php if(Layout::hasRegion('canvas.bottom')): ?>

							<div id="canvas-bottom">

								<?php Layout::renderRegion('canvas.bottom'); ?>

							</div>

							<?php endif; ?>

						</div>

						<!-- /canvas -->

						

						<?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>

					<?php if(Layout::hasRegion('content.bottom')): ?>

						<div id="content-bottom">

							<?php Layout::renderRegion('content.bottom'); ?>

						</div>

					<?php endif; ?>

				</div>

			</div>

			<!-- /content-container -->

			

			<div id="footer-container">

				<div id="footer">

					<?php if(Layout::hasRegion('footer.top')): ?>

						<div id="footer-top">

							<?php Layout::renderRegion('footer.top'); ?>

						</div>

					<?php endif; ?>

					<div id="footer-content">

						<?php Layout::renderRegion('footer.content'); ?>

					</div>

					<?php if(Layout::hasRegion('footer.bottom')): ?>

						<div id="footer-bottom">

							<?php Layout::renderRegion('footer.bottom'); ?>

						</div>

					<?php endif; ?>

				</div>

			</div>

		</div>

	</div>

</body>

</html>



Updated Layout Helper. I will add documentation and examples soon.




<?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->_id          = $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(Util::t('The block id must be a string.'));

		}

		$this->_id = $id;

		return $this;

	}

	

	public function setContent($content)

	{

		if(!is_string($content))

		{

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

		}

		$this->_content = $content;

		return $this;

	}

	

	public function setWeight($weight)

	{

		if(!is_numeric($weight))

		{

			throw new CException(Util::t('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(Util::t('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(Util::t('The block tag name must be a string.'));

		}

		$this->_tagName = $tagName;

		return $this;

	}

	

	public function setVisible($visible)

	{

		if(!is_bool($visible))

		{

			throw new CException(Util::t('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(Util::t('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(Util::t('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(Util::t('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);

		}

	}

}



great work!

That would be lovely! :)