Sunday, November 8, 2009

Smarty for me

Why would you need Smarty? What can Smarty do that pure PHP can't? Why should you work with this big library and sacrifice a lot of resources? Questions that I used to ask myself before knowing a single line of smarty, before trying and knowing it well. I was convinced that it's a big waste of time, speed and resources to use Smarty in my projects. Well, I'm happy to write down my experience and answer all the questions for those of you who face the same situation.

If you're working in a team where designers work close to the programmers than Smarty is the perfect solution in order to separate the content from presentation. The designer will have a way more easier job finding exactly what they want to change and customize while the programmer will have it's own space of work, away from the unexperienced. Whatever it's done in the "presentation" part will not affect the "content". The presentation is much cleaner and easy to follow through, written in, almost, pure html.

Another perfect situation when you would chose to use it is when you deliver scripts and work with clients. Everyone may know HTML but not everyone knows PHP so how do you make such a product in order to be easy to customize and re-design? Let me guide you, use Smarty.

You're probably asking yourself what exactly does this engine do, when it operates and how. Let's suppose we have 2 files: index.php and index.tpl. In index.php you write down a lot of code queries, set variables and prepare the content to deliver to the browser. You can simply echo the content out (this of course would involve some escaping mixes of html and php blocks of code) or you can pass it to the template engine and let it deliver the presentation by replacing your assigned content with it's templated version.

index.php without smarty:
<?php
$var = 'something here inside a variable';
echo '<p>' . $var . '</p>';
?>



index.php with smarty:
<?php
$var = 'something here inside a variable';
$smarty->assign('myvar', $var);
$smarty->display('index.tpl');
?>



index.tpl:
<p>{$myvar}</p>



As you can see I've let smarty replace the keywords from inside the curly brackets with whatever I assign. The templated code is very clean and it doesn't involves escaping, apostrophes and other stuff like that in order to tell the running script which is a string, which and what should it execute, parse or simply display as a string.

I like to consider Smarty as a good bridge in my code. Exactly as a MVC framework (Model, View, Controller), Smarty plays a very important role inside a good and well organized project.

One of the most important aspects about Smarty is the way it delivers the content by building it's own pages (templates) before sending the presentation. It generates those files on the fly and uses them whenever a request is sent. If the content changes, Smarty will re-generate the templates file without further action from your part (stuff like clearing the cache, deleting the old files etc.). Inside it's templates <p>{$myvar}</p> becomes <p><?php echo $myvar; ?></p> but Smarty does the hard part of the job while you take care of the rest and enjoy working with your well organized code.

You would probably say that it's much faster to load the content from pure php without waiting for some template engine to parse and generate the files before sending them to the browser (and you're right) but keep in mind that this process runs only once (and every time you perform updates of course) as the templates will be used every time a new request will be sent. A small price to pay if you're asking me.

Smarty also supports caching which can very well be a huge advantage, used right. Imagine a page with a lot of queries and other external data, libraries, templates etc. It can be very slow or it can be very fast using the caching feature of Smarty. If the file is saved and cached, the running script won't interrogate the database in order to retrieve the dynamic content. It's already there, cached and delivered with the speed of pure HTML.

It takes seconds to install and start using Smarty. Just a little configuration and you're ready to start working with it. I use a function to call and load the templates:
<?php
function load_template ( $tags, $template_page )
{
require_once('Smarty.class.php');
$smarty = new Smarty();

$smarty->caching = 0;
$smarty->compile_check = true;
$smarty->debugging = true;

$smarty->template_dir = 'templates/';
$smarty->compile_dir = 'templates_c/';
$smarty->cache_dir = 'smarty_cache/';

$smarty->clear_all_assign ();

foreach( $tags as $assign => $value )
{
$smarty->assign($assign, $value);
}

$smarty->display ( $template_page );
}
?>



Using the above method makes it very easy for you to load the template at the end of your code. It needs 2 parameters: $tags which is an associative array where the keys are the correspondent variables inside the template ( {$myvar} where $myvar is the variable ) and $template_page which is the template you wish to use (it can be a tpl file, php file or whatever).

As an example we will get back to our index.php file and make some changes:

<?php
$dog = 'dog';
$cat = 'cat';

$tags = array
(
'dog' => $dog,
'cat' => $cat
);

load_template ( $tags, 'index.tpl' );
?>



index.tpl:

{$dog} eats {$cat}



The above code will produce: 'dog eats cat'. Very clean and easy to follow.

The examples we used above are very basic but Smarty can pass objects, variables, arrays and all sort of content. It won't limit or force you to prepare everything inside the content area. {$dog} eats {$cat} can very well be {$dog->name} eats {$cat->name} and we're in objects already or {$dog.name} eats {$cat.name} for the arrays. There are a lot of things that can be done from inside the template. For example, the designer wants to capitalize the dog's name at the header of the template and use it lower case at the footer. You will probably try to pass 2 variables like this:

$tags = array
(
'dog' => ucfirst($dog),
'dog_lower' => strtolower($dog),
'cat' => $cat
);



This is not the case. What we'll discuss from here is called "variable modifier" if you study the Smarty documentation. Keeping the same content here's the cleaner solution for our problem:
index.tpl
<!-- header -->
{$dog|ucfirst} eats {$cat}

<!-- footer -->
{$dog|strtolower} eats {$cat}



Nicely done directly from the template. You can enjoy your Hawaii trip. No need for you at the office :). Another good example being: {$content|regex_replace:"/dog/":"cat"} where all the occurrences of 'dog' will be replaced with 'cat'.

You can also assign variables directly from the template without editing the php code and having to assign it first. Here's an example:

{assign var=some_var value=$dog}



When you call {$some_var} will output the value of $dog or whatever else you decide to assign in there. Constants can be used as well:
php code:



define ( 'SOME_CONSTANT', 'some constant value' );



template code:
{$smarty.const.SOME_CONSTANT}



That's it. No hacks or special functions etc. Smarty recognizes all this stuff and won't stay in your way as it's really helping you maintain a clean and well structured code.

But that's not all. What If I want to create a 'loop'. How can smarty do that? Very easy I say. Very easy:
php code:
$array = array ( 'dogs', 'cats', 'horses', 'tigers', 'lions' );
$tags = array ( 'myArray' => $array );
load_template ( $tags, 'index.tpl' );



template code:
<ul>
{foreach from=$myArray item=value}
<li>{$value}</li>
{/foreach}
</ul>



Which will produce a nice unordered list with the array values. It's the same thing if you have keys also inside your array:
template code:
<ul>
{foreach from=$myArray item=value key=k}
<li>{$value}</li>
{/foreach}
</ul>



If you want to add a counter there's no easier way than this one that Smarty provides:
{counter start=0 print=0}
<ul>
{foreach from=$myArray item=value key=k}
<li>{counter} {$value}</li>
{/foreach}
</ul>



Where 'start' is the start position and 'print' is a boolean value where in 0/FALSE the counter won't print the first value (0) where it's defined but will start printing at the very next request, inside the loop. So instead of:

0
<ul>
<li>1 dogs</li>
<li>2 cats</li>
//etc
</ul>



we will have:
<ul>
<li>1 dogs</li>
<li>2 cats</li>
//etc
</ul>



Working with already defined functions inside the template is also a piece of cake. Just look at the following example:
php code:
function multiply ($this, $that, $other_that)
{
return ( $this * $that ) * $other_that;
}


template code:
{$this|multiply:$that:$other_that}



OR
{10|multiply:20:30}



which will output: 6000

As you probably noticed already, the first parameter that follows the opening curly bracket is the first parameter of the function followed by a '|' pipe, followed by the function name to call and followed by the rest of the function parameters separated by ':'. If the function needs no parameters you can call it this way: {''|multiply} or {''|@multiply} if you like to hide the errors (if you have any).

Filters

Yes. You can set 3 types of filters when working with Smarty: pre-filters, post-filters and output filters. I think the best way to describe their functionality is by talking about real examples.
You have a template which you created using dreamweaver's templating engine. Dreamweaver relies on some comments to build the templates but you wish to hide them from your visitors. In the same time, you wish to keep them because you might work on those templates, and dreamweaver, at other time. You can set a pre-filter (something like preg_replace) to strip down those comments and unwanted code when the template is parsed. This won't affect your template but the ones that Smarty generates inside it's compiling folder.

What if, you want to keep a small log on your templates like creation date or request ip etc. For this type of things you will need a post-filter to write those details after sending the content to the browser.

You may want to transform url's to hyperlinks or obfuscate email addresses in order to keep the spam bots away. You will need an output filter.


Plug-ins

The above discussed filters are also plug-ins that Smarty use. You can create a lot of plug-ins to change the way Smarty reads and operates. By default Smarty reads from flat files (php, html, tpl) but it can be instructed to use a database or almost any kind of source. Plug-ins allow you to create/edit variable modifiers, functions or filters (pre, post, output), perform form validations and all kinds of stuff.

I have included a working example at the end of this tutorial (look for the download section) with a very basic implementation of Smarty.

As a short conclusion I will say that Smarty definitely is a very strong tool for both programmers and designers and has the potential to highly increase your effectiveness. I strongly recommend anyone reading this tutorial to, at least, try this wonderful template engine.


No comments:

Post a Comment