
The part describes how to plug PHPTAL to Zend Framework and have traditional helpers and scripts reusable as well (e.g. Zend_Layout or Zend_Form). You should already know what a powerful template system PHPTAL is.
So now, when we have ready Basic Zend Framework application, we may start to add PHPTAL onto it. First of all is downloading PHPTAL, and placing it into /library directory.
The best place to hang up PHPTAL is obviously My_Controller_PLugin_ViewSetup class. We need to replace new Zend_View with our custom, PHPTAL view.
Usually you create custom views by extending Zend_View_Interface. Matthew Ratzloff does it right this way. I don't think it is the best way. Better way is extending Zend_View_Abstract, and this is the way we will do it. The best solution would be to handle everything by PHP magic methods (__set, __get, __call and so on). Let's see how it looks like:
<?
require_once('Zend/View/Abstract.php');
/**
* file: /library/My/PHPTAL/ZFView.php
* Extended Zend_View to support PHPTAL
*/
class My_PHPTAL_ZFView extends Zend_View_Abstract
{
/**
* PHPTAL object
* @access private
* @var object PHPTAL
*/
protected $_engine = null;
/**
* Plug in PHPTAL object into View
*
* @name setEngine
* @access public
* @param object PHPTAL $engine
*/
public function setEngine(PHPTAL $engine)
{
$this->_engine = $engine;
$this->_engine->set('this', $this);
return $this;
}
/**
* Get PHPTAL object from View
*
* @name getEngine
* @access public
*/
public function getEngine()
{
return $this->_engine;
}
/**
* Set PHPTAL variables
*
* @access public
* @param string $key variable name
* @param string $value variable value
*/
public function __set($key, $value)
{
$this->_engine->set($key, $value);
}
/**
* Get PHPTAL Variable Value
*
* @access public
* @param string $key variable name
* @return mixed variable value
*/
public function __get($key)
{
return $this->_engine->$key;
}
/**
* Check if PHPTAL variable is set
*
* @access public
* @param string $key variable name
*/
public function __isset($key)
{
return isset($this->_engine->$key);
}
/**
* Unset PHPTAL variable
*
* @access public
* @param string $key variable name
*/
public function __unset($key)
{
if (isset($this->_engine->$key)) {
unset($this->_engine->$key);
}
}
/**
* Clone PHPTAL object
*
* @access public
*/
public function __clone()
{
$this->_engine = clone $this->_engine;
}
/**
* Display template
*
* @access protected
*/
protected function _run()
{
$this->_engine->setTemplate(func_get_arg(0));
try {
echo $this->_engine->execute();
} catch (Zend_View_Exception $e) {
throw new Zend_View_Exception($e);
}
}
}
I used setEngine() method to pass PHPTAL object to the View. Now we need to change our ViewSetup.php. We just replace Zend_View with My_PHPTAL_ZFView class, set some PHPTAL options, and pass it to the View. Now it looks like that:
<?php
require_once 'Zend/Controller/Plugin/Abstract.php';
/**
* Zend_Controller_Plugin preparing View
*/
class My_Controller_Plugin_ViewSetup extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopStartup (Zend_Controller_Request_Abstract $request)
{
$root = Bootstrap::$root;
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
/*$view = new Zend_View();*/
// now we are using PHPTAL View
$view = new My_PHPTAL_ZFView();
$view->addScriptPath($root . '/application/modules/'
. $request->getModuleName() . '/views/templates'
)
->doctype('XHTML1_STRICT');
$viewRenderer->setView($view)
->setViewSuffix('tpl.html')
->init();
// setup Zend_Layout (optional)
Zend_Layout::startMvc(array(
'layoutPath' => $root
. '/application/modules/default/views/layouts',
'layout' => 'main' , 'viewSuffix' => 'tpl.html'
)
);
// add this two lines if you wish to use PHPTAL
$phptal = new PHPTAL;
$view->setEngine($phptal);
// phptal options
$phptal->setPhpCodeDestination($root . '/temp')
->setForceReparse(true);
}
}
That's it. Simple, isn't it? Since now we can use ${variable} to display variable, and ${php:this.helpername()} to display helper content. If you wish to display HTML code, you must prepend this with structure keyword. The syntax of helpers doesn't look very inviting, so I decided to write custom PHPTAL modifier to simplify the syntax:
/**
* helper: custom PHPTAL modifier
*
* You may want to rename this function
* to phptal_tales_this if you want to use
* this:helperName() instead helper:helperName()
*
* @name phptal_tales_helper
* @param string $src
* @param bool $nothrow
*/
function phptal_tales_helper($src, $nothrow)
{
$src = 'this->' . trim($src);
require_once 'PHPTAL/Php/Transformer.php';
return PHPTAL_Php_Transformer::transform($src, '$ctx->');
}
Just put this function in ZFView.php. Now you can use syntax like this: ${helper:helpername()}, e.g. ${structure helper:layout().content}. But it what with the .phtml scripts we created prior to using Zend Framework + PHPTAL? For now this inline php syntax does not work. We need to replace it manually, use regex in our favorite editor, or… write PHPTAL pre-filter to do it for us:
<?php
/**
* PHPTAL Filter
* file: /library/My/PHPTAL/Filter/ZFSyntax.php
* Fixes Zend_View inline PHP to use with PHPTAL
*/
class My_PHPTAL_Filter_ZFSyntax implements PHPTAL_Filter
{
protected $search = '';
protected $replace = '';
/**
* Add ctx-> to this->
* Used in preg_replace callback function
*
* @name _replace
* @access private
* @param string $str
* @return string
*/
private function _replace($str)
{
$search = array(
// helpers
'@\$this->([^\(\s;]+)\s?\((.*)\)@is',
// variables
'@\$this->([a-zA-z_0-9^\(]+)@is'
);
$replace = array(
'$ctx->this->\\1(\\2)',
'$ctx->\\1'
);
$str = preg_replace($search, $replace, $str);
return $str;
}
/**
* String filtering method, returns filtered string
*
* @name filter
* @access public
* @param string $xhtml
* @return string
*/
public function filter($xhtml)
{
// finds PHP code block and performs _replace only inside
$xhtml = preg_replace('@(<\?(=|php)?\s(.*?)\s\?>)@es', '$this->_replace(\'\\1\')', $xhtml);
return $xhtml;
}
}
?>
We put this filter in /library/My/PHPTAL/Filter/ZFSyntax.php and register it adding one line to PHPTAL configuration in ViewSetup.php:
// phptal options
$phptal->setPhpCodeDestination($root . '/temp')
->setForceReparse(true)
// pre filter to support traditional Zend_View syntax in templates
->setPreFilter(new My_PHPTAL_Filter_ZFSyntax());
Note: After extracting archives you must download Zend Framework and PHPTAL libraries and put it in the /library directory.