Thursday 20 December 2012

MVC views with include() in PHP

If you are doing your first steps with MVC (ModelViewController) in PHP and not using any framework but trying to develop your own code (probably because need to upgrade -like me- an old web application make by yourself with a not MVC logic), then let me show you how i manage the view (V) content from the controller (C) file.

In this brief example i don't entry in the "model" (M) question (ie, how to manage data from database or what else). The purpose of this article is to know how manage PIECES of HTML (the "views" of the MVC) probably with dynamic php insertions in them.

The quit of the question is the CONTROL OF THE BUFFER. I don't pretend to offer here a tutorial about the php buffer, but let me remember the main concepts for the beginners:
  • the php server, by default return to the client browser whatever you output with an echo command, for example, or whatever you include in your php files outside the tags.
  • optionally, we can indicate to php for store these returned texts in a buffer and not to send to client browser until we need. In fact the system is more sophisticated and php give the developers a collection of functions for start, retrieve, clean or return this buffer. It sounds fine, it isn't?
Said this, let me show yet my example code. We only need 2 files:

view.php

1  <h1><?= $msg ?></h1>

index.php

1  <?php
2
3      $output1 
renderView('view.php','this is HEADER');
4
5      
$output2 renderView('view.php','this is FOOTER');
6
7      
$output3 renderView('view.php','this is MAIN CONTENT');
8
9       echo 
$output1.$output3.$output2;
10
11       function 
renderView($viewname,$msg){
12            
ob_start( );
13            include(
$viewname);
14            
$render ob_get_clean( );
15            
ob_end_clean();
16            return 
$render;
17       }
18
19  
?>
Read the update of 16/07/2014 about this function renderView(), because the new version let to the views recursively include other views!

Browser output

1  <h1>this is HEADER</h1>
2  <h1>this is MAIN CONTENT</h1>
3  <h1>this is FOOTER</h1>

Analysis of this codes
  • My first goal is to build the HTML of my web application in files like the view.php where the format is truly HTML&CSS and the minimal PHP code, and manage data in the "model" or the "controller" (index.php) files (in this sense, better in the model than in the controller... remember this: fat model thin controller).
  • My second goal is to CONTROL WHEN TO SEND html to client browser (or webservice, or whatever other client), because in a real environment (not like here in this toy example) i would need to manipulate these different HTML pieces that the components of my application will generate (menus, widgets, etc.) before to join in a unique HTML raw stream for send to browser.
  • for this reason, the view.php file is almost a piece of HTML&CSS code where i can INSERT pieces of php which will replace this kind of "placeholders" just like it was a template.

    It's important to note here that the variables which will be accessible from view.php are uniquely the variables accessible within the function (or method) where we use the include() command.
  • Obviously, the most interesting part of this example is the function renderView($viewname,$msg):

    • When we call ob_start() the Output Buffer begin to store all what we return as echo or what we include outside php tags (like the content of the view.php file). 
    • With ob_get_clean() we retrieve the content stored at this moment, and also empty the buffer. 
    • And finally, with ob_end_clean() we finish the buffering, although we can use it again afterward with ob_start(), as many times as we need.
Conclusion

As you see, is very simple then to build a mini MVC logic for your web applications. Think that this control of the buffer let us for example store the output in some kind of cache (in a folder of our application) before to send to browser, for example. Or we could store some "little dynamic" pieces of HTML in this cache, or we could REUSE the same generated HTML (some widget?) in different places of the same HTML page without to generate twice. Etcetera...

I hope this mini-guide has given to you some good ideas. Please, add comments and suggestions  if you have.

Update 16/07/2014

The initial renderView() function don't let to recursively include a view render inside another view render. For solve this need i improved the function just as you read below:


1  <?php
2  
function renderView($viewname,Array $vars){
3      
// == we convert the variables passed in vars
4      // == to "real" native PHP variables
5          
if (count($vars)>0){
6              foreach(
$vars as $k=>$v){
7                  ${
$k}=$v;
8              }
9          }
10      
// == we save a copy of the content already existing
11      // == at the output buffer (for no interrump it)
12          
$existing_render ob_get_clean( );
13      
// == we begin a new output
14          
ob_start( );
15          include(
dirname(__FILE__).'/view_'.$viewname.'.php');
16      
// == we get the current output
17          
$render ob_get_clean( );    
18      
// == we re-send to output buffer the existing content
19      // == before to arrive to this function ;)
20          
ob_start( );
21          echo 
$existing_render;
22         
23          return 
$render;
24  }
25  
?>
As you can see in this version you can pass an array of variables, something like this:
  • $html = renderView('main_content', array('age'=>44));
and then you can use that passed variable inside the PHP/HTML view file usgin something like this:
  • Age: <?= $age ?> years old.

2 comments: