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

by 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:
<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;    
    }
    
}

?>

Report

More on Helpers

Advertising

Comments

  • nemoDreamer posted on 07/07/08 06:59:15 PM
    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?
    • niels posted on 05/29/11 09:54:52 PM
      Hey, I'm hoping you're still reading the forum.
      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());
          $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;
      }
      ?>
      [end quote]
      Thanks a lot in advance!
  • poppitypop posted on 06/22/08 01:56:21 AM
    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?
  • populus posted on 06/02/08 07:45:38 AM
    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.
  • nickh posted on 05/16/08 04:46:14 AM
    Very useful helper.

    This should definitely be included in the core, it's surely a common thing to want to do.
  • ste.ve posted on 03/27/08 03:11:23 PM
    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..
  • ste.ve posted on 03/27/08 03:07:25 PM
    A very nice and handy helper! Should be included in the core. Works pretty well for me in Cake 1.2 beta
  • DanBallance posted on 09/09/07 01:55:49 PM
    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 :-)
  • DanBallance posted on 09/05/07 05:03:33 AM
    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 :-)
    • rtconner posted on 09/05/07 02:45:14 PM
      @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
  • naonak posted on 08/30/07 04:48:41 AM
    You call it "Layout" but "PartialLayout" should more appropriate, no ?
    • zeroasterisk posted on 09/02/07 12:56:37 PM
      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';
login to post a comment.