Skip to content

Extending Controller with masterpage template funtionality

World Wide Web Server edited this page Jul 4, 2012 · 11 revisions

Category:Library::Controller | Category:Library::Community [h3]Introduction[/h3] 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.

[h3]Requirements[/h3] CodeIgniter 1.6.x PHP 5

[h3]Installation[/h3] Create a MY_Controller.php, insert the class that follows and store it in [b]APPPATH/libraries/[/b] folder

[code] <?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){
    $this->load->library('pathfinder');
    //$this->pathfinder->addTrail((string)$this->title, site_url($this->uri->uri_string()));

    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, $data, TRUE);
            
            //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&#40;$file, $custom_url=false&#41;{
    
    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&#40;$file, $custom_url=false&#41;{
    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 &#40;module&#41; 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, $params, TRUE);
    
    return true;
}

/**
 * Marks the begining of inline scripting.
 * Example:
 *     &lt;?php ....
 *
 *             $this->_start_inline_scripting();
 *     ?&gt;
 *     [removed] .... [removed]
 *  &lt;?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);
}

} ?> [/code]

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

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

<?php echo $output; ?>
<?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; // } ?>

</body> </html> [/code]

[h3]Example[/h3]

A controller should look like this: [code] <?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");
  }

} ?> [/code]

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.

Clone this wiki locally