Inspired by this article I started to play around a bit to integrate the Smarty template engine into the Zend Framework. My ambition was to minimize the required code in the controller actions but stay close to the given Zend_View API. I also wanted to integrate the Smarty caching feature. Here is the code I came up with.
Class location
The class file is named by my company (Travello) and is placed in the Travello directory beneath the Zend Framework library include path. Its advantage is that the class will be auto loaded in my setup.
/ Zend
/ View
/ Travello
/ View
Smarty . php
Class definition and constructor
Let's start with the class definition and the constructor part. My class Travello_View_Smarty is extending the Zend_View_Abstract class. In the constructor the parent constructor from Zend_View_Abstract is called first. After that a Smarty object is instantiated, configured and stored in a private attribute.
Please note that I use a configuration object from the object store to get the configuration data for Smarty.
class Travello_View_Smarty extends Zend_View_Abstract
{
private = false ;
public function __construct( $data = array ())
{
parent :: __construct( $data );
$config = Zend :: registry( ' config ' );
$this -> _smarty = new Smarty();
$this -> _smarty -> caching = $config -> getSetting( ' smarty ' , ' caching ' );
$this -> _smarty -> cache_lifetime = $config -> getSetting( ' smarty ' , ' cache_lifetime ' );
$this -> _smarty -> template_dir = $config -> getSetting( ' smarty ' , ' template_dir ' );
$this -> _smarty -> compile_dir = $config -> getSetting( ' smarty ' , ' compile_dir ' );
$this -> _smarty -> config_dir = $config -> getSetting( ' smarty ' , ' config_dir ' );
$this -> _smarty -> cache_dir = $config -> getSetting( ' smarty ' , ' cache_dir ' );
}
Implement _run() method
The method _run() is the only method that needs to be implemented in any subclass of Zend_View_Abstract. It is called automatically within the render() method. My implementation just uses the display() method from Smarty to generate and output the template.
___FCKpd___2
Overwrite assign() method
The next part is an overwrite of the assign() method from Zend_View_Abstract, which works in a similar way. The big difference is that the values are assigned to the Smarty object and not to the $this->_vars variables array of Zend_View_Abstract.
___FCKpd___3
Overwrite escape() method
The next part is an overwrite of the escape() method from Zend_View_Abstract. It works both for string and array values and also uses the escape() method from the Zend_View_Abstract. The advantage of this is that I don't have to care about each value of an array to get properly escaped.
___FCKpd___4
Print the output
The next method output() is a wrapper on the render() method from Zend_View_Abstract. It just sets some headers before printing the output.
___FCKpd___5
Use Smarty caching
The last two methods were created to simply integrate the Smarty caching mechanism in the View class. With the first one you can check for cached template and with the second one you can set the caching on or of.
___FCKpd___6
That was the complete code of my Travello_View_Smarty class.
How to use the class
The usage of this class is quite simple. In your bootstrap file you can initialize it like this. The $viewConfig is used to setup the Zend_View paths. After creation the object is registered in the object store for later usage.
___FCKpd___7
Within your controller an action method could look like this.
___FCKpd___8
Conclusion
That was basically it. I have a couple of ideas how to extend this solution, but it already does the work for me. Any comments are welcome.
Updated on April 18, 2006
Please have also a look at the follow-up article on Integrating Sarty and ez Components with the Zend Framework.
Comments
PHPDeveloper.org just pointed out a related article on caching using Smarty. This will fit nicely with what Ralf has written here.
currently I am using the ezcConfiguration and ezcConfigurationIniReader from the ezComponents
http://ez.no/doc/components/view/latest/(file)/introduction_Configuration.html
To integrate the ezComponents within the Zend Framework I put the ezComponents directory in my include_path and use a slightly different __autoload() function:
include_once 'Zend.php';
include_once 'Base/src/base.php';
function __autoload($class)
{
if ('ezc' == substr($class, 0, 3))
{
ezcBase::autoload($class);
}
else
{
Zend::loadClass($class);
}
}
</ pre >
To use the Configuration component I set it up and store the configuration object in the object store of the Zend Framework.
$reader = new ezcConfigurationIniReader();
$reader->init('path/to/your/ini/files', 'settings.ini');
$config = $reader->load();
Zend::register('config', $config);
</ pre >
That is basically it.
HTH, Ralf
If you redefined the Smarty Tags to "<?" and "?>" and uses Templates it allows you to see a really clean design in your design editor (there are other ways to do that, but this is quick!!). Templates also make it easy to develop huge interface changes in all your application on the fly without touching your code (the customers like that!!!) and taking advantage of the smarty cache management.
Another thing that helped me was the idea of Tom Anderson of adding a "T" block for Internationalization support. With this you, can even make your design in English and tagged all translatable text with "T" blocks and after use a Smarty-T- block plugin to support your application in different languages. I used in Japanese and I developed my own t block plug in like this:
{
if ( ! $content )
return $content ;
return i18ngettext( trim ( $content ));
}
The i18ngettext is a function that search into the localization files and returns the content with the translated phrase if it exists. I rewrite the i18ngettext in order to cached the files.
In design time text will look like:
<?t?>Translate me<?/T?>
Bye,
Hermann
For example if you created a Zend_View_Helper_MakeUrl and want to invoke it through a template:
<a href="{makeUrl('index','login')}">Login</a>
I don't think it is possible by using your approach because the helper method are unknown to the smarty object.
In my code is assigned a Zend_View Object that includes all output variables to the smarty object by doing:
$view -> template = ' index.html ' ;
// add other output variables in the actioncontroller
$smarty = new Smarty();
// smarty cfg stuff
//at the end of the script
$smarty -> assign( ' view ' , $view );
$smarty -> display( $view -> template);
By doing this, smarty will automatically invoke the Zend_View::__call() method to unknown funktions, and that invokes the helper methods. the disadvantage is that you have to use:
<a href="{$view->makeUrl('index','login')}">Login</a>
which is a little more code, but it works for me.
One more Question: Did anyone manage to make TemplateLite (former SmartyLite) working with ZF?
regards, Marc
thanks for your comments on internationalization. Sounds very good to me. For myself, I haven't come to that part yet, but your approach sounds reasonable to me.
Until now what I did was to assign an array called "translate" to Smarty and to access the translation via {$template.to_be_translate}.
Best Regards,
Ralf
you could easily assign the View object to Smarty as well by doing something like this in the _run() method:
{
$this -> _smarty -> assign( ' view ' , $this );
$this -> _smarty -> display( $template );
}
But I haven't tested this yet, so I might be wrong.
Best Regards,
Ralf
I just wanted to drop a comment to tell you how much I appreciate this tutorial. I was in the process of starting a new project, and wanted to use a more stuctured approach. I was all ready using smarty without the Zend framework.
I knew I wanted to use the framework in my new project, but also wanted to use smarty. Your tutorial was the deciding factor in my changing to the Zend Framework. After spending most of yesterday downloading, and installing Apache I was able to get it working. (After spending a few hours learning how th configure Apache. Oh well, the burden of running your own server.)
Anyway, thanks again.
Troy
However, I have made just 4 methods in my class:
three that you have mentioned (__construct, assign, _run) and also _script() - to avoid redundant Zend_Exception:
* Overrides parent's method.
* @param $name string The base name of the script.
* @return void
*/
protected function _script( $name )
{
return $name ;
}
The main issue in your code (IMHO) is the following: you are extending the Zend_View_Abstract interface by adding several new methods that are not present in the abstract class. This cannot be considered a problem until one day you decide that Smarty is no good - and you should fall back to using Zend_View instead.
Then you can extend the Zend_View and make Torello_View_Zend class with stub methods, and that will be ok - but I think you should mention this in your article.
"Uncaught exception 'Zend_Exception' with message 'File "Zend/View/Helper/run.php" was not found"
Seems that the file run.php is not part of the Zend Framework.
Any Idea ?
Help please.
What can you say about design of my sites?
<a href="http://eumcci.com/htm/images/artical/data/index.php">sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=1">adult sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=2">sex toy party</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=3">sex toy for man</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=4">homemade sex toy</a>
What can you say about design of my sites?
<a href="http://eumcci.com/htm/images/artical/data/index.php">sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=1">adult sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=2">sex toy party</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=3">sex toy for man</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=4">homemade sex toy</a>
What can you say about design of my sites?
<a href="http://eumcci.com/htm/images/artical/data/index.php">sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=1">adult sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=2">sex toy party</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=3">sex toy for man</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=4">homemade sex toy</a>
I am currently developing my own framework based on ZF and decided to use TemplateLite as template engine.
In response to octavian82 question, I give you Phlame_View_Tpl integrating TemplateLite with Zend View.
You can view the source here:
http://dev.inetive.pl/phlame/Phlame_View_Tpl.phps
And here is some example.
The template: http://dev.inetive.pl/phlame/test_template.tpl
The example code: http://dev.inetive.pl/phlame/tpl_test.phps
And the result: http://dev.inetive.pl/phlame/tpl_test.php
I would appreciate any comments and ideas.
Inspired by this article I started to play around a bit to integrate the Smarty template engine into the Zend Framework. My ambition was to minimize the required code in the controller actions but stay close to the given Zend_View API. I also wanted to integrate the Smarty caching feature. Here is the code I came up with.
Class location
The class file is named by my company (Travello) and is placed in the Travello directory beneath the Zend Framework library include path. Its advantage is that the class will be auto loaded in my setup.
Class definition and constructor
Let's start with the class definition and the constructor part. My class Travello_View_Smarty is extending the Zend_View_Abstract class. In the constructor the parent constructor from Zend_View_Abstract is called first. After that a Smarty object is instantiated, configured and stored in a private attribute.
Please note that I use a configuration object from the object store to get the configuration data for Smarty.
Implement _run() method
The method _run() is the only method that needs to be implemented in any subclass of Zend_View_Abstract. It is called automatically within the render() method. My implementation just uses the display() method from Smarty to generate and output the template.
Overwrite assign() method
The next part is an overwrite of the assign() method from Zend_View_Abstract, which works in a similar way. The big difference is that the values are assigned to the Smarty object and not to the $this->_vars variables array of Zend_View_Abstract.
Overwrite escape() method
The next part is an overwrite of the escape() method from Zend_View_Abstract. It works both for string and array values and also uses the escape() method from the Zend_View_Abstract. The advantage of this is that I don't have to care about each value of an array to get properly escaped.
Print the output
The next method output() is a wrapper on the render() method from Zend_View_Abstract. It just sets some headers before printing the output.
Use Smarty caching
The last two methods were created to simply integrate the Smarty caching mechanism in the View class. With the first one you can check for cached template and with the second one you can set the caching on or of.
That was the complete code of my Travello_View_Smarty class.
How to use the class
The usage of this class is quite simple. In your bootstrap file you can initialize it like this. The $viewConfig is used to setup the Zend_View paths. After creation the object is registered in the object store for later usage.
Within your controller an action method could look like this.
Conclusion
That was basically it. I have a couple of ideas how to extend this solution, but it already does the work for me. Any comments are welcome.
Updated on April 18, 2006
Please have also a look at the follow-up article on Integrating Sarty and ez Components with the Zend Framework.
Digg This!
Comments
PHPDeveloper.org just pointed out a related article on caching using Smarty. This will fit nicely with what Ralf has written here.
currently I am using the ezcConfiguration and ezcConfigurationIniReader from the ezComponents
http://ez.no/doc/components/view/latest/(file)/introduction_Configuration.html
To integrate the ezComponents within the Zend Framework I put the ezComponents directory in my include_path and use a slightly different __autoload() function:
include_once 'Zend.php';
include_once 'Base/src/base.php';
function __autoload($class)
{
if ('ezc' == substr($class, 0, 3))
{
ezcBase::autoload($class);
}
else
{
Zend::loadClass($class);
}
}
</ pre >
To use the Configuration component I set it up and store the configuration object in the object store of the Zend Framework.
$reader = new ezcConfigurationIniReader();
$reader->init('path/to/your/ini/files', 'settings.ini');
$config = $reader->load();
Zend::register('config', $config);
</ pre >
That is basically it.
HTH, Ralf
If you redefined the Smarty Tags to "<?" and "?>" and uses Templates it allows you to see a really clean design in your design editor (there are other ways to do that, but this is quick!!). Templates also make it easy to develop huge interface changes in all your application on the fly without touching your code (the customers like that!!!) and taking advantage of the smarty cache management.
Another thing that helped me was the idea of Tom Anderson of adding a "T" block for Internationalization support. With this you, can even make your design in English and tagged all translatable text with "T" blocks and after use a Smarty-T- block plugin to support your application in different languages. I used in Japanese and I developed my own t block plug in like this:
{
if ( ! $content )
return $content ;
return i18ngettext( trim ( $content ));
}
The i18ngettext is a function that search into the localization files and returns the content with the translated phrase if it exists. I rewrite the i18ngettext in order to cached the files.
In design time text will look like:
<?t?>Translate me<?/T?>
Bye,
Hermann
For example if you created a Zend_View_Helper_MakeUrl and want to invoke it through a template:
<a href="{makeUrl('index','login')}">Login</a>
I don't think it is possible by using your approach because the helper method are unknown to the smarty object.
In my code is assigned a Zend_View Object that includes all output variables to the smarty object by doing:
$view -> template = ' index.html ' ;
// add other output variables in the actioncontroller
$smarty = new Smarty();
// smarty cfg stuff
//at the end of the script
$smarty -> assign( ' view ' , $view );
$smarty -> display( $view -> template);
By doing this, smarty will automatically invoke the Zend_View::__call() method to unknown funktions, and that invokes the helper methods. the disadvantage is that you have to use:
<a href="{$view->makeUrl('index','login')}">Login</a>
which is a little more code, but it works for me.
One more Question: Did anyone manage to make TemplateLite (former SmartyLite) working with ZF?
regards, Marc
thanks for your comments on internationalization. Sounds very good to me. For myself, I haven't come to that part yet, but your approach sounds reasonable to me.
Until now what I did was to assign an array called "translate" to Smarty and to access the translation via {$template.to_be_translate}.
Best Regards,
Ralf
you could easily assign the View object to Smarty as well by doing something like this in the _run() method:
{
$this -> _smarty -> assign( ' view ' , $this );
$this -> _smarty -> display( $template );
}
But I haven't tested this yet, so I might be wrong.
Best Regards,
Ralf
I just wanted to drop a comment to tell you how much I appreciate this tutorial. I was in the process of starting a new project, and wanted to use a more stuctured approach. I was all ready using smarty without the Zend framework.
I knew I wanted to use the framework in my new project, but also wanted to use smarty. Your tutorial was the deciding factor in my changing to the Zend Framework. After spending most of yesterday downloading, and installing Apache I was able to get it working. (After spending a few hours learning how th configure Apache. Oh well, the burden of running your own server.)
Anyway, thanks again.
Troy
However, I have made just 4 methods in my class:
three that you have mentioned (__construct, assign, _run) and also _script() - to avoid redundant Zend_Exception:
* Overrides parent's method.
* @param $name string The base name of the script.
* @return void
*/
protected function _script( $name )
{
return $name ;
}
The main issue in your code (IMHO) is the following: you are extending the Zend_View_Abstract interface by adding several new methods that are not present in the abstract class. This cannot be considered a problem until one day you decide that Smarty is no good - and you should fall back to using Zend_View instead.
Then you can extend the Zend_View and make Torello_View_Zend class with stub methods, and that will be ok - but I think you should mention this in your article.
"Uncaught exception 'Zend_Exception' with message 'File "Zend/View/Helper/run.php" was not found"
Seems that the file run.php is not part of the Zend Framework.
Any Idea ?
Help please.
What can you say about design of my sites?
<a href="http://eumcci.com/htm/images/artical/data/index.php">sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=1">adult sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=2">sex toy party</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=3">sex toy for man</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=4">homemade sex toy</a>
What can you say about design of my sites?
<a href="http://eumcci.com/htm/images/artical/data/index.php">sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=1">adult sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=2">sex toy party</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=3">sex toy for man</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=4">homemade sex toy</a>
What can you say about design of my sites?
<a href="http://eumcci.com/htm/images/artical/data/index.php">sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=1">adult sex toy</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=2">sex toy party</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=3">sex toy for man</a>
<a href="http://eumcci.com/htm/images/artical/data/?page=4">homemade sex toy</a>
I am currently developing my own framework based on ZF and decided to use TemplateLite as template engine.
In response to octavian82 question, I give you Phlame_View_Tpl integrating TemplateLite with Zend View.
You can view the source here:
http://dev.inetive.pl/phlame/Phlame_View_Tpl.phps
And here is some example.
The template: http://dev.inetive.pl/phlame/test_template.tpl
The example code: http://dev.inetive.pl/phlame/tpl_test.phps
And the result: http://dev.inetive.pl/phlame/tpl_test.php
I would appreciate any comments and ideas.