views:

178

answers:

5

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?

A: 

What I've done (in Kohana 2) is have the 1 template with all the sub sections (like left menu, top header), and a single controller that populates the variables that will be replaced in the template.

Then, the variables for every sub-section can be generated by functions called in the controller itself. You can also have those functions be in a separate controller class's constructor, with every controller of yours extending that one so they're automatically ran and set as class variables for easy access.

For slightly nicer templates you can have the subsections in separate files, and the big template include them:

<?php include 'leftMenu.php'; ?>
Fanis
+1  A: 

have you considered templates? There are many decent ones available with a little searching - check the CI wiki.

templates do more or less exactly what you are after. You define one master template and "sections", and these are loaded for you each time

don't want to plug too much so this might get you started - template libraries in CI

Ross
+1  A: 

I would make a MY_Controller to take care of all this. You can top it with a layout(template)/navigation library to generate all the layouts, navigation, showing/highlighting selected menu item, loading views etc.

I'd say it's not the right way to do it, if you're using a controller for each page section. You can to make use of views and nested views for that.

rkj
+2  A: 

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"&gt;
    <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.

Reinis I.
This seems like a good option but I'm not keen on the idea of "views embedding other views" -- how does the other views get the data? I assume this would only work well when the included views have static content
Gary Green
Views are just includes, so they share the same controller (`$this`) and variables as the base template. See how I use `$this->title` in the 'meta' view, which is included by the base template. I could also have used `$content` there.
Reinis I.
I added an example of a controller specific view to the Home controller.
Reinis I.
After racking my head around the fact that `_output` is a magic Codeigniter function it looks like a niceish way of doing it. So basically if you ever wanted a new template/layout you can create another MY_New_Template and extend your new controllers to use that? I'm still not entirely convinced this a good idea of embedding other views due to that fact that you need to get DATA to pass onto each view. I thought that's what controllers are for and views shouldn't be called directly, the flow should always be Controller --> Gets data --> Passes to View, or am I missing something?
Gary Green
@Reins I've just tried this code and I'm having a bit of trouble with it. `_output` doesn't actually output anything I have to do `echo $this->output->get_output();` before I get any output. In the controller Home because of the `$this->load->view('home')` it echos it at that point and therefore it echos the content twice!
Gary Green
The views share the same context, i.e., the base template will automatically share its data with the views it calls.I'm not sure why it doesn't work for you, but I checked and I think my example code is correct.
Reinis I.
A: 

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.

Phil Sturgeon