Part of the EllisLab Network
   
1 of 2
1
layouts?
Posted: 03 August 2007 06:20 PM   [ Ignore ]  
Summer Student
Total Posts:  4
Joined  06-28-2007

hi all—

i’m a newbie to CI, coming back to PHP after an extensive time in Rails.

with my first project, I was looking for how to handle layouts.  Again, coming from Rails, there’s usually a layout file, and individual views are set to use a particular layout.

just asking…..

thanks

Profile
 
 
Posted: 03 August 2007 09:37 PM   [ Ignore ]   [ # 1 ]  
Lab Technician
Avatar
RankRankRankRank
Total Posts:  1092
Joined  08-06-2006

http://codeigniter.com/wiki/FAQ/

 Signature 

peeker email (imap/pop) | site_migrate | OOCalendar | PhotoBox2 | word_limiter

Profile
 
 
Posted: 04 August 2007 02:25 AM   [ Ignore ]   [ # 2 ]  
Lab Technician
Avatar
RankRankRankRank
Total Posts:  2280
Joined  07-30-2007

In Ruby you have a parent layout that controls the entire page - then a particular segment of the page is loaded via the yield variable.

This is possible within CI - but the default action is to have one view for each controller (although you can load multiple views from within that first view).

Personally, I create a global directory to include my header and footer, and then include those 2 views from within all of my other views - but it really depends on personal preference.

Take a look through the documentation - as well as these forums and the wiki - there have been countless discussions, and libraries, developed to support these features.

 Signature 

Follow me on twitter here.
MichaelWales.com | MichaelWales.info

Profile
 
 
Posted: 04 August 2007 03:19 AM   [ Ignore ]   [ # 3 ]  
Lab Assistant
RankRank
Total Posts:  234
Joined  03-12-2007

I wrote a hook that pretty much mimics RoR behavior.

In your config/hooks.php add:

$hook['display_override'][] = array('class'    => 'Yield',
                                    
'function' => 'doYield',
                                    
'filename' => 'Yield.php',
                                    
'filepath' => 'hooks'
                                   
); 

Create a file named application/hooks/Yield.php:

<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Yield  ::  HOOKS
 *
 * Adds layout support :: Similar to RoR <%= yield =>
 * '{yield}' will be replaced with all output generated by the controller/view.
*/
class Yield
{
  
function doYield()
  
{
    
global $OUT;
  
    
$CI =& get_instance();
    
$output $CI->output->get_output();
    
    if (isset(
$CI->layout))
    
{
      
if (!preg_match('/(.+).php$/'$CI->layout))
      
{
        $CI
->layout .= '.php';
      
}

      $requested 
BASEPATH 'application/views/layouts/' $CI->layout;
      
$default BASEPATH 'application/views/layouts/default.php';
      
      if (
file_exists($requested))
      
{
        $layout 
$CI->load->file($requestedtrue);
        
$view str_replace("{yield}"$output$layout);
      
}
      
else
      
{
        $layout 
$CI->load->file($defaulttrue);
        
$view str_replace("{yield}"$output$layout);
      
}
    }
    
else
    
{
      $view 
$output;
    
}
    
    $OUT
->_display($view);
  
}
}  

?> 

Create a folder in views named layouts.  In this folder create a file name default.php ... this will serve as your default layout if none is specified in a controller.  To add another layout, just create a file in views/layouts and define the variable in your controller.  For example if you had a file named views/layouts/example.php and a controller named controllers/example.php:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<
html>
  <
head>
    <
meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <
title>Example.php</title>
  </
head>
  <
body>
{yield}
  
</body>
</
html
<?php

class Example extends Controller
{
  
public $layout 'example';
  
  public function 
__construct()
  {
    parent
::Controller();
  
}

  
public function index()
  
{
    $this
->load->view('index_view');
  
}

The string {yield} in your layout file will be replaced with the output generated by the view file loaded from the controller.  Not as easy as with Rails, but the behavior is there for the most part.  BTW, if the variable $layout is not defined in your controller, CI will do its default behavior… so you can use layouts in some scenarios and not in others.

Profile
 
 
Posted: 04 August 2007 10:27 AM   [ Ignore ]   [ # 4 ]  
Summer Student
Total Posts:  4
Joined  06-28-2007

kudos to teamhurting!

that is exactly what i was looking for….. thank you

*bows to teamhurting*

Profile
 
 
Posted: 04 August 2007 01:02 PM   [ Ignore ]   [ # 5 ]  
Sr. Research Associate
Avatar
RankRankRankRankRank
Total Posts:  2774
Joined  07-27-2006

I’m close to completing a library that lets you create multiple master-templates filled with regions (or yields, have you). Then, within your controllers, you simply write to those regions. Regions are defined before hand, so your master templates don’t get cluttered with a bunch of conditional routines for each region. You can go a step beyond just defining a region and define default content and markup (xhtml and attributes).

Snippet of a master template

<h1><?$title ?></h1>
<
div id="content">
  
<?$content ?>
</div

Filling regions from the controller (ideally a controller, but could happen anywhere)

$this->template->write($title'title'); // Writes $title to the 'title' region
$this->template->write($intro'content'); // Writes $intro to 'content' region
$this->template->write_view('article'$article'content'); // Loads $article to the 'article.php' view and appends the rendered view to the 'content' region ($intro remains) 

Also possible, but not as likely useful (or recommended)

$name 'Colin';
$this->template->write($name'content''<div>', array('class' => 'name'));
/* Written to 'content' region:
  <div class="name">Colin</div>
*/ 

Then the output

$this->template->output('template'); // Loads and displays template.php (in the 'views' folder 

or, more simply

$this->template->output(); // Loads and displays master template already set in config 

The ability to override the master template on this call any time makes the front-end coding much easier, especially if you have drastically different layouts for different areas of a site.

Theres some other goodies I’m going to add before I release it (mainly message handling, where messages persist across internal redirects). I’ve used it on a few projects now and have enjoyed it.

 Signature 

Check out the Template Library
Oh yeah, I tweet, too (regarding CodeIgniter on occassion).

Profile
 
 
Posted: 05 August 2007 11:39 PM   [ Ignore ]   [ # 6 ]  
Summer Student
Total Posts:  2
Joined  08-05-2007

Kinda new to CI, but was researching this topic and ran across this thread.

Anyways, I was having troubled getting teamhurting’s Yield.php code to cooperate. I did a little rewrite that seems to be work pretty good. I thought I’d share it here incase anyone notices a problem that I might be over looking.

class Yield {
    
    
function doYield() {
        
global $OUT;
  
        
$CI =& get_instance();
        
$output $CI->output->get_output();
        
        
/* Set the default layout file */
        
$layoutFile BASEPATH 'application/views/layouts/default.php';
    
        if (isset(
$CI->layout)) {
      
            
if (!preg_match('/(.+).php$/'$CI->layout)) {
                  $CI
->layout .= '.php';
              
}
    
              $requested 
BASEPATH 'application/views/layouts/' $CI->layout;
            
            
// If theres been a request for layout and the file exists
            // replace the dafault layout file
            
if (file_exists($requested)) {
                $layoutFile 
$requested;
            
}
        
        }
        
        $layout 
$CI->load->file($layoutFiletrue);
        
$view str_replace("{yield}"$output$layout);

        
$OUT->_display($view);
    
}

Profile
 
 
Posted: 06 August 2007 02:01 AM   [ Ignore ]   [ # 7 ]  
Grad Student
Rank
Total Posts:  51
Joined  04-17-2006

You might want to give the Layout Library a try.

Profile
 
 
Posted: 06 August 2007 08:01 AM   [ Ignore ]   [ # 8 ]  
Lab Assistant
RankRank
Total Posts:  234
Joined  03-12-2007

Hey tenaciousj,

My code could probably use some cleanup wink

Just note that your rewrite changes the behavior of the doYield method in that it locks you into using layouts.  I guess this is best if you are after true RoR emulation, but it had intentionally been set it up so you could choose between both this added functionality and CI’s default behavior.  Probably more sloppy that way, but I prefer the flexibility.

Profile
 
 
Posted: 06 August 2007 11:31 AM   [ Ignore ]   [ # 9 ]  
Summer Student
Total Posts:  2
Joined  08-05-2007

Bleh, your right! Didn’t even think about that, thanks for the heads up smile

This should fix it.

class Yield {
    
    
function doYield() {
        
global $OUT;
  
        
$CI =& get_instance();
        
$output $CI->output->get_output();
        
        
/* Set the default layout file */
        
$layoutFile BASEPATH 'application/views/layouts/default.php';
    
        if (isset(
$CI->layout)) {
      
            
if (!preg_match('/(.+).php$/'$CI->layout)) {
                  $CI
->layout .= '.php';
              
}
    
              $requested 
BASEPATH 'application/views/layouts/' $CI->layout;
            
            
// If theres been a request for layout and the file exists
            // replace the dafault layout file
            
$layoutFile $requested;
        
        
}
        
        
// if our selected layout file exists load it into the view 
        // else simply load the controller view by itself
        
if (file_exists($layoutFile)) {
            $layout 
$CI->load->file($layoutFiletrue);
            
$view str_replace("{yield}"$output$layout);
        
}
        
else {
              $view 
$output;
        
}
        
        $OUT
->_display($view);
    
}

Profile
 
 
Posted: 06 August 2007 07:14 PM   [ Ignore ]   [ # 10 ]  
Lab Assistant
RankRank
Total Posts:  234
Joined  03-12-2007

Hey tenaciousj,

That will still lock you in assuming default.php exists - which it should if you are using this hook.  Take a look at the original code.  The layout functionality should only take place if $CI->layout is defined.  Otherwise, you will get CI’s default behavior.  If you wanted to add layout support to all controllers without having to explicitly define $layout, you could either use your first rewrite or place a property named $layout in Controller or a subclass of Controller from which all of your application controllers would inherit from.

Profile
 
 
Posted: 02 November 2007 08:34 AM   [ Ignore ]   [ # 11 ]  
Summer Student
Total Posts:  1
Joined  10-31-2007

I changed your code to be more practical.
if you set:

public $layout 'example'

in your controller, then example.php will be used as layout file. if no, default.php will be used. and if none of them exist, page will directly rendered.

<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Yield  ::  HOOKS
 *
 * Adds layout support :: Similar to RoR <%= yield =>
 * '{yield}' will be replaced with all output generated by the controller/view.
 */
class Yield
{
    
function doYield()
    
{
         
        
global $OUT;

        
$CI =& get_instance();
        
$output $CI->output->get_output();
        
$default BASEPATH 'application/views/layouts/default.php';

        if (isset(
$CI->layout))
        
{
            
if (!preg_match('/(.+).php$/'$CI->layout))
            
{
                $CI
->layout .= '.php';
            
}
            
            $requested 
BASEPATH 'application/views/layouts/' $CI->layout;
            
            if (
file_exists($requested))
            
{
                $layout 
$CI->load->file($requestedtrue);
                
$view str_replace("{yield}"$output$layout);
            
}
        }
        
else if (file_exists($default))
        
{
            $layout 
$CI->load->file($defaulttrue);
            
$view str_replace("{yield}"$output$layout);
        
}
        
else
        
{
            $view 
$output;
        
}
        $OUT
->_display($view);
    
}
}

?> 
Profile
 
 
Posted: 25 March 2008 10:50 AM   [ Ignore ]   [ # 12 ]  
Summer Student
Total Posts:  1
Joined  03-25-2008

This is really useful but, I think it would be better if used paths were changed by APPPATH . ‘views/layouts/’. Then, you will be able to change you application_folder to whatever you want and the hook will still work.

Profile
 
 
Posted: 10 April 2008 01:53 PM   [ Ignore ]   [ # 13 ]  
Summer Student
Total Posts:  1
Joined  04-10-2008

My Layout, sending back to the Repo. (SVN habit)

< ? if (!defined('BASEPATH')) exit('No direct script access allowed');
class 
Yielder
{
function yield()
{
/*added CI benchmark support. System/Libraries/Output.php _display replace, inherit. */
global $BM;

$CI =& get_instance();
$output = &$CI->output->final_output;

if (!
preg_match("/(.+).php$/"$CI->layout)){
$CI
->layout .= ".php";
}
/*
if you dont want to use layout, use can use this->layout = -1 definition within your controller init function
*/
if ($CI->layout != -1
{
$requested 
'application/views/layouts/' $CI->layout;
$default 'application/views/layouts/default.php';
if (!
file_exists($default)) die("Hook failed: Yealder 404 $default");
if (
file_exists($requested))
{
$layout 
$CI->load->file($requested,true);
$view $layout//almost there is no performance diff
}
else
{
$layout 
$CI->load->file($defaulttrue);
$view $layout;
}
}
else
{
$view 
$output;
}
/* inherit? */
echo $CI->output->_display($view);
//echo $view;
}
}
?> 
Profile
 
 
Posted: 19 April 2011 05:10 PM   [ Ignore ]   [ # 14 ]  
Summer Student
Total Posts:  6
Joined  04-19-2011

I am very new to php, so I am grateful for this information. I was trying to figure out how the layouts work. It is all really confusing to me. I think I get it now though,it seems to make sense to me anyway. I guess I’ll find out here in a minute. Thank you very much for this thread.

Profile
 
 
Posted: 21 June 2011 11:46 AM   [ Ignore ]   [ # 15 ]  
Summer Student
Total Posts:  1
Joined  06-21-2011

My own version is at GitHub’s Gist. Key difference between mine and the original are:

* Assumes you want a layout by default and you need to set $this->layout = FALSE to disable.
* Uses PHP’s normal execution to inject the content rather than a find/replace.
* Allows data to be passed to the layout (such as a title).
* Better documentation
* More concise code

Profile
 
 
   
1 of 2
1
 
‹‹ Database issue...      Smiley issue ››