$anything_for_layout: Making HTML from the View available to the layout

By Rob Conner (rtconner)
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.

An Example

This is a quick and dirty layout:
Download code <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 -
Download code <?=$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
Download 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;    
    }
    
}

?>

 

Comments 516

CakePHP Team Comments Author Comments
 

Comment

1 Nice helper

You call it "Layout" but "PartialLayout" should more appropriate, no ?
Posted Aug 30, 2007 by Fab
 

Comment

2 alternative

Just in case you don't need this level of control, it can be really simple to get variables in the layout.

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';
Posted Sep 2, 2007 by alan blount
 

Comment

3 Not working for me...

Hiya, I'd like to use this code, but it's not working for me as of yet. Firstly, It seems that the helper should start with:

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:

blockStart('subheader');?> etc

code in my views?

Any help greatly appreciated,

dan :-)
Posted Sep 5, 2007 by Dan Ballance
 

Comment

4 reply to Not working for me

@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
Posted Sep 5, 2007 by Rob Conner
 

Comment

5 my bad

My apologies Rob, I'm using 1.1. My mistake, sorry
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 :-)
Posted Sep 9, 2007 by Dan Ballance
 

Comment

6 Works great in 1.2 beta

A very nice and handy helper! Should be included in the core. Works pretty well for me in Cake 1.2 beta
Posted Mar 27, 2008 by Stefan Vetter
 

Comment

7 (double post)

The connection got lost, so I made a double post accidentially! How can I delete it, btw? Seems that the Bakery is missing this function..
Posted Mar 27, 2008 by Stefan Vetter
 

Comment

8 Great

Very useful helper.

This should definitely be included in the core, it's surely a common thing to want to do.
Posted May 16, 2008 by Nick H
 

Comment

9 mmm

I just started using cake this week, and I've already bumped into the problem with being able to output stuff at different locations in my layout.

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 AppHelper
{
function verticalAd()
{
return $this->output("
Advert text here!
");
}
}

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.
Posted Jun 2, 2008 by Jason Yang
 

Comment

10 cakephp should make the views classes

I propose that cake uses classes for the views, this would make even more sense. Example:

View Template:


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

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

Maybe someone could make a helper that does this?
Posted Jun 22, 2008 by Jonah Turnquist
 

Comment

11 Little improvements

Hey Rob, thanks a bunch for this helper! I hope you don't mind i post some little changes i made to make it more flexible:

<?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?
Posted Jul 7, 2008 by Philip Blyth