Part of the EllisLab Network
x
 
Create New Page
 View Previous Changes    ( Last updated by George Tavas )

Extending Controller with masterpage template funtionality

Category:Library -> Controller | Category:Library -> Community

Introduction

Since i started using the CI, I was searching a way to support master pages or master templates if you like to call it.
When a view is loading, i would like the output to be displayed at a certain position of the master page.
So i started building a library to do such a thing, when i realized that i had to write more code than before to load my template and all of its components. When i read about the output method made me to think a more efficient way to add the functionality that i wanted.
I have created a MY_Controller class that extends the common Controller class, so i have added the _output method into the MY_Controller class.
My controllers now, that have to use this template system, just extends the MY_Controller class instead of extending the Controller class.
With this way i was able to add even more common functionality for my controllers without have to write everytime a lot of code in each one of my controllers.

Requirements

CodeIgniter 1.6.x
PHP 5

Installation

Create a MY_Controller.php, insert the class that follows and store it in
APPPATH/libraries/ folder

Download

File:MY Controller 2.zip

<?php
/**
 * This library extends the default controller and adds some useful extra features.
 * Features:
 *         1. Enables the usage of master page/templates.
 *         2. Can add css and javascript files.
 *         3. Uses the _output method for controling the controllers output.
 *         4. Can load relative content with in the form of modules (views)
 */
class MY_Controller extends Controller {
    
/* Output control constants */
    
const OUTPUT_TEMPLATE 10;
    const 
OUTPUT_NORMAL 11;

    
/* Private properties */

    //the default template
    
private $template_view 'default';
    
    
//the default public folder this means that content inside this folder will be accessed directly
    //without using the routing.
    //Note!!! This folder must be enabled in the .htaccess file.
    
private $public_folder 'public/';
    
    
//the default location for the templates inside the views folder this means (views/templates/)
    
private $template_folder 'templates/';
    
    
//the default css location for the css files inside the $public_folder("public/" by default) (public/css/)
    
private $css_folder 'css/';
    
    
//the default js location for the css files inside the $public_folder("public/" by default) (public/js/)
    
private $js_folder 'js/';
    
    
//Inline scripting (Javascript)
    
private $inline_scripting '';

    private 
$modules = array(); //An array that contains the modules output.

    
private $charset ''//The page charset

    
private $title ''//The page Title

    //Media files and data
    
private $media = array('css'=>array(),
                            
'js'=>array(),
                             
//meta tags
                            
'meta'=>array(),
                             
//RDF are 3rd genreration meta tags
                            
'rdf'=>array());

    
//The requested controller
    
protected $controller '';
    
//The requested method to be called
    
protected $method        '';
    
    private 
$_output_data = array(); 

    
/**
     * The MY_Controller constructor method.
     */
    
function __construct(){
        parent
::Controller();
                
        
//Initializing the controller
        //Get the default charset from the config file.
        
$this->charset $this->config->item('charset');

        
//Set the default mode to use a template view
        
$this->_setOutputMode(self::OUTPUT_TEMPLATE);

        
//Passing as properties the controller and the method that should be called.
        
$this->controller $this->uri->rsegment(1);
        
$this->method      $this->uri->rsegment(2);
    
}

    
/**
     * CodeIgniter magic method that controls the output of a controller.
     * You can't call it directly.
     *
     * @see http://codeigniter.com/user_guide/general/controllers.html#output
     * @final this method cannot be overloaded
     * @param string $output the controller output
     * @return void
     */
    
final function _output($output){
        
switch($this->mode){
            
//Use the template
            
case self::OUTPUT_TEMPLATE:
                
$data = array(    'meta'=>$this->media['meta'],
                                
'rdf'=>$this->media['rdf'],
                                
'js'=>$this->media['js'],
                                
'css'=>$this->media['css'],
                                
'title'=>$this->title,
                                
'charset'=>$this->charset,
                                
'output'=>$output,
                                
'modules'=>(object)$this->modules,
                                
'inline_scripting'=>"[removed]" $this->inline_scripting "[removed]");
                
                
//Merge the data arrays
                
$data array_merge($data$this->_output_data);
                
                
//Load the final output
                
$out $this->load->view($this->template_folder $this->template_view$dataTRUE);
                
                
//The End
                
echo $out;
            break;
            
//or just echo output.
            
case self::OUTPUT_NORMAL:
            default:
                echo 
$output;
            break;
        
}
    }
    
    
/**
     * Pass extra data on the final output.
     *
     * @param string $paramName the parameter name.
     * @param mixed $value $the value of the parameter
     */
    
    
protected function _setOutputData($paramName$value){
        $this
->_output_data[$paramName] $value;
    
}

    
/**
     * This method sets the output mode. That the controller should use to display the content
     *
     * @access protected
     * @param int $mode One of the constants self::OUTPUT_TEMPLATE, self::OUTPUT_NORMAL
     * @return void
     */
    
protected function _setOutputMode($mode){
        $this
->mode $mode;
    
}
    
    
/**
     * Sets the template that will be used at the final output.
     *
     * @access protected
     * @param string $template
     * @return bool
     */
    
public function _template_to_use($template){
        $filepath 
APPPATH "views/"  $this->template_folder str_replace('.php','',$template) . ".php";
                
        if(!
$this->_is_file_exists($filepath)){
            show_error
("Cannot locate template file <tt>$template</tt>");
            return 
false;
        
}

        $this
->template_view $template;
        
        return 
true;
    
}

    
/**
     * Adds a Javascript file into the template.
     *
     * @access protected
     * @param string $file a js file located inside the public/js/ folder or an url.
     * @param boolean $custom_url Default FALSE. A flag to determine if the given $file is an url or just a file inside the public/js/ folder.
     * @return bool
     */
    
public function _add_js_file($file$custom_url=false){
        
        
if($custom_url===false){
            $filepath 
$this->public_folder $this->js_folder str_replace('.js','',$file) . ".js";
                    
            if(!
$this->_is_file_exists($filepath)){
                show_error
('Cannot locate javascript file <tt><a href="'.$filepath.'">'.$filepath.'</a></tt>');
                return 
false;
            
}
            
            $filepath 
base_url() . $filepath;
            
        
}else{
            $filepath 
$file;
        
}
        
        
if (array_search($filepath$this->media['js']) === false)
            
$this->media['js'][] $filepath;
        else
            return 
false;
            
        return 
true;
    
}
    
    
/**
     * Adds a CSS file into the template.
     *
     * @access protected
     * @param string $file a css file located inside the public/js/ folder or an url.
     * @param boolean $custom_url Default FALSE. A flag to determine if the given $file is an url or just a file insite the public/js/ folder.
     * @return bool
     */
    
public function _add_css_file($file$custom_url=false){
        
if(!$custom_url){
            
            $filepath 
$this->public_folder $this->css_folder str_replace('.css','',$file) . ".css";
            
            if(!
$this->_is_file_exists($filepath)){
                show_error
('Cannot locate css file: <tt><a href="'.$filepath.'">'.$filepath.'</a></tt>');
                return 
false;
            
}
            
            $filepath 
base_url() . $filepath;
        
}else{
            $filepath 
$file;
        
}

        
if(array_search($filepath$this->media['css']) === false)
            
$this->media['css'][] $filepath;
        else return 
false;
        
        return 
true;
    
}

    
/**
     * Sets the default charset
     *
     * @access protected
     * @param string $charset
     * @return void
     */
    
public function _set_chartset($charset){
        $this
->charset $charset;
    
}

    
/**
     * Sets the page title
     *
     * @access protected
     * @param string $new_title
     * @return void
     */
    
public function _set_title($new_title){
        $this
->title $new_title;
    
}

    
/**
     * Appends a string at the title text
     *
     * @access protected
     * @param string $title
     * @return void
     */
    
public function _append_title($title){
        $this
->title .= " - $title";
    
}

    
/**
     * Adds meta tags.
     *
     * @access protected
     * @param string $name the name of the meta tag
     * @param string $content the content of the mneta tag
     * @return bool
     */
    
public function _add_meta($name$content){
        
if(array_key_exists($name$this->media['meta']))
            
show_error("Duplicate usage of meta tag file <tt>$name</tt>.");

        
$this->media['meta'][$name] $content;
        return 
true;
    
}

    
/**
     * Adds RDF meta tags (3rd generation meta tags).
     *
     * @access protected
     * @param string $name the name of the meta tag
     * @param string $content the content of the mneta tag
     * @return bool
     */
    
public function _add_RDF($name$content){
        
if(array_key_exists($name$this->media['rdf']))
            
show_error("Duplicate usage of meta tag file <tt>$name</tt>.");

        
$this->media['rdf'][$name] $content;
        return 
true;
    
}

    
/**
     * Registers module positions
     *
     * @access protected
     * @param string $position_name the name of the position (no special chars or spaces are allowed)
     * @return bool
     */
    
public function _register_module_position($position_name){
        
if(array_key_exists($position_name$this->modules))
            
show_error("Module position failed because position <tt>$position_name</tt> has already been registered.");

        
//Check for illegal characters.
        
if(!preg_match("/[a-zA-Z0-9]*/"$position_name))
            
show_error("Position name <tt>$position_name</tt> contains some illegal characters. Only letters or numbers are allowed.");

        
$this->modules[$position_name] = array();

        return 
true;
    
}

    
/**
     *    Loads a view file (module) in a certain position.
     *
     * @access protected
     * @param string $position the module position
     * @param string $view_file the view file path.
     * @param array $params    the parameter to be passed in the view file.
     * @return bool
     */
    
public function _load_module($position$view_file$params = array()){
        
if(!array_key_exists($position$this->modules))
            
show_error("Module position <tt>$position</tt> hasn't ever been registered.");
        
        
$this->modules[$position][] $this->load->view($view_file$paramsTRUE);
        
        return 
true;
    
}

    
/**
     * Marks the begining of inline scripting.
     * Example:
     *     <?php ....
     *
     *             $this->_start_inline_scripting();
     *     ?>
     *     [removed] .... [removed]
     *  <?php
     *         $this->_end_inline_scripting();
     *     .....
     *!!!Note that the <scrpt*>[removed] tags will be removed!!!
     *
     */
    
public function _start_inline_scripting(){
        ob_start
();
    
}

    
/**
     * Marks the end of the inline scripting.
     */
    
public function _end_inline_scripting(){
         $s 
ob_get_clean();
         
         
$s preg_replace("/[removed]]*>/"''$s);
         
$s preg_replace("/<\/script>/"''$s);
              
         
$this->inline_scripting .= $s;
    
}
    

    
/**
     * Checks if the given file exists in the filesystem.
     *
     * @access private
     * @param string $filepath The file path, using a physical relative path
     * @return bool
     */
    
private function _is_file_exists($filepath){
        
return file_exists($filepath);
    
}
}
?> 

Create a file default.php insert the foolowing code and store it in APPPATH/views/templates/ folder:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<
html >
<
head>
    <
title><?php echo $title?></title>
    <
meta http-equiv="Content-Language" content="<?php echo isset($lang) ? $lang : 'en';?>" />
    <
meta http-equiv="Content-Type" content="text/html; charset=<?php echo $charset; ?>" />
<?php foreach($meta as $name=>$content): ?>
    
<meta name="<?php echo $name; ?>" content="<?php echo $content; ?>" />
<?php endforeach; ?>
<?php 
if(count($rdf) > 0): ?>
<!--
    <
rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ddc="http://purl.org/net/ddc#">
        <
rdf:Description rdf:about="<?php echo base_url(); ?>">
<?php foreach($rdf as $name=>$content): ?>
            
<<?php echo $name?>><?php echo $content?></<?php echo $name?>>
<?php endforeach;?>
        
</rdf:Description>
    </
rdf:RDF>
-->
<?php endif;?>
<?php 
foreach($js as $js_file): ?>
    [removed][removed]
<?php 
endforeach; ?>
<?php 
foreach ($css as $css_file): ?>
    
<link rel="stylesheet" type="text/css" href="<?php echo base_url() . $css_file; ?>" />
<?php endforeach; ?>
<?php 
if (isset($fav_icon)) :?>
    
<link rel='shortcut icon' type="image/x-icon" href='<?php echo base_url() . $fav_icon; ?>' />
<?php endif; ?>

<?php 
echo $inline_scripting ?>

</head>
<
body>
<
div>
    <
div id="main">
    
<?php echo $output?>
    
</div>
</
div>
<
div id="bottom"><?php
//If we had to display some extra modules (views). This will display all the modules that have
//loaded at the "bottom" position. But first we should propably register the postion inside
//the MY_Controller construct (or whatever) using the $this->_register_module_potion() method.
//eg: $this->_load_module("bottom", "modules/my_module_view", $data);

//    foreach ($modules->bottom as $mod ){
//        echo $mod;
//    }
?>
</div>
</
body>
</
html

Example

A controller should look like this:

<?php
class SomeController extends MY_Controller{
      
      
function __construct(){
         parent
::__construct();
         
$this->_template_to_use("my_template_file");

      
}

      
function index(){
         $this
->load->view("some_view_file");
      
}
}
?> 

As you can see here it shouldn’t change the structure or the way that you are usually writing a controller.
For more portability you can use a config file to configure the MY_Controller class in which default template will be using, or which position should register an more. it’s up to you.