Welcome Guest, Not a member yet? Register   Sign In
Wrapping content in layout after execution (need some opinions)
#1

[eluser]mycroes[/eluser]
I'm managing a growing application, that will probably keep on growing for another few years. In about every (controller-) function that actually outputs something I'm loading a header and a footer view. In my header I display the title (as set by $this->load->vars('title')) but that's about as dynamic as it gets. I'm also going to add breadcrumbs, but those are just a combination of controller global data + title. Occassionally I output json (javascript object notation) and maybe I'll have other content types to offer in the future that should not get wrapped.

What I want:
1 controller specific setting of title
2 ability to turn layout wrapping off

The best thing would be if I could trigger the wrapper to off-state by throwing a header like 'Content-type: text/javascript' (or whatever it should be for my content), because that would save me some duplicate lines of code.

Options I figured out this far are:
a Setting a hook to wrap when everything has happened inside the controller
b Extending a default controller (will probably do this for other uses too) with layout functionality
c Load a library, call a function in it

Things wrong with options I figured out:
a Setting a hook to wrap
Hooks are dirty. I have not read much about real life usage of hooks, but the documentation makes me want to avoid hooks. Also, I can't set hooks from controllers, so point 1 only half works (I can still set data from within the controller)

b Extending a default controller
Currently the most appealing option for me... I can create a __destruct function (class destructor, using PHP5, don't care for portability) where I wrap all current output in the header and footer, seems like it should work. Turning it on is as simple as extending a controller, turning it off controller-wide is as simple as setting a variable or not extending the controller, and of course combinations allow for easy turning on for just one function, although I could also wrap the layout code in a library, load the library from the default controller and if I don't want to extend the default controller I can load the library by hand. It would be possible to also use a constructor and there start an output buffer, close the output buffer in the desctructor and then just echo header . buffer . footer, that currently seems like total win to me. Still, I don't think there's a way to catch the header in here...

c Create a layout library
Possible, but would mostly consist of getting content, returning header . content . footer... Also would have to call this at the end of all functions that want to include header and footer, that's exactly what I'm running from (although it would take less lines).

I hope someone can shine some light on how he's done this. I've seen some posts about using templates, but most of the implementations are dirty, a.o. involving reroutes and then reimplementing part of codeigniter functionality to load the real controller. I think option b is best, but maybe someone has some good points why I shouldn't create a base controller and extend it in the way I described, other than non-portability when using constructors and destructors.
Regards,

Michael
#2

[eluser]Colin Williams[/eluser]
Your controllers can have an _output() method where you might be able to do what you are hoping to do: http://ellislab.com/codeigniter/user-gui...tml#output
#3

[eluser]mycroes[/eluser]
[quote author="Colin Williams" date="1225346478"]Your controllers can have an _output() method[/quote]
It seems _output is hopelessly broken. Seemed like a great idea to me, but the function argument seems to be empty, and whatever you echo, the output is already done... You can add this piece of code to any controller to see for yourself:

function _output($output) {
echo 'test';
}
#4

[eluser]mycroes[/eluser]
Gotten further... The issue is that output isn't properly buffered. using $this->load->view a couple of times works, using echo $this->load->view($param1, $param2, true); will not buffer the view. Clearly CI's output buffer is broken.
I'll file a bug about it, then my code should work without any further issues.
Regards,

Michael
#5

[eluser]Colin Williams[/eluser]
Clearly your specific CI codebase is broken. Just tested on fresh installs of 1.6.3 and 1.7 with 100% success. Do you have a MY_Output.php library?
#6

[eluser]SitesByJoe[/eluser]
It sounds like your creating a more complicated solution than you need.

All you're trying to do is stick some meta data in your view for the most part.

Here's what I do:

1. Make a custom config file.
2. Add some defaults for all the meta data.
3. Add the file to your autoload.php
4. In your controller, do something like this:
Code:
$data['title'] = 'My Great Page';
$data['description'] = 'The description of this great page.';
$data['keywords'] = 'My, keywords, for, this, page';
$data['sections'] = array(
  'main_content',
  'sub_content'
);
$this->load->view('my_template', $data);
5. In your view, do something like this:
Code:
<html>
  <head>
    <title><?php echo $title; ?></title>
    <meta name="description" content="<?php echo $description; ?>">
    <meta name="keywords" content="<?php echo $keywords; ?>">
  </head>
  <body>
    <?php
    foreach ($sections as $section)
    {
      $this->load->view(section);
    }
    ?>
  </body>
</html>
#7

[eluser]mycroes[/eluser]
[quote author="SitesByJoe" date="1225414760"]It sounds like your creating a more complicated solution than you need.[/quote]
I seriously don't consider your code a viable solution. Besides the fact that I very often pass data along to views, I just want to be able to use CI without these kind of hacks. Currently my code works, as long as I load views and don't echo any content. Also show_404 doesn't work, but I guess there's something strange with codeigniter going on here...

My current code:
Code:
<?php

class Layout_controller extends Controller {

        function Layout_controller() {
                parent::Controller();
                $this->enabled = true;
        }

        function Controller() {
                $this->Layout_controller();
        }

        function layout_off() {
                $this->enabled = false;
        }

        function _output($output) {
                if ($this->enabled) {
                        echo $this->load->view('layout/denc', array('content' => $output), true);
                } else {
                        echo $output;
                }
        }

}

With my code:
- I only have to extend Layout_controller (instead of Controller)
- I can use views as they were meant to be used
- I can easily disable the template ($this->layout_off())
- I can create other controllers that extend this controller (I have login_controller which requires users to login, which extends layout_controller)
- I can use $this->load->vars() to set data needed either in views or the template

The most important part for me being that I don't want to load a template by hand in every function needing it. There are only a couple of functions not needing the template (because they return json) and once I standardize my json generation I can probably do without manually disabling the template for json data too... I could actually already base it on function names, if I wanted too...

Your solution also leaves the buffer gap open... Even if the buffer was properly catching echo's, it wouldn't be possible to use with your 'template engine' unless more code is added to set up extra buffers and catch everything that is echoed...
Regards,

Michael
#8

[eluser]mycroes[/eluser]
Oh and of course you need to tell codeigniter to load layout_controller.php (or whatever you name it) because codeigniter can't find it wherever you'd put it... My solution (not really mine actually, as seen on the forums) was to create MY_Controller with require_once('layout_controller.php'); and more such lines for every other controller I create. Also the Controller() function in Layout_controller is just to have easy transition between different types of controllers... You don't want to have to replace parent::Controller() everytime you change controller classes (even if that's never).
Regards,

Michael
#9

[eluser]mycroes[/eluser]
[quote author="Colin Williams" date="1225412357"]Clearly your specific CI codebase is broken. Just tested on fresh installs of 1.6.3 and 1.7 with 100% success. Do you have a MY_Output.php library?[/quote]
I only saw your post after already responding to another post... I don't have MY_Output.php or any such thing. It's just CI behaviour. I filed a bug and someone there told me that's just how CI works... Sounds like CI is broken in that aspect... On your configuration you should see the exact same issues when using echo, just loading views does work for me...
#10

[eluser]SitesByJoe[/eluser]
Quote:I seriously don’t consider your code a viable solution. Besides the fact that I very often pass data along to views, I just want to be able to use CI without these kind of hacks.

Please explain what I'm hacking here. I just tried to post a simple example to solve a simple problem.

Quote:Currently my code works, as long as I load views and don’t echo any content. Also show_404 doesn’t work, but I guess there’s something strange with codeigniter going on here…

Sorry to bring this up again, but speaking of hacks?!? I'm not gonna argue code - I'm real impressed with the fact you can perform so many manipulations, but geez - your solution is rather verbose considering it simply adds content to a view.

Perhaps I shouldn't even be defending this, but isn't the point of code igniter to do alot with a little code?




Theme © iAndrew 2016 - Forum software by © MyBB