Advertisement
PHP

How to Create a Layout Manager with CodeIgniter

by

This Premium video and companion article will teach you how to create a simple yet powerful library to handle layouts in the popular CodeIgniter Framework. The library you'll create will allow you to maximize your efficiency, save time and code, modularize your views and even your Javascript and CSS files.


Step 1 Download Required Files

For this tutorial, all you're going to need is the CodeIgniter 1.7.2 framework. You can download it from their website at codeigniter.com/downloads/


Step 2 How We'll Do This

The basic functionality of this library will be very simple. We'll take the contents of a view, render them with the appropriate data, then take the rendered content and assign it to a variable. Now, we'll render the layout itself, and replace a part of the layout with the contents of this variable. Simple, but powerful enough.

The idea is to mimic the calls to $this->load->view(). When we call this method, we pass the name (and location) of our view, and then an array of data that will be accessible from the view. Here's an example:

 
function method($url_param) 
{ 
  $this->load->view('controller_views/method_view', array('url_param' => $url_param)); 
}

The above code will take the file system/application/views/controller_views/method_view.php, pass it the url_param variable, and then send it to the browser. Here's where we come in. We will not send the content to the browser yet. Instead, we'll send it to the layout, then to the browser. But how do we do that?

The view() method we just called can be passed a third (boolean) parameter, that, if true, will return the rendered view instead of sending it to the browser. We can save that content, perform a second call to the same method, but this time call a layout file that will print this content (surrounded with all headers, sidebars and footers).


Full Screencast



Step 3 Create a New Library

We'll create this library step by step, starting from the most basic. First off, we'll create a new library in our system/application/libraries folder and call it Layouts.

If you've never created a CodeIgniter library, they're simply classes, which get loaded by a call to $this->load->library().

So, let's jump straight into the code:

 
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 
 
/** 
 * Layouts Class. PHP5 only. 
 * 
 */ 
class Layouts { 
  public function __construct() { } 
}

Let's go through each section of the code:

  1. The very first line is a coding convention of CodeIgniter, it essentially makes sure users can't directly access the file from their browsers, because CodeIgniter sets the BASEPATH constant in its index.php file.
  2. The class will be PHP 5 only. This will allow us to add method chaining to the class, which will be useful later when we work with JS and CSS includes.
  3. The class constructor has nothing for the time being. This is just the skeleton of our library.

So, what happens if we include this from a controller? Well, nothing. The class does absolutely nothing for now (not even the constructor), so nothing will happen.


Step 4 Create a Layout

We'll create a very simple layout to explain how all works.

 
<!DOCTYPE HTML> 
<html> 
<head> 
  <title>Our very first layout!</title> 
</head> 
<body> 
  <?php echo $content_for_layout; ?> 
</body> 
</html>

As you can see, this is extremely basic; it's just a title and a body. Now the important part is in the PHP code there. We echo a $content_for_layout variable. The idea is to assign the rendered content to this variable. This way, it'll get printed there, surrounded with the rest of the body, head, etc.


Step 5 Write Some Code!

Let's write some code to handle this layout:

 
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 
 
/** 
 * Layouts Class. PHP5 only. 
 * 
 */ 
class Layouts { 
   
  // Will hold a CodeIgniter instance 
  private $CI; 
   
  public function __construct()  
  { 
    $this->CI =& get_instance(); 
  } 
   
  public function view($view_name, $params = array(), $layout = 'default') 
  { 
    // Load the view's content, with the params passed 
    $view_content = $this->CI->load->view($view_name, $params, TRUE); 
 
    // Now load the layout, and pass the view we just rendered 
    $this->CI->load->view('laytous/' . $layout, array( 
      'content_for_layout' => $view_content 
    )); 
  } 
}

Let's explain what the new code looks like:

  1. We added a new private attribute to our library: $CI. From within our libraries, we can't access the CodeIgniter instance directly. The only way is to get a reference to it and access it from there. So, in our constructor (which gets called when the library is loaded), we get our CI instance, and assign it to our local private $CI attribute, so we can call it later. We need it to call the load->view() method.
  2. Now, we added a view method. The syntax is practically identical to the load->view() method. We get a view name, an array of parameters (the variables that will be visible from the view), and a layout name, which by default will be (duh) 'default'. The latter allows us to have multiple layouts in our application (maybe one for the login box without menus and stuff).
  3. Now, as we spoke earlier, we call the load->view() method, we pass the view's name, the params, and a third parameter with the value of TRUE. This ensures that we will not send the output to the browser. Instead it will be returned to us, and assigned to the variable $view_content.
  4. Finally, we load the layout file (which we will store in the system/application/views/layouts folder), and pass the content of the just loaded view as a parameter. When the layout gets loaded, the $content_for_layout variable will be replaced with the content just loaded, and will be sent to the browser (note the missing final parameter, we don't pass TRUE this time).

Step 6 Change the Title of the Page

The basic library is technically done. But there are a couple of things we can add to it to make it even better.

As it is, the title of the layout is always the same. This is not practical. We need to be able to change it easily from our controllers, without having to create an infinite ammount of layouts with different titles (this would defeat the purpose of this tutorial). So, how do we do this? We'll suppose the site has a permanent title, say "Layouts Library". After that, we would put the section of the site we're visiting. For example, for the login page, the title would read "Layouts Library | Login".

First, let's rewrite the layout a bit.

 
<!DOCTYPE HTML> 
<html> 
<head> 
  <title>Layouts Library<?php echo $title_for_layout ?></title> 
</head> 
<body> 
  <?php echo $content_for_layout; ?> 
</body> 
</html>

We just added another PHP echo. This time we print the $title_for_layout variable, which we'll tweak in our library. Here's the rewritten library:

 
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 
 
/** 
 * Layouts Class. PHP5 only. 
 * 
 */ 
class Layouts { 
   
  // Will hold a CodeIgniter instance 
  private $CI; 
   
  // Will hold a title for the page, NULL by default 
  private $title_for_layout = NULL; 
   
  // The title separator, ' | ' by default 
  private $title_separator = ' | '; 
   
  public function __construct()  
  { 
    $this->CI =& get_instance(); 
  } 
   
  public function set_title($title) 
  { 
    $this->title_for_layout = $title; 
  } 
   
  public function view($view_name, $params = array(), $layout = 'default') 
  {  
    // Handle the site's title. If NULL, don't add anything. If not, add a  
    // separator and append the title. 
    if ($this->title_for_layout !== NULL)  
    { 
      $separated_title_for_layout = $this->title_separator . $this->title_for_layout; 
    } 
     
    // Load the view's content, with the params passed 
    $view_content = $this->CI->load->view($view_name, $params, TRUE); 
 
    // Now load the layout, and pass the view we just rendered 
    $this->CI->load->view('laytous/' . $layout, array( 
      'content_for_layout' => $view_content, 
      'title_for_layout' => $separated_title_for_layout 
    )); 
  } 
}

What did we do here?

  1. We added two new attributes to our library: $title_for_layout and $title_separator. The first will hold our title, and the second, will define the string that will separate the title of the layout from the title set by the set_title() method.
  2. Since the $title_for_layout was set to private, we add a method to set it from our controllers. Thus, set_title() will set the value of $title_for_layout to whatever we tell it to, eg. 'Login'.
  3. In the view() method, we added a chunk of code to handle the new attribute. If the user never sets a title for the page, we want to be able to "degrade gracefully", ie. not append the separator for nothing. Thus, we first check the value of the $title_for_layout attribute. If not NULL, then we append the configured separator and the title set by the set_title() method.
  4. When rendering the layout, we make sure we pass the new attribute (even if NULL), so we can echo it in the title.

Step 7 Adding modular CSS and JS

Now, for last, we want to be able to add CSS and Javascript files modularly. What does this mean? Say you want to use a jQuery plugin, but you just want to use it on a single part of the website (maybe a form validation plugin). You could just include it on the view itself, but that doesn't look very good on the final code. It's always preferable to have all Javascript (and CSS) includes in the header. We're going to create a method (well, two actually) that will allow us to do just this.

Go ahead and add these two methods to your library:

 
public function add_include($path, $prepend_base_url = TRUE) 
{ 
  if ($prepend_base_url) 
  { 
    $this->CI->load->helper('url'); // Load this just to be sure 
    $this->file_includes[] = base_url() . $path; 
  } 
  else 
  { 
    $this->file_includes[] = $path; 
  } 
   
  return $this; // This allows chain-methods 
} 
 
public function print_includes() 
{ 
  // Initialize a string that will hold all includes 
  $final_includes = ''; 
   
  foreach ($this->includes as $include) 
  { 
    // Check if it's a JS or a CSS file 
    if (preg_match('/js$/', $include)) 
    { 
      // It's a JS file 
      $final_includes .= '<script type="text/javascript" src="' . $include . '"></script>'; 
    } 
    elseif (preg_match('/css$/', $include)) 
    { 
      // It's a CSS file 
      $final_includes .= '<link href="' . $include . '" rel="stylesheet" type="text/css" />'; 
    } 
     
    return $final_includes; 
  } 
}

Be sure to also add this new attribute to your class, just above the constructor:

 
private $includes = array();

and this to your layout, just after the title

 
<?php echo $this->layouts->print_includes() ?>

A little explanation:

  1. The add_include() method allows us to add multiple JS or CSS files from our controller. It even allows method chaining, meaning we can do something like $this->layouts->add_include('js/jquery.js')->add_include('js/jquery.plugin.js')->add_include('css/jquery.plugin.css'); which can be very comfortable when loading multiple things. This method chaining feature is the reason we need PHP 5, because PHP 4 doesn't support it.
  2. The $prepend_base_url parameter on the add_include() method, will by default prepend the base url of the CodeIgniter installation. By calling this method with the $prepend_base_url set to FALSE, we can include remote files (for example, the jQuery lib from Google's CDN).
  3. The print_includes() method is self-explanatory. It iterates through all the includes added with the add_include() method, checks whether the file is a Javascript or a CSS file (no other files supported), and appends the include to a string that will finally be echo'ed in the layout.

Conclusion

We've created a complete and very practical layout manager library for CodeIgniter from scratch! This will allow you to save time, avoid unnecesary calls to include headers, content, and footer all the time, and modularize your Javascript and CSS files.

This is the final code for the layout and the library:

 
<!DOCTYPE HTML> 
<html> 
<head> 
  <title>Layouts Library<?php echo $title_for_layout ?></title> 
  <?php echo $this->layouts->print_includes(); ?> 
</head> 
<body> 
  <?php echo $content_for_layout; ?> 
</body> 
</html>
 
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 
 
/** 
 * Layouts Class. PHP5 only. 
 * 
 */ 
class Layouts { 
   
  // Will hold a CodeIgniter instance 
  private $CI; 
   
  // Will hold a title for the page, NULL by default 
  private $title_for_layout = NULL; 
   
  // The title separator, ' | ' by default 
  private $title_separator = ' | '; 
   
  public function __construct()  
  { 
    $this->CI =& get_instance(); 
  } 
   
  public function set_title($title) 
  { 
    $this->title_for_layout = $title; 
  } 
   
  public function view($view_name, $params = array(), $layout = 'default') 
  {  
    // Handle the site's title. If NULL, don't add anything. If not, add a  
    // separator and append the title. 
    if ($this->title_for_layout !== NULL)  
    { 
      $separated_title_for_layout = $this->title_separator . $this->title_for_layout; 
    } 
     
    // Load the view's content, with the params passed 
    $view_content = $this->CI->load->view($view_name, $params, TRUE); 
 
    // Now load the layout, and pass the view we just rendered 
    $this->CI->load->view('laytous/' . $layout, array( 
      'content_for_layout' => $view_content, 
      'title_for_layout' => $separated_title_for_layout 
    )); 
  } 
   
  public function add_include($path, $prepend_base_url = TRUE) 
  { 
    if ($prepend_base_url) 
    { 
      $this->CI->load->helper('url'); // Load this just to be sure 
      $this->file_includes[] = base_url() . $path; 
    } 
    else 
    { 
      $this->file_includes[] = $path; 
    } 
 
    return $this; // This allows chain-methods 
  } 
 
  public function print_includes() 
  { 
    // Initialize a string that will hold all includes 
    $final_includes = ''; 
 
    foreach ($this->includes as $include) 
    { 
      // Check if it's a JS or a CSS file 
      if (preg_match('/js$/', $include)) 
      { 
        // It's a JS file 
        $final_includes .= '<script type="text/javascript" src="' . $include . '"></script>'; 
      } 
      elseif (preg_match('/css$/', $include)) 
      { 
        // It's a CSS file 
        $final_includes .= '<link href="' . $include . '" rel="stylesheet" type="text/css" />'; 
      } 
 
      return $final_includes; 
    } 
  } 
}

Be sure to watch the screencast for the full overview and commentary!

Related Posts
  • Code
    Android SDK
    Create a Music Player on Android: Project Setup0d63m preview image@2x
    The Android platform provides resources for handling media playback, which your apps can use to create an interface between the user and their music files. In this tutorial series, we will create a basic music player application for Android. The app will present a list of songs on the user device, so that the user can select songs to play. The app will also present controls for interacting with playback and will continue playing when the user moves away from the app, with a notification displayed while playback elapses.Read More…
  • Code
    Theme Development
    Custom Controls in the Theme CustomizerTheme customizer custom control 400
    In the last article, we explored the advanced controls available in the Theme Customizer, and how to implement them. We’re going to look at how to create our own custom control, allowing you to choose which Category of Posts are displayed on the home page. To get started, download version 0.6.0 of our Theme Customizer Example.Read More…
  • Code
    PHP
    Setting Up a Local Mirror for Composer Packages With SatisComposer retina preview
    Installing all your PHP libraries with Composer is a great way to save time. But larger projects automatically tested and run at each commit to your software version control (SVC) system will take a long time to install all the required packages from the Internet. You want to run your tests as soon as possible through your continuous integration (CI) system so that you have fast feedback and quick reactions on failure. In this tutorial we will set up a local mirror to proxy all your packages required in your project's composer.json file. This will make our CI work much faster, install the packages over the local network or even hosted on the same machine, and make sure we have the specific versions of the packages always available.Read More…
  • Code
    PHP
    Validation and Exception Handling: From the UI to the BackendProcedural to oop php retina preview
    Sooner or later in your programming career you will be faced with the dilemma of validation and exception handling. This was the case with me and my team also. A couple or so years ago we reached a point when we had to take architectural actions to accommodate all the exceptional cases our quite large software project needed to handle. Below is a list of practices we came to value and apply when it comes to validation and exception handling.Read More…
  • Code
    PHP
    Creating a Photo Tag Wall With Twilio Picture Messaging & PHPProcedural to oop php retina preview
    Twilio's recently announced Picture Messaging has vastly opened up what we can do with text messaging, now we can attach photos to our text messages and have them get used in different ways. In our case, we are going to build a Photo Tag Wall, which will contain photos linked to tags that will be displayed on a website.Read More…
  • Code
    Tools & Tips
    Tips to Avoid Brittle UI TestsUi test retina preview
    In the last article I talked about a few ideas and patterns, like the Page Object pattern, that help write maintainable UI tests. In this article we are going to discuss a few advanced topics that could help you write more robust tests, and troubleshoot them when they fail:Read More…