Smarty and the Zend Framework
by Naneau
Like I’ve mentioned in previous posts, I’m a great fan of using “decent” template engines, and try to avoid writing views in php. I don’t want to discuss the reasons behind this in detail right now. I just believe that limiting yourself to a small set of template tags makes you think more about structuring your output and separating logic from design. Which is a good thing.
When I started using the Zend Framework a while ago now, I read this article on the zend developer zone. While it describes a decent implementation, I have some problems with it. First of all it breaks standard Zend_View behavior. Like mentioned in the comments somewhere, if you were to decide you want to use Zend_View again for some reason you would have to rewrite large parts of your application, apart from editing your templates. Especially the caching functions annoy me, as they add a set of behavior not even remotely present in the parent class. Zend_Cache is there for a reason.
Also, you can’t use view helpers with his approach. So I decided to come up with my own implementation. It follows Zend_View as closely as possible, while still retaining standard Smarty behavior. That means that I have overwritten as little as possible, and added nothing.
You can assign variables to your view and access them directly from your Smarty template, with {$variableName}. However, I have made sure that you can also use $this (like you would in a regular view) in your templates. Have a look at the _run method to see how it works:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | /** * fetch a template, echos the result, * * @see Zend_View_Abstract::render() * @param string $name the template * @return void */ protected function _run() { $vars = get_object_vars($this); foreach ($vars as $key => $value) { if ('_' != substr($key, 0, 1)) { $this->_smarty->assign($key, $value); } } //assign variables to the template engine $this->_smarty->assign_by_ref('this', $this); //why 'this'? //to emulate standard zend view functionality //doesn't mess up smarty in any way $path = $this->getScriptPaths(); $file = substr(func_get_arg(0), strlen($path[0])); //smarty needs a template_dir, and can only use templates, //found in that directory, so we have to strip it from the filename echo $this->_smarty->fetch($file); //process the template (and filter the output) } |
As you can see I use get_object_vars() in _run(). Therefore I didn’t have to overwrite the __get() and __set() methods of the parent class. The only functionality I really did have to overwrite was the way the view handles script paths. Because Smarty expects a single path from which it gets it’s templates, I had to change the setScriptPath() and addScriptPath() methods.
Examples
Check out these examples, to see what I mean:
1 2 3 4 5 6 | {$test} {$this->test} {* will output the same variable 'test' *} {$this->formButton('but', 'button!')} {*will create a button, using the standard zend view helper *} |
There’s one little catch you may want to think about, though. Let’s assume you have a controller script that does the following:
1 2 |
and a template like:
1 2 3 4 5 6 7 8 9 10 |
will output:
1 | Array 1 2 3 4 5 5 |
As you can see, {$test} is an array at first, but the foreach statement puts a new value in it on every loop. After the loop is complete {$test} is set to 5. Please pick one way of accessing your variables and stick to it. Personally I would choose {$this->varName} over {$varName}, even though it’s longer. It’s just closer to the normal Zend_View implementation.
At any rate, download Naneau View Smarty and check it out for yourself! It is well documented. Just put it in your library. Make sure to create a directory for your templates and compiled templates. My playground uses it, and I’ve been more than happy with how it works.
Update – May 29, 2007
Because of the new viewRenderer action helper in the framework snapshot version, you will get exceptions complainingg about somecontroller/someaction.phtml not being present, if you use Naneau_View_Smarty. The action helper tries to automate the process of initiating/rendering views. I suggest you disable the viewRenderer action helper for now:
1 | $frontController->setParam('noViewRenderer', true); |
Update 2 – May 31, 2007
I have a solution for those that want to use Naneau_View_Smarty with Zend Framework 1.0.0RC1.
Comments
Thanks for the great article. I really like using the Zend Framework, but hate having to write views the Zend way. This gives the best blend of Smartys in built functions, and the cool Zend_View helpers.
Thanks again.
Hi there, why not just use this approach:
$view = new Zend_View();
/* set view options and put it in the registry to fill it in the controller-actions */
$smarty = new Smarty();
/* set smarty options */
$smarty->assign(‘view’, $view);
$smarty->display($view->template);
Then you can easily access all view variables and even Helpers and the smarty modifiers:
{$view->test|esape}
{$view->formSelect(…)}
Greetings, Marc
That would work, indeed, but I don’t think it’s a good implementation for two reasons. First you would have to work with both Smarty AND Zend_View in your controllers, assigning variables and setting up helpers/filters/etc. with the second, then displaying it using the first. As you can see I also assign the view directly to Smarty, but do this in the _run() method. You can still use Smarty modifiers as well as view helpers. Basically it’s the same thing, but with my approach you wouldn’t have to update your controllers if you would like to change your View class.
The second reason is, that you would lose behavior, check out this snippet from the render function from Zend_View_Abstract:
ob_start();
$this->_run($this->_file);
return $this->_filter(ob_get_clean()); // filter output
If you use the display() function from Smarty, you loose this (handy) filtering behavior. I tried to follow the Zend_View approach as closely as possible. If you don’t like Zend_View you could of course loose it completely and use just Smarty for output processing.
[...] Cal Evans points out on the Zend Developer Zone today, Maurice Fonk has created a nice little tutorial on using the Smarty templating system to help manage the output of a Zend Framework [...]
This is great, thank you! Am testing it out now. One thing occurred to me was that I’d like to pass a Zend Config object in to the class instead of an assoc array. You see in my app config.ini, I have these rows:
smarty.scriptPath = /root/views
smarty.compileDir = /root/views/templates_c
smarty.configDir = /root/views/config
So, I can access these through $config->smarty in the controller. Obviously scriptPath etc are properties of object rather than keys of array. Where do you think the best place to do this conversion is? This is my hack:
Controller:
$config = $registry->get(‘config’);
$view = new Naneau_View_Smarty($config->smarty);
Hacked Naneau Lib:
public function __construct($config_object)
{
$this->_smarty = new Smarty();
//Process incoming ini object
$config = array();
$config['scriptPath'] = $config_object->scriptPath;
$config['compileDir'] = $config_object->compileDir;
$config['configDir'] = $config_object->configDir;
…
Thanks!
Ignore my last comment – sorry!
Here’s my solution:
$view = new Naneau_View_Smarty($config->smarty->asArray());
Sorry, askismet somehow marked your comments as spam… Right in the middle of a spam wave. So I’m a bit late to react. You found out about the asArray() method yourself already, sounds like a good solution.
I subclass my view by the way, and set up configuration in the subclass’ constructor. It feels like a lot of repetition to do it time and time again in your controllers
. I have also subclassed Zend_Controller_Action, to provide a createView() method, which reduces overhead even more. I guess I should do that in an action helper though. But when I created my controller class, those weren’t around.
Thanks for your excellent tutorials. I would love to see how to use Smarty templating along with the new ViewRenderer. Perhaps the solution is to extend Zend_Controller_Action_Helper_ViewRenderer? I’m just starting to use ZF so I’m not too sure.
Bryan, check out: http://naneau.nl/2007/05/31/using-naneau_view_smarty-with-rc1/
I am new to Zend.
Where and how do I put the smarty config?
I have imitated Zend_View_Abstract behavior. You can pass an array of configuration options to the constructor. The only one you have to set is compileDir, the others get set either automatically, or aren’t needed (you shouldn’t use Smarty’s own caching with this solution).
If you really do need to do additional setup, you can retrieve the smarty object with getEngine(), and use that directly.
[...] those who feel the need can integrate various templating systems with the Zend_View (here’s a nice article on integrating Smarty with [...]
Bonjour Monsieur Fonk,
Could you please enlighten me on the view filters. In a comment I noticed this little sentence :
“If you use the display() function from Smarty, you loose this (handy) filtering behavior”
I was wondering which kind of filters you’d apply on the output. Moreover, the view filters directory is empty in the zf and the doumentation is very poor on the subject.
I often come back on old posts but, you know, I read them, then, after a wile, when I got a problem, I remember I read something about it. So, if you don’t mind…
Fred
P.S : as you’re a smarty aficionado, did you take a look at Template Lite ?
I really like what you’ve done. Thanks.
One question though. Is there a way to use Smarty “include” statement?
Thanks again
Jeff
[...] написал довольно таки симпатичную, короткую статью об использовании Smarty внутри Zend Framework. Like I’ve mentioned in previous posts, I’m a great fan of using“decent” template engines, [...]
[...] Naneau Smarty and the Zend Framework – No overhead for all colocated parts Naneau Smarty and the Zend Framework [...]
[...] Naneau Smarty and the Zend Framework – No overhead for all colocated parts Naneau Smarty and the Zend Framework [...]
Could any one tells me why smarty implementation needed on zend? What are the benefits of smarty over zend template?
Thanks
Do you like to write ‘var_name ?>’ instead of ” ?
And what about powerful smarty functions ?
Sorry, mistake:
I made a small change to the _run function
protected function _run()
{
$this->strictVars(true);
//assign variables to the template engine
$vars = get_object_vars($this);
foreach ($vars as $key => $value) {
if (‘_’ != substr($key, 0, 1)) {
$this->_smarty->assign($key, $value);
}
}
//why ‘this’?
//to emulate standard zend view functionality
//doesn’t mess up smarty in any way
$this->_smarty->assign_by_ref(‘this’, $this);
//smarty needs a template_dir, and can only use templates,
//found in that directory, so we have to strip it from the filename
//This checks the default application/smarty/template directory
// as well as the module views/scripts directory to find the template
$paths = $this->getScriptPaths();
$arg = func_get_arg(0);
foreach ($paths as $path) {
if ($file = substr($arg, strlen($path))) {
$this->_smarty->template_dir = $path;
break;
}
}
//process the template (and filter the output)
echo $this->_smarty->fetch($file);
}
I found I needed to do this for a specific application that didn’t use teh controller view/script directories but instead used the standard smarty template directory. My change allows smarty to work with either. Hope its useful to someone. Thanks for the original code.
There is a small amendment to the above _run() code to deal with ZF-5062 issue.
replace
$paths = $this->getScriptPaths();
$arg = func_get_arg(0);
foreach ($paths as $path) {
if ($file = substr($arg, strlen($path))) {
$this->_smarty->template_dir = $path;
break;
}
}
with
$paths = $this->getScriptPaths();
$arg = func_get_arg(0);
foreach ($paths as $path) {
//next line added by matthew phinney @ Zend to stop problems with
// render() – issue ZF-5062
if (0 === strpos($arg,$path)) {
if ($file = substr($arg, strlen($path))) {
$this->_smarty->template_dir = $path;
break;
}
}
}
This fixes that issue and means that smarty will observe Zend_View rendering rules.
Is is possibale to Add the smarty on Zend frame work, Because we are creating new php application on zend framework, we want to use the another application which is created by smarty. OR is there any sample project for Smarty and Zend Framework
Mark
http://www.outsourceitindia.com
http://dwoo.org/
Yes, dwoo is most certainly worth mentioning. It’s a PHP5 replacement for smarty that has near full compatibility. It will run in STRICT, so your server admin will be happy.
Hi ,
i’m new to zend and smarty.i’m using Mac-OS. i tried my projects in zend framework. But i don know how to integrate smarty templates with zend. please send me the structure of integration or Simple application sources for MAC-OS. It will be helpful for me…..