Welcome Guest, Not a member yet? Register   Sign In
Efficiently re-using code
#1

[eluser]Xandrios[/eluser]
Hello,

I've just started learning CI. Aside from a few strange issues in the Database cache module things are going smooth. Worked successfully through a couple of tutorials as well. So for practice I decided to setup a small CMS-like website. And this is where I ran into problems.

Say I would like all the application pages to look the same (header, menu, side, footer), only the main content changes. And with for example on every page the weekly poll shown on the side.
Building simple pages works very well, but how would I re-use the header/footer code in a smart way? And more importantly: How would I show the Poll on each page on the side? Off course this could be solved by copying the poll-view to the view of every page, but that is ugly at the least. plus that would mean that I need to implement a database call (Got to find the poll question and choices) in each controller to be able to show the poll properly.

Is there a way to somehow create a module (ie a poll) and 'include' this on every page that I would like it to be on? And the same for header/footer data?

Thank you!
#2

[eluser]OwanH[/eluser]
Hey Xandrios,

You can try this:

Place the header, menu, side and footer code within their own views and simply embed those views within the individual page views. Then let your controllers query all the data from the db and pass it to the page views. The individual page views can pass that data on to the embedded views as well.

Now to avoid having repetitive code in your controllers I think it would be good idea to develop a library of classes that provide functions for extracting data from the db for these common views, including the sidebar poll-view. You would then load these libraries in your page controllers and call the class methods to get the data for the common page views.

Hope this helps.
#3

[eluser]Xandrios[/eluser]
Hi Owan, thank you very much for your reply.

While this would probably work, it would still involve requesting (although easier) data for the embedded views. If this has to be done in every controller of which view embeds something, even though it is not much, it feels repetitive.

I was wondering, is it not common for the view to have a reference to the model? In other words: If I create a poll-view, and a poll-model, would it be possible to load the poll-model in the poll-view? (instead of the controller). This way I could include the poll-view in every page I like, and the poll-view could request the specific data from the poll-model itself.

http://upload.xandrios.net/alt_model_idea.png

Would this be a smart solution to the issue? And would it technically be possible? I tried loading a model in a view, but this did not seem to work. However when loading the model in a controller, I was able to access it in the view...

[edit]
I was able to load a Model in a view, using this method:

$CI =& get_instance();
$CI->load->model('Test');
$data = $CI->Test->testFunction();

The documentation however says that it should also work with $this instead of $CI. Unfortunately this doesnt seem to be the case. "$this->load->model('Test');" does not work in the view. Could this be because my view does not include a class declaration?
#4

[eluser]Xandrios[/eluser]
If I would use this method, I would most probably need a loaded database class/connection in each Model. If I would call $this->load->database(); multiple times, in multiple Models/Classes...does that mean multiple database connections are opened?

Or does the loading work with references, so that wherever i load the database class the same instance (and thus the same connection) will be used/returned?

Thanks!
#5

[eluser]sophistry[/eluser]
one way is to extend the controller class and put your repetitive code in there.

so, all your controllers extend your extension instead of the controller.
#6

[eluser]Xandrios[/eluser]
That is a good one for the data gathering/prepping indeed. However it would still require to copy/paste the main layout in every view. Would it be possible to somehow also use an extendable class in the view?

A (completely different) problem I came across is when caching database queries. The caching works fine, however the removing/clearing of the cache does not work at the index page. It does work with the 'normal' pages, just not with the index.

It seems to be caused by the fact that the cache file is written to the cache directory in a different way for the index page. The '$this->db->cache_delete()' is unable to delete that specific file.

$this->db->cache_delete_all(); does seem to be able to work at first sight, however that one deletes not only the cache files, but also the parent directory! Which, at the next pagehit, shows with a nasty error.

Is this a known bug that the index cache cannot be removed? Is there a workaround? Or am I missing something on how to remive the index cache?
#7

[eluser]esra[/eluser]
[quote author="Xandrios" date="1183827038"]That is a good one for the data gathering/prepping indeed. However it would still require to copy/paste the main layout in every view. Would it be possible to somehow also use an extendable class in the view?[/quote]

Coolfactor's View library should handle what you want.

http://ellislab.com/forums/viewthread/49910/

There is a another library that I have not tried called ViewLib. You should find information about it on the wiki.
#8

[eluser]Xandrios[/eluser]
Thanks a lot Smile

viewLib seems to be a bit limiting, due to the static header/footer/sides definitions. I decided to go with Coolfactor’s Library.

To be able to simplify things I decided to extend the Coolfactor’s library. The content of this extended class could/should probably be different for each site. This is what it looks like for my test:
Code:
class Theview extends View {
    var $CI;
    var $content;
    
    function Theview(){
        parent::View();
        $this->CI = & get_instance();
    }
    
    function partReturn($view) {
        return $this->CI->load->view($view, $this->vars, TRUE);
    }
    
    function enableSideBoxes($sideboxes){
        
        //loop through boxes
        foreach ($sideboxes as $box){    
            switch($box){
                case "poll": //set data vars for poll
                    $this->CI->load->model("Pollmodel");                
                    $pollquestions = $this->CI->Pollmodel->getData();                
                    $this->CI->theview->set("pollquestions", $pollquestions);
                break;
            }
            
            //collect view data
            $output[$box] = $this->CI->theview->partReturn($box);    
        }    
        
        //pass view data to 'boxes' var, to be used in the mid-view
        $this->CI->theview->set('boxes', $output);
    }
    
    function addContent($content){
        $this->content = $content;
    }
    
    function showAll(){
        //add header
        $this->CI->theview->part('header', 'header.php');
        
        //add content
        $this->CI->theview->set('content', $this->content);
        $this->CI->theview->part('mid', 'mid.php');
        
        //add footer
        $this->CI->theview->part('footer', 'footer.php');
        
        //spit out the page
        $this->CI->theview->load('pagelayout');
    }
}

This defines a couple of things. First I added a function to complement the Coolfactor’s part() function: partReturn(). That way I am able to retrieve the data of the partial view as well. Having all data in variables is a bit more flexible. I only output the final data using the 'pageLayout' view, which simply echoes the header, mid and footer vars.

This site has a header, midsection with multiple sideboxes, a content section, and a footer. The most interesting ones are the sideboxes. I enable them by passing an array with the names of the ones I want for that specific page. The enableSideBoxes() function loads the views of each sidebox and if needed gathers some data from their Models. The output from the sideboxes is saved in the 'boxes' var.

The mid-view looks like this, and displays the sideboxes and main content:
Code:
<table border="1">
    <tr>
        <td width="100">
        
            &lt;?php foreach($boxes as $box=>$boxdata):?&gt;
                &lt;!--- &lt;?=$box?&gt; --&gt;
                &lt;?=$boxdata;?&gt;
            &lt;?php endforeach;?&gt;
        
        </td>
        <td width="600">
            &lt;?=$content?&gt;
        </td>
    </tr>
</table>

And the poll-sidebox view:
Code:
<strong>Poll</strong>
<p>
    <ul>    
    &lt;?php foreach($pollquestions as $question):?&gt;

    <li>&lt;?=$question;?&gt;</li>

    &lt;?php endforeach;?&gt;
    </ul>
</p>

Now the controller looks like this:
Code:
class News extends Controller {

    function index()
    {        
        $this->theview->enableSideBoxes(array("ad", "poll"));
        
        $this->theview->set("story1", "Hello, this is a news story!");
        $this->theview->set("story2", "And another one");
        $content = $this->theview->partReturn("news");
        
        $this->theview->addContent($content);
        $this->theview->showAll();
    }
}

It might look a bit confusing, but for every next page I only need to call the functions shown in the example controller. Which is quite easy, and allows to define how the sides should look like.




Theme © iAndrew 2016 - Forum software by © MyBB