$anything_for_layout: Making HTML from the View available to the layout
Did you ever have a side navigation that you wanted to change based upon changes in the view? Using this helper, you can write HTML and other output for display in the layout. The output itself is written in the your view and then transfered to the layout.
This is pretty simple to use. Instead of explaining it all and it's many many varied uses and advantages, I'll just give a quick demo.
And now to put a subheader into your layout, you can just write a view like this -
Enjoy ;)
An Example
This is a quick and dirty layout:
<html>
<head>
<title><?=$title_for_layout;?>
</head>
<body>
<h2>This is a Website header</h2>
<? $layout->output($subheader_for_layout);?>
<hr>
<?php echo $content_for_layout;?>
<hr>
<h3>A footer would go here</h3>
</body>
</html>
And now to put a subheader into your layout, you can just write a view like this -
<?=$layout->blockStart('subheader');?>
<h4>This is a page Sub Heading</h4>
<?=$layout->blockEnd();?>
This would be the main content of the current page.
Enjoy ;)
The Code
Here is the complete Helper Code
<?php
/**
* LayoutHelper
* This Helper provides a few functions that can be used to assist the layout.
*
* @author Robert Conner <rtconner>
*/
class LayoutHelper extends AppHelper {
var $__blockName = null;
/**
* Start a block of output to display in layout
*
* @param string $name Will be prepended to form {$name}_for_layout variable
*/
function blockStart($name) {
if(empty($name))
trigger_error('LayoutHelper::blockStart - name is a required parameter');
if(!is_null($this->__blockName))
trigger_error('LayoutHelper::blockStart - Blocks cannot overlap');
$this->__blockName = $name;
ob_start();
return null;
}
/**
* Ends a block of output to display in layout
*/
function blockEnd() {
$buffer = @ob_get_contents();
@ob_end_clean();
$out = $buffer;
$view =& ClassRegistry::getObject('view');
$view->viewVars[$this->__blockName.'_for_layout'] = $out;
$this->__blockName = null;
}
/**
* Output a variable only if it exists. If it does not exist you may optionally pass
* in a second parameter to use as a default value.
*
* @param mixed $variable Data to ourput
* @param mixed $defaul Value to output if first paramter does not exist
*/
function output(&$var, $default=null) {
if(!isset($var) or $var==null) {
if(!is_null($default))
echo $default;
} else
echo $var;
}
}
?>

<?php
/**
* Ends a block of output to display in layout
*
* @modified sends buffer to wrapper
*/
function blockEnd() {
$this->forLayout($this->__blockName, @ob_get_clean());
$this->__blockName = null;
}
/**
* Wrapper to save to current view's viewVars array
*
* @param string $name Will be prepended to form {$name}_for_layout variable
* @param string $data Content of variable
* @return void
* @author Philip Blyth
*/
function forLayout($name, $data='')
{
$view =& ClassRegistry::getObject('view');
$view->viewVars[$name.'_for_layout'] = $data;
}
?>
That way, you can use, for ex.:
<?php $layout->forLayout('banner', $this->element('banner', array('section' => 'signup'))) ?>to capture the output of a function without having to make a block.Also, i modified the output function to make it return instead of echo, and created a wrapper for it that echoes.
That ok?
I had a question about the new adjustment you made.
I'm new to cakephp. And I was wondering if you could explain a little bit more on how I can implement this helper in my project.
Could you give a concrete example on how to implement ?
For starters where do I put this piece of code :
forLayout('banner', $this->element('banner', array('section' => 'signup'))) ?>in my controller or view.
And is this below the whole code for the helper or just the changes you made to the first post ?
[quote]
forLayout($this->__blockName, @ob_get_clean());
[end quote]$this->__blockName = null;
}
/**
* Wrapper to save to current view's viewVars array
*
* @param string $name Will be prepended to form {$name}_for_layout variable
* @param string $data Content of variable
* @return void
* @author Philip Blyth
*/
function forLayout($name, $data='')
{
$view =& ClassRegistry::getObject('view');
$view->viewVars[$name.'_for_layout'] = $data;
}
?>
Thanks a lot in advance!
View Template:
And also the View parent class could hold the default values for each sub-view. So if sideBar() is not defined in NewsView for example, it would use the default function set in the parent class View<?php
class NewsView extends View {
function main_content_for_layout() {
//main content put here
}
function sideBar_content_for_layout() {
//side bar content put here
}
//etc
}
?>
Maybe someone could make a helper that does this?
The solution I came with is this:
Make Helpers.... think of them as display modules. so for example I made this helper:
class AdvertHelper extends AppHelperAdvert text here! ");
{
function verticalAd()
{
return $this->output("
}
}
I can then use it on the layout as thus:
blah blah html
verticalAd(); ?> blah blah html
Remember to add the helper to the Controller(s) (if you need this in the index page, you need to make a copy of the "pages_controller.php" from the cake library and add the helper there too):
var $helps = array(....., 'Advert');
You can make as many 'modules' (helpers) as you want, group the output functions in whichever 'modules' you want, and they can even take parameters and contain logic like whether it should show or not.
This should definitely be included in the core, it's surely a common thing to want to do.
In the end I have coded something that does the job in my application, but it's not as modular as your code which is a shame. Hopefully I will migrate to 1.2 at some point, but since I use cake for my work, there's not enough documentation right now for me to take that step yet - I'm not brave enough lol
peace to you,
dan :-)
class LayoutHelper extends Helper {
instead of:
class LayoutHelper extends AppHelper {
Having made this change, it runs wihtrout error, but nothing is output to my view. I am right in thinking that I use the:
=$layout->blockStart('subheader');?> etc
code in my views?
Any help greatly appreciated,
dan :-)
Sorry, his really hasn't been tested outside my system and setup and version of PHP. I haven't a clue how it will work on PHP4 or cake 1.1.
So.. to clarify,
- this code assumes you have the Output Controll lib installed (http://us.php.net/manual/en/ref.outcontrol.php)
- I am pretty sure $layout->output() will only work with PHP5.
- Also I am fairly sure this only works with cake 1.2
You dont need to use the output function, its just handy in case the ${blah}_for_layout varaible you are using does not exist.
Hope this helps.
-Rob
Just set any variable with the suffix "_for_layout".
eg: $this->set('anything_for_layout','1234');
Also - the $title_for_layout can be modified within a controller by modifying the $pageTitle variable.
eg: var $pageTitle = 'This Controller';
eg: $this->pageTitle.= ' | This Action';