This is a continuation of our basic tutorial on MVC Framework. In this section, we will be creating the template files for both the TBS and the Smarty template engines.
The recap
In part one, we have created application controllers, models, and the one and only lone View class. Once again, please allow me to present few segments of those Classes here.
Main Controller We will use this as our example. All of our application controllers have the method called index(). If we can recall from part one, we made the parent controller as an abstract class with an abstract method called index(). Remember? By doing so, all of our application controllers must have a method with the same name as the abstract method of the parent. As I have already mentioned that the only reason in doing this is to serve like a training wheel. We don't want our application to wonder off the patterns that we want our application to take.
public function index(){
$this->view->use_tbs($this->main_model->Content(),FileHelper::parse_menu(),'index',FALSE);
$this->view->use_smarty($this->main_model->Content(),null,'index',FALSE);
}
Let us take those two items inside the method index() above. They may appear odd and with no to little relevance to unsuspecting eyes, but those two lines of codes are the logic carriers/converters. In other words, after the model or other methods in the controllers performed all of their business logic responsibilities, the resultants or the products of those processes must be delivered to the view. The view will then take these products and process it to become a part of what we all know as presentation logic. Isn't it this is the ultimate goal of web develpment and all we want is to deliver the response to the users? When I was in 11th grade, I don't even know the proper terminologies for these type of logic, but I was fully aware about the importance of separating these two.
Simple Elaboration with retrace
Let's retrace this particular line of codes. Please do not underestimate the importance of this. This is the only star gate between our application and the outside world. Of course, the simpleMvc class is the landing area, but the point where the business logic is transform into presentation logic is triggered here. If you watched the Sci-Fi movie entitled Star Gate, this system kind of work like that. First you need to dial the access codes (router), and then if the codes are valid the vortex will open up (landing page), and then you will be sucked and converted into pexilized form ( controllers and model), and finally you will be reassembled to your orignal form as you arrived to your final destination ( View and Template engine).
$this->view->use_tbs($this->main_model->Content(),FileHelper::parse_menu(),'index',FALSE);
This is the instance of our View class
$this->view
This is the instance of our view class utilizing its method to use TBS template engine
$this->view->use_tbs
These are the arguments for the method use_tbs().
($this->main_model->Content(),FileHelper::parse_menu(),'index',FALSE);
The data output from the Business logic of the main model are introduced to the View model in this form
$this->main_model->Content()
We added another data from our application helper class called FileHelper.
FileHelper::parse_menu()
We provide the template file name to where data can be viewed by the users as a response to their requests.
'index'
and this one, is a switch if we want our template file to be cached or not.
FALSE
Template files for TBS and Smarty
First, we create our header template file. I would like to remind you that this is the very basics of implmenting template engine and I choose not to fully cover the subjects about template inhiretance.
Filename: header.tpl Remember in our Set Class? We assigned the template extensions as .tpl.
<!DOCTYPE HTML>
<html>
<head>
<title></title>
<script type="text/javascript" src="http://localhost/tinymce/tinymce.min.js"></script>
<script type="text/javascript">
tinymce.init({
selector: "textarea"
});
</script>
<link href="http://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
<link href="http://localhost/mvctheme/css/style.css" rel="stylesheet">
</head>
<body>
very typical and pretty much nothing in it but the TinyMCE. Lets create the footer
<br/>
<div class="copy">
{% content.copyright %}
</div>
<br/>
</body>
</html>
Wow look at that, we now have something. I want you to focus on this type of syntax
{% content.copyright %}
All data from the view are derived from either the controller or the model and the View class assigned them into an array. In this particular example, the view use_tbs() method merged all the data into a single array called content. Let's take a look at the code segment from the View class
$this->tbs->MergeBlock('content',$data);
The same argument was use in the use_smarty assign method.. please take a look the codes below.
$this->smarty->assign('content', $data);
$this->smarty->assign('menu',FileHelper::parse_menu());
The only difference between the smarty and the TBS is that in Smarty, I we can call the assign method anywhere where an instance of of Smarty object is present. While in TBS, you will need to follow a simple convention like this
$data[] = $someArray();
To better understand how the template engine use the merged function or assign function, let's pretend we are writing the application in procedural form. The above codes is pretty much or closely equivalent to this.
$content = array('data'=>array(
'copyright'=>$copyright,
'title'=>$title,
'content'=>$content
));
So, don't be confused with all of these derivatives that are thrown into the mixed. What we should be thankful and must appreciate is the ability to write our arrays in DOT ( dot) notation. e.g. content.copyright gives us the copyright value.
I hope I breakdown pretty much all of the introductory parts an pieces of our application as it applies to the template engine. Let us move on to the index.tpl for both TBS and Smarty.
TBS Index.tpl file
{% onload;file=header.tpl %}
<div class="content">
<h2> This is index.tpl file generated by TBS</h2>
Article Count: {% content.# %}
<div>
<h3 class="title"><a class="title" href="{% content.url %}">{% content.title;block=div %}</a></h3>
{% content.content %}
{% content.poster %}
</div>
<br/>
{% onload;file=footer.tpl %}
Smarty index.tpl file
{% include file="mvctheme/theme/header.tpl" menu=$menu show="false" %}
<div class="content">
<h2> This is index.tpl file generated by Smarty</h2>
<ul >
{% section name=item loop=$content %}
<li>
<h3 class="title"><a class="title" href="{% $content[item].url|replace:' ':'' %}">{% $content[item].title %}</a></h3>
{% $content[item].content %}... <a class="more" href="{% $content[item].url|replace:' ':'' %}">read more</a>
<br/>
Posted by: {% $content[item].poster %}
</li>
{% /section %}
{% *onload;file=footer.tpl* %}
Let us take a look at the template files called index.tpl above. Notice how pretty it is? I mean common now, everyone could not disagree with me on how pretty the template file above. It is so pretty and safe from all types of harms and danger. I can literally delete this and I have no problem rewritting it. There is nothing in it that cannot be rewrite. However, try doing it on your controller file or the model file.
Now, let us talk about the presented codes above. Not the HTML tags, but the TBS syntax.
In TBS, this is how we include other template files. We are including the header.tpl file and the footer.tpl
{% onload;file=header.tpl %}
<!-- The rest of the codes here -->
{% onload;file=footer.tpl %}
In Smarty, this is how we include other template files. It will function and work as the above
{% include file="mvctheme/theme/header.tpl" menu=$menu show="false" %}
<!-- The rest of the codes here -->
{% include file="mvctheme/theme/footer.tpl" %}
What is ever worth mentioning between these two template engine is the ability of Smarty to add an argument that needs to be evaluated in the included template file. I could discuss more about this topic, but it will confuse the readers. So, let us set those possible divergence aside for now.
Remember the data array assigned as content on the tbs instance of the View? Here they are;
TBS iteration of the content array
{% content.title;block=div %}
Don't make the code confuse you. It all means is that show the title from the content array and loop the content array inside the div. Please take a look at our index.tpl above. Noticed that all of the items affixed with content are inside the div? So, if want this iteration to happen inside the <li>, what should we put in the block value? block=li, you said? Perfect, now you are getting into this template engine thing.
Smarty iteration of the content array
<ul >
{% section name=item loop=$content %}
<li>
<h3 class="title"><a class="title" href="{% $content[item].url|replace:' ':'' %}">{% $content[item].title %}</a></h3>
{% $content[item].content %}... <a class="more" href="{% $content[item].url|replace:' ':'' %}">read more</a>
<br/>
Posted by: {% $content[item].poster %}
</li>
{% /section %}
In smarty, we can loop an array in many different ways. One is using the section iteration function. First I created a section and define the name and define which array it has to loop. The above codes is a perfect demonstration of how the dot notation can be very useful. Raw PHP just don't have the function that will allow us to use dot notation in handling arrays. I also added a demonstration on how to use string manipulation function in Smarty e.g. replace:' ':'' which is nothing but intended to function like trim(). We can also use foreach in Smarty, if that is the function offering the most convinience for the project at hand. However, we can use the section in simple or multi-dimensional array. For more complex application, I strongly recommends the use of the section function. But if you are going to insert any iteration control or arguments before the end of the loop, you should use foreach function instead, because it is a lot easier to interupt the iteration in foreach loop.
In part One, I mentioned that I might add another templating function that will use plain PHP. I guess I am not too lazy today, so let's do it. As we all know, template engine is pretty much the most criticized innovation in Web develpment. Some says, PHP is already a template engine itself and does not need any type of template engine that suck the life of your server. So, if you are one of those people who thinks PHP is still in the same category as a lower level programming language of the past, here is a sample of using the raw PHP as a template engine.
Remember in part one, where I said that I am using the article class as a demonstration for bypassing the model pattern? Let's use the very same class in demonstrating how to use PHP as a template engine. First we need to make adjustments on the article class.
modified article controller class. This time we will be using the model pattern, but we are not going to use any template engine ONLY PHP.
class Article extends Controller{
public function __construct(){
parent::__construct();
$this->article_model = Init_Object::get_Object('Article_Model');
}
public function index(){
$ar_data = $this->article_model->content();
return($this->view->set_content($ar_data,$this->settings['no_tbs']));
}
}
Noticed, there are no instances of view->use_tbs and view->use_smarty? Instead, this particular controller will be accessing the output from the Article model and then pass it on to the view class, and lastly assigned the output to a PHP file named simplemvc_view.php. If you are going to experiment with this kind of approach, make sure the php template file must be assigned for every controller that you will have to make.
simplemvc_view.php was also defined in our class set as. I am aware that I made a typo on part one and listed it as mvcthem/simplemvc_vew.
'no_tbs' => 'mvctheme/simplemvc_view',
Here are the codes for the above template file
<!DOCTYPE HTML>
<html>
<head>
<title></title>
<script type="text/javascript" src="http://localhost/tinymce/tinymce.min.js"></script>
<script type="text/javascript">
tinymce.init({
selector: "textarea"
});
</script>
<link href="http://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
<link href="http://localhost/mvctheme/css/style.css" rel="stylesheet">
</head>
<body>
<div class="content">
<h2> This is mvctheme/simplemvc_view.php file generated by PHP serving as a template file</h2>
<ul>
<?php
foreach($content as $item){
echo '<h3 class="title"><a class="title" href="../'.(trim($item['url'])).'">'.$item['title'].'</a></h3>';
echo $item['content'].'... <a class="more" href="../'.(trim($item['url'])).'">read more</a><br/>';
echo 'Poster : '.$item['poster'].'<br/>';
}
//print_r($content);
unset($content);
?>
</ul>
</div>
</body>
</html>
That's pretty much about templating for our simple MVC. You can always do it with the options you are the most comfortable with.
Below is the screenshots of how the finished framework output will look like
The mainpage will all look the same on all three template files, except for the message describing which template engine is generating the file. For the article controller above the url can be accessed as localhost/simplemvc.php/article/. Url for both Smarty and TBS localhost/simplemvc.php/.
The output of the add controller localhost/simplemvc.php/add/. This page will allow you to add an article and save it as a text file. I also added the TinyMCE to make it look interesting
Lastly, this is the output of our read controller. The url is localhost/simplemvc.php/read/
Special thanks and credits for the CSS and others: Dynamic drive for the top menu and TinyMCE for the textarea WYSIWYG.
How to set for the framework to use the Smarty Engine?
/* select template engine to use */
'use_template' => TRUE, // always set to true
'use_smarty'=> TRUE,
'use_tbs_eng'=> FALSE,
'use_twig'=>FALSE,
For TBS, just set use_smarty to FALSE adn use_tbs_eng to TRUE, BUT never TRUE on BOTH.
I hope this tutorial have provided you something valuable. If not, my sincere apology for the lost of your valuable time.
Which Framework Should I use?
After becoming an expert with the operation of MVC pattern in PHP, and you are now looking for what open source PHP MVC framework to use. My answer to this question is simple. Try starting with CI and try creating a simple application similar to the ones we created in this tutorial. Once you finished and tested your application written in CI, jumped into the new framework. Something that is different than the rest of all frameworks. Frameworks that are created by people who are dedicated to solve problems using the latest innovations. I mean, people who can think outside the box and can view the outside the box environment as not a violation of the so called "Why reinvent the wheel" doctrine. Most people have a complete different interpretation of this term. They assumed that we should follow a certain line blindfolded. To me this is just a reason for stopping the younger generations to innovate. They don't have that same crapola when Mr. Jobs and Mr. Gates were growing up. Only in my generation where people would tell me that I cannot do this and do other things that I think can solve something. Overtime, people have begun to think like they are computers, but this is a really bad evolution inside the human brains. Computer are not smart, they are just fast and can do things redundantly with amazing speed.
To make this paragraph short, try looking at the Laravel, Kohana, and FuelPHP.
Which Framework I like
I like all of them, but there are three frameworks that I really like the most.
1. CI
2. Kohana and Symfony2
3. FuelPHP
I listed FuelPHP as the third framework that I like. However, if I will be writting a new application today based on PHP MVC Framework, I will definitely build it on FuelPHP.
What makes FuelPHP the right choice?
1. It is pretty light
2. It was developed by some people who contributed in the develpment of the early CI
3. It is so easy to create a new application throught the use of Oil CLI.
4. It has an excellent migration.
5. Oil can generate all the basic files needed for your new application.
The most important About FuelPHP is that it is one of the only two frameworks that are HMVC (Hierarchical model–view–controller ). So, if you want to run ahead of many people, this is the one you need to learn. The other HMVC framework is Kohana. Both have a really good ORM, but I am heavily leaning towards FuelPHP. I always love being with the underdog.
How does the regular MVC framework compared to HMVC?
The answer is simple. If you think CI can still compete with other well maintained frameworks, inspite of inability of its founder to provide upgrade, CI will look like a Dinasour compared to HMVC like the FuelPHP.
Things I don't Like About Framework?
I don't like the autoloader. The reason I don't like the autoloading is that the application needs to include all of the files at once. So in other words , even if your application is at idle, it has to include all of the files for the application. What I have been experimenting in the past is a reponsible loading as requested.
Here is the code I been using for experimenting the responsible loading of the controller and model files. Let say we have three controller and model files called main, read, and add. Now, I don't want these files to be included by the bootstrap at all times, even when they are not needed.
We create a simple array for all the controllers and models for our application. We just add them as we write them
$app_files = array(
'MainController'=>'index',
'ReadController'=>'read',
'AddController'=>'add',
'MainModel'=>'index',
'ReadModel'=>'read',
'AddModel'=>'add'
);
We can now use a simple router to find if the user requests have an existing controller. Can be simple as this
$controller = Route::route();
if(in_array($controller, $app_files) !== false){
$LoadController = Use_Class::loadController($controller,$pagesArray);
## we include the controller file
Use_Class::autoload($LoadController[0]);
## we create an instance or object of the controller.
## the instance for the view and the model are created inside the controller.
$object = Ini_object::instance($LoadController[1]);
$object->index();
}
By using the above approach, the application will only be carrying the load of system controller, model, and maybe a few libraries. That is a lot of relief that carrying the entire system and application files.
That will conclude my tutorial series on the basics of MVC Framework. I will attached the Zip file for this tutorial sometime later. I was not able to create the zipped file.
Thanks for reading and make sure to come back and check for the zip file later.