Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Codeigniter: Best way to structure partial views

How would you structure the below page in Codeigniter?

alt text

I thought about creating seperate controllers for each section

  1. Left nav
  2. Content nav
  3. Login name
  4. Leaderboard

Excluding the content section (as this changes depending on the link on the left nav and content nav used as a kinda sub-menu). All the other sections remain roughly the same

I thought about doing:

Class User_Profile extends Controller
{

    function index()
    {
        $this->load_controller('Left_Nav');
        $this->load_controller('Content_Nav');
        $this->load_controller('Login_Name');
        $this->load_controller('Leaderboard', 'Board');

        $this->Left_Nav->index(array('highlight_selected_page' => 'blah'));

        $this->load('User');

        $content_data = $this->User->get_profile_details();

        $this->view->load('content', $content_data);

        $this->Login_Name->index();
        $this->Board->index();
    }

}

Obviously this load_controller does not exist but this functionaility would be useful. The controller for each section gets the data required from the model and then loads the page through $this->view->load()

It could be a headache to have this code in all the left nav links like News, Users, About Us, etc.. But then again not every nav link has all those sections so I need that flexability of having the sections as a "partial view"

Can anyone suggest a better way of doing this?

like image 206
Gary Green Avatar asked Sep 09 '10 08:09

Gary Green


3 Answers

@Reinis answer probably hit the spot correctly for older versions of CI less than 2.0 however alot has changed since then, so I thought I'd answer this question with an up to date method of what I've done.

Most of it is similar to @Reinis method and also described here:http://codeigniter.com/wiki/MY_Controller_-_how_to_extend_the_CI_Controller

However here are the updates ive done:

Step 1: Create a MY_Controller.php file and store it in /application/core

Step 2: In your MY_Controller.php file put in the following contents:

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

class MY_Controller extends CI_Controller {

    function __construct()
    {
        parent::__construct();
    }

    function _output($content)
    {
        // Load the base template with output content available as $content
        $data['content'] = &$content;
        echo($this->load->view('base', $data, true));
    }

}

Step 3: Create a sample controller to base off of MY_Controller.php, in this case I will create a welcome.php controller inside of application/controllers/ with the following content:

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

class Welcome extends MY_Controller {

    function __construct()
    {
        parent::__construct();
    }

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

}

Once you have these controllers set, do the following:

Step 4: Create a base view inside of /application/views and name the file base.php, the content of the file should be similar to this:

<!DOCTYPE html>
<!--[if IE 7 ]><html lang="en" class="ie7"><![endif]-->
<!--[if IE 8 ]><html lang="en" class="ie8"><![endif]-->
<!--[if gt IE 8]><!--><html lang="en"><!--<![endif]-->
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <title></title> 
        <link rel="stylesheet" href="<?php echo base_url(); ?>stylesheets/reset.css" media="screen" />
    </head>
    <body>
        <div id="section_main">
            <div id="content">
                <?php echo $content; ?>
            </div>
        </div>
        <?php $this->load->view('shared/scripts.php'); ?>
        </div>
    </body>
</html>

Step 5: Create another view in /application/views and name this view welcome_message.php, the content of this file will be:

<h1>Welcome</h1>

Once, all this is complete, you should see the following output:

<!DOCTYPE html>
<!--[if IE 7 ]><html lang="en" class="ie7"><![endif]-->
<!--[if IE 8 ]><html lang="en" class="ie8"><![endif]-->
<!--[if gt IE 8]><!--><html lang="en"><!--<![endif]-->
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <title></title> 
        <link rel="stylesheet" href="http://somedomain.local/stylesheets/reset.css" media="screen" />
    </head>
    <body>
        <!-- BEGIN: section_main -->
        <div id="section_main">
            <div id="content">
                <h1>Welcome</h1>
            </div>
        </div>
        <!-- END: section_main -->
        <script src="/path/to/js.js"></script>
        </div>
    </body>
</html>

As you can see <h1>Welcome</h1> was put into the base template.

Resources:

  • Obviously @Reinis initial response
  • http://codeigniter.com/wiki/Extending_Controller_with_masterpage_template_funtionality

Hope this helps anyone else coming across this technique.

like image 82
alvincrespo Avatar answered Oct 19 '22 01:10

alvincrespo


I can't vouch that this is the best approach, but I create a base controller like this:

class MY_Controller extends CI_Controller {

    public $title = '';
    // The template will use this to include default.css by default
    public $styles = array('default');

    function _output($content)
    {
        // Load the base template with output content available as $content
        $data['content'] = &$content;
        $this->load->view('base', $data);
    }

}

The view called 'base' is a template (a view that includes other views):

<?php echo doctype(); ?>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <?php $this->load->view('meta'); ?>
    </head>
    <body>
        <div id="wrapper">
            <?php $this->load->view('header'); ?>

            <div id="content">
                <?php echo $content; ?>
            </div>

            <?php $this->load->view('footer'); ?>
        </div>
    </body>
</html>

What this achieves is that every controller wraps its output in the base template, and that views have valid HTML instead of opening tags in one view and closing in another. If I'd like a specific controller to use a different or no template, I could just override the magic _output() method.

An actual controller would look like this:

class Home extends MY_Controller {

    // Override the title
    public $title = 'Home';

    function __construct()
    {
        // Append a stylesheet (home.css) to the defaults
        $this->styles[] = 'home';
    }

    function index()
    {
        // The output of this view will be wrapped in the base template
        $this->load->view('home');
    }
}

Then I could use its properties in my views like this (this is the 'meta' view that populates the <head> element):

echo "<title>{$this->title}</title>";
foreach ($this->styles as $url)
    echo link_tag("styles/$url.css");

I like my approach because it respects the DRY principle and the header, footer and other elements get included just once in the code.

like image 43
slikts Avatar answered Oct 19 '22 00:10

slikts


My Template library can handle all of this. You create a single (or multiple) layout file(s) that contain the partials and a tag for where the main body content will go.

Syntax as simple as:

// Set the layout: defaults to "layout" in application/views/layout.php
$this->template->set_layout('whatever') 

// Load application/views/partials/viewname as a partial
$this->template->set_partial('partialname', 'partials/viewname');

// Call the main view: application/views/bodyviewname
$this->template->build('bodyviewname', $data); 

Simples right?

Put some of that into MY_Controller and its even easier.

like image 6
Phil Sturgeon Avatar answered Oct 19 '22 00:10

Phil Sturgeon