Sunday, January 4, 2009

Integrate Smarty with Zend Framework

I collected some information regarding this topic.

The first one is probably the easiest approach to use Smarty in Zend framework.
require('Zend.php');

include 'smarty/Smarty.class.php';
$smarty = new Smarty();
$smarty->template_dir = 'resources/templates';
$smarty->compile_dir = 'resources/templates_c';
$smarty->plugins_dir = array(SMARTY_DIR . 'plugins', 'resources/plugins');
//may be some more smarty setup

//register this smarty
Zend::register('smarty', $smarty);

//use it in action controller
class IndexController extends Zend_Controller_Action
{
function index()
{
$smarty = Zend::registry('smarty');
$smarty->assign('title', 'Test');
$smarty->display('index.tpl');
}
}

However, you have to handle view logic in your action controllers.

The second option is to extend Zend_View_Abstract
class Templater extends Zend_View_Abstract
{
protected $_path;
protected $_engine;

public function __construct()
{
$config = Zend_Registry::get('config');

require_once('Smarty/Smarty.class.php');

$this->_engine = new Smarty();
$this->_engine->template_dir = $config->paths->templates;
$this->_engine->compile_dir = sprintf('%s/tmp/templates_c',
$config->paths->data);

$this->_engine->plugins_dir = array($config->paths->base .
'/include/Templater/plugins',
'plugins');
}

public function getEngine()
{
return $this->_engine;
}

public function __set($key, $val)
{
$this->_engine->assign($key, $val);
}

public function __get($key)
{
return $this->_engine->get_template_vars($key);
}

public function __isset($key)
{
return $this->_engine->get_template_vars($key) !== null;
}

public function __unset($key)
{
$this->_engine->clear_assign($key);
}

public function assign($spec, $value = null)
{
if (is_array($spec)) {
$this->_engine->assign($spec);
return;
}

$this->_engine->assign($spec, $value);
}

public function clearVars()
{
$this->_engine->clear_all_assign();
}

public function render($name)
{
return $this->_engine->fetch(strtolower($name));
}

public function _run()
{ }
}
And we need to set up view renderer in bootstrap file
// setup the view renderer
$vr = new Zend_Controller_Action_Helper_ViewRenderer();
$vr->setView(new Templater());
$vr->setViewSuffix('tpl');
Zend_Controller_Action_HelperBroker::addHelper($vr);

An alternative is to implement Zend_View_Interface
class App_View implements Zend_View_Interface
{
/**
* Smarty object
* @var Smarty
*/
protected $_smarty;

/**
* Constructor
*
* @param string $tmplPath
* @param array $extraParams
* @return void
*/
public function __construct($tmplPath = null, $extraParams = array())
{
require_once ('Smarty/Smarty.class.php');
$this->_smarty = new Smarty;

if (null !== $tmplPath) {
$this->setScriptPath($tmplPath);
}

foreach ($extraParams as $key => $value) {
$this->_smarty->$key = $value;
}
$config = Zend_Registry::get('config');
$this->_smarty->compile_dir = sprintf('%s/templates_c', $config->paths->data);
$this->_smarty->plugins_dir = '';
$this->base_url = $config->paths->baseurl;
}

/**
* Return the template engine object
*
* @return Smarty
*/
public function getEngine()
{
return $this->_smarty;
}

/**
* Set the path to the templates
*
* @param string $path The directory to set as the path.
* @return void
*/
public function setScriptPath($path)
{
if (is_readable($path)) {
$this->_smarty->template_dir = $path;
return;
}

throw new Exception('Invalid path provided');
}

/**
* Retrieve the current template directory
*
* @return string
*/
public function getScriptPaths()
{
return array($this->_smarty->template_dir);
}

/**
* Alias for setScriptPath
*
* @param string $path
* @param string $prefix Unused
* @return void
*/
public function setBasePath($path, $prefix = 'Zend_View')
{
return $this->setScriptPath($path);
}

/**
* Alias for setScriptPath
*
* @param string $path
* @param string $prefix Unused
* @return void
*/
public function addBasePath($path, $prefix = 'Zend_View')
{
return $this->setScriptPath($path);
}

/**
* Assign a variable to the template
*
* @param string $key The variable name.
* @param mixed $val The variable value.
* @return void
*/
public function __set($key, $val)
{
$this->_smarty->assign($key, $val);
}

/**
* Retrieve an assigned variable
*
* @param string $key The variable name.
* @return mixed The variable value.
*/
public function __get($key)
{
return $this->_smarty->get_template_vars($key);
}

/**
* Allows testing with empty() and isset() to work
*
* @param string $key
* @return boolean
*/
public function __isset($key)
{
return (null !== $this->_smarty->get_template_vars($key));
}

/**
* Allows unset() on object properties to work
*
* @param string $key
* @return void
*/
public function __unset($key)
{
$this->_smarty->clear_assign($key);
}

/**
* Assign variables to the template
*
* Allows setting a specific key to the specified value, OR passing
* an array of key => value pairs to set en masse.
*
* @see __set()
* @param string|array $spec The assignment strategy to use (key or
* array of key => value pairs)
* @param mixed $value (Optional) If assigning a named variable,
* use this as the value.
* @return void
*/
public function assign($spec, $value = null)
{
if (is_array($spec)) {
$this->_smarty->assign($spec);
return;
}

$this->_smarty->assign($spec, $value);
}

/**
* Clear all assigned variables
*
* Clears all variables assigned to Zend_View either via
* {@link assign()} or property overloading
* ({@link __get()}/{@link __set()}).
*
* @return void
*/
public function clearVars()
{
$this->_smarty->clear_all_assign();
}

/**
* Processes a template and returns the output.
*
* @param string $name The template to process.
* @return string The output.
*/
public function render($name)
{
return $this->_smarty->fetch($name);
}

/**
* get smarty template dir
*
* @return string template dir
*/
public function getScriptPath()
{
return $this->_smarty->template_dir;
}//end getScriptPath()
}


There is one problem with this method: all template files have to be placed in one directory. What if we want to put template files in different folders? Say, i have two modules, and their templates are placed in two folders named with the module names?

The key is the value of template_dir. To work around, we can specify template_dir at action controller.

class App_ControllerAction extends Zend_Controller_Action
{
public $db;
public function init()
{
//set smarty templete dir
$module = $this->getRequest()->getModuleName();
$path = Zend_Registry::get('config')->paths->templates;
if (empty($module) === false) {
$this->view->setScriptPath($path . '/' . $module);
}
}
}

No comments: