Welcome Guest, Not a member yet? Register   Sign In
Need Help with Views
#1

[eluser]robnecciai[/eluser]
Please forgive me in advance. I know that similar topics have been covered in the forum. However, I'm new to CI and I'm struggling to find a good MVC way of handling views.

I know that standard information for headers and footers can easily be handled by extending MY_Controller. As I understand it, this will allow me to manage the output of the views and add a header, footer, etc. to each and optionally pass data to them for display.

However, I am having some difficulty with the main view in that each page in my site can have varying dynamic content that must be pulled from the database (Ads, for example). Some pages have ads and some do not. Moreover, the TYPE of ads displayed on one page may be different (size, content, etc.) than the type of ads displayed on others. I'm not sure I want to know all of that detail in the controller code.

My thought is to add code to each of the "main" views that instantiate and call library functions to get the desired content. Although, I think this may violate MVC practices. The solution would be something like this...

MY_Controller would combine the following when outputting every page

[header_view.php] - fairly static, passed variables for things like "greeting name", "logged-in", etc.
[????_view.php] - the "body", or main part of the page - passed variables for the main content and calls library functions to get the rest
[footer_view.php] - same functionality as header

By the way, I have a simple "storedcontent.php" library built in CI. This library basically accesses the database to return content based on a given "key". So, the "main" view may make a call to get content like this:


<div>
&lt;?php
$this->CI =& get_instance();
$this->CI->load->library('storedcontent');
echo $this->CI->storedcontent->stored_content('TEST_CONTENT');
?&gt;
</div>

It seems that this allows a little more flexibility when designing the views...

Is this acceptable or is there a better way?

Thanks, in advance,
#2

[eluser]techgnome[/eluser]
I'd get the stored content from inside the controller... pass it to the view. Same with the ads.

At least that's how I usually write my controllers:
1) Get all the data
2) Perform additional logic
3) If necessary, get more data
4) Pass everything to the view

In the View I:
1) Load the head template
2) Load the page banner template
3) Load left side
4) Load main content based on $view_content passed from the controller
5) Load the right view (unless it's a wide view)
6) Load the footer

In your case as for the ads, you may not care about the types of ads or the ads themselves, but you should be able to retrieve them based on the view you want to display, and then simply pass along the results to the view when you load it.

Or have I over simplified it?

-tg
#3

[eluser]CroNiX[/eluser]
I believe in total separation of functionality. What that means to me, is that each controller should ONLY deal with its own specific type of logic. Like if I have a controller that is for products and has methods to add/delete/edit products, etc, I would never even deal with ads, or anything else, anywhere in that controller. Just like I would never output a header or footer directly from a controller. I only output the view generated by THAT controller, and pass it back to a master library which handles assembling all views from whatever other controllers are necessary.

Lets take your example of the ads.

In my master library (which is autoloaded), in the construct, it would get the current users id (or status or whatever). It would then call an internal library method to get the ads appropriate for that user by their level or whatever your criteria is. Now, this data is available anywhere from the library because it was autoloaded.

There is also another method in this library called generate_view($content), which would look something like this:
Code:
&lt;?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class Template
{
    private $ads = array();
    private $user = array();
    public $CI = null;

function __construct()
{
    $this->CI =& get_instance();
    $this->user = $this->load_user();  //you would have a method to get the user data via id from session
    $this->ads = $this->load_ads();  //you would have a method to get ads based on user data
}

function generate_view($content)
{
    $ads['ads'] = $this->ads();  //ads was already set in the construct of the library

    //lets generate the "ads" view and store it in an array (using 3rd parameter of TRUE to get it as a string)
    //We pass the $ads array to the ads view, and within that view it loops through the ads creating whatever is necessary for that view.  
    $data['ad_content'] = $this->CI->load->view('frontend/partials/ads', $ads, TRUE);  

    //gets header and footer...assuming there is nothing to pass to the header to create its view
    $data['header'] = $this->CI->load->view('frontend/partials/header', array(), TRUE);  
    $data['footer'] = $this->CI->load->view('frontend/partials/footer', array(), TRUE);  //gets footer

    //here we are just passing along the specific content generated by whatever controller we called this method from so we
    //can pass it to the "master template" view.
    $data['content'] = $content;

    //now output all of the "partial views" to the main template and then to the browser
    $this->CI->load->view('frontend/partials/main_template', $data);  //no 3rd parameter used here...just output it
}

}
//In your "main_template.php" file, you would have something like:
&lt;?php echo $header; ?&gt;
<div id="ads"><php echo $ads; ?&gt;</div>
<div id="content">&lt;?php echo $content; ?&gt;</div>
<div id="footer">&lt;?php echo $footer; ?&gt;</div>

//in your "ads.php" template you would have something like:
<ul>
&lt;?php foreach($ads as $ad): ?&gt;
    <li>&lt;?php echo $ad['name']; ?&gt;</li>
&lt;?php endforeach; ?&gt;
</ul>

So, if I am in my products controller, I might do something like:
Code:
....
class Products extends Controller
{
    function __construct()
    {
        parent::Controller();
    }

function get()
{
    $cat_id = (int) $this->uri->segment(3);
    $data['products'] = $this->product_model->get_products_by_cat($cat_id);

    //generate our view partial and send it to the template_library for display
    $content = $this->load->view('frontend/partials/product_display', $data, TRUE);

    $this->template_library->generate_view($content);
}

}
//now all of my classes methods are very clean and only deal with their own specific logic and everything else is done.
//Very...modularized and DRY.
#4

[eluser]robnecciai[/eluser]
Thanks guys. Your responses were very helpful. I knew that leaving such logic in the views was probably a bad idea. So, after a little redesigning, I came up with a solution that basically utilizes a single "default" view. Now, all of the logic resides inside the controller(s) and the "default" view simply acts as a template.

The critical piece that I was missing before was the ability to return the view as a string (via $this->load->view('myview', $data, TRUE). After using that, everything started to fall into place. But, like anything else, it will be refined over time.

Thanks again for your help.




Theme © iAndrew 2016 - Forum software by © MyBB