Una vez que su controlador ha asignado variables y llamado a render(),
Zend_View incluye el script de vista solicitado y lo
ejecuta "dentro" del ámbito de la instancia de Zend_View. Por lo tanto,
en sus scripts de vista, las referencias a $this en realidad apuntan a la
propia instancia de Zend_View.
Las variables asignadas a la vista desde el controlador se denominan propiedades de instancia. Por ejemplo, si el controlador asignara una variable 'something', usted se referiría a ella como $this->something en el script de vista. (Esto le permite mantener un seguimiento de qué valores se asignaron al script, y cuáles son internos al script en sí mismo.)
A modo de recordatorio, aquí está el script de vista de ejemplo de la
introducción de Zend_View.
<?php if ($this->books): ?>
<!-- A table of some books. -->
<table>
<tr>
<th>Author</th>
<th>Title</th>
</tr>
<?php foreach ($this->books as $key => $val): ?>
<tr>
<td><?php echo $this->escape($val['author']) ?></td>
<td><?php echo $this->escape($val['title']) ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php else: ?>
<p>There are no books to display.</p>
<?php endif;?>
Una de las tareas más importantes a realizar en un script de vista es asegurarse de que la salida se escape correctamente; entre otras cosas, esto ayuda a evitar ataques de cross-site scripting. A menos que esté usando una función, método o helper que realice el escapado por sí mismo, siempre debería escapar las variables cuando las muestre.
Zend_View incluye un método llamado escape() que realiza dicho
escapado por usted.
// bad view-script practice: echo $this->variable; // good view-script practice: echo $this->escape($this->variable);
Por defecto, el método escape() usa la función PHP htmlspecialchars()
para el escapado. Sin embargo, dependiendo de su entorno,
puede que desee que el escapado se realice de una forma diferente. Use el
método setEscape() a nivel del controlador para indicarle a Zend_View
qué callback de escapado usar.
// create a Zend_View instance
$view = new Zend_View();
// tell it to use htmlentities as the escaping callback
$view->setEscape('htmlentities');
// or tell it to use a static class method as the callback
$view->setEscape(array('SomeClass', 'methodName'));
// or even an instance method
$obj = new SomeClass();
$view->setEscape(array($obj, 'methodName'));
// and then render your view
echo $view->render(...);
La función o método de callback debería recibir el valor a escapar como su primer parámetro, y todos los demás parámetros deberían ser opcionales.
Aunque PHP es en sí mismo un potente sistema de plantillas, muchos desarrolladores
sienten que es demasiado potente o complejo para sus diseñadores de plantillas y
querrán usar un motor de plantillas alternativo. Zend_View proporciona
dos mecanismos para hacerlo, el primero a través de scripts de vista, el
segundo implementando Zend_View_Interface.
Un script de vista puede usarse para instanciar y manipular un objeto de plantilla independiente, como una plantilla al estilo PHPLIB. El script de vista para ese tipo de actividad podría parecerse a esto:
include_once 'template.inc';
$tpl = new Template();
if ($this->books) {
$tpl->setFile(array(
"booklist" => "booklist.tpl",
"eachbook" => "eachbook.tpl",
));
foreach ($this->books as $key => $val) {
$tpl->set_var('author', $this->escape($val['author']);
$tpl->set_var('title', $this->escape($val['title']);
$tpl->parse("books", "eachbook", true);
}
$tpl->pparse("output", "booklist");
} else {
$tpl->setFile("nobooks", "nobooks.tpl")
$tpl->pparse("output", "nobooks");
}
Estos serían los archivos de plantilla relacionados:
<!-- booklist.tpl -->
<table>
<tr>
<th>Author</th>
<th>Title</th>
</tr>
{books}
</table>
<!-- eachbook.tpl -->
<tr>
<td>{author}</td>
<td>{title}</td>
</tr>
<!-- nobooks.tpl -->
<p>There are no books to display.</p>
Algunos pueden encontrar más fácil simplemente proporcionar un
motor de plantillas compatible con Zend_View.
Zend_View_Interface define la interfaz mínima necesaria para
la compatibilidad:
/** * Return the actual template engine object */ public function getEngine(); /** * Set the path to view scripts/templates */ public function setScriptPath($path); /** * Set a base path to all view resources */ public function setBasePath($path, $prefix = 'Zend_View'); /** * Add an additional base path to view resources */ public function addBasePath($path, $prefix = 'Zend_View'); /** * Retrieve the current script paths */ public function getScriptPaths(); /** * Overloading methods for assigning template variables as object * properties */ public function __set($key, $value); public function __isset($key); public function __unset($key); /** * Manual assignment of template variables, or ability to assign * multiple variables en masse. */ public function assign($spec, $value = null); /** * Unset all assigned template variables */ public function clearVars(); /** * Render the template named $name */ public function render($name);
Usando esta interfaz, resulta relativamente fácil envolver un
motor de plantillas de terceros como una clase compatible con Zend_View.
Como ejemplo, el siguiente es un posible wrapper para Smarty:
class Zend_View_Smarty 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())
{
$this->_smarty = new Smarty;
if (null !== $tmplPath) {
$this->setScriptPath($tmplPath);
}
foreach ($extraParams as $key => $value) {
$this->_smarty->$key = $value;
}
}
/**
* 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);
}
/**
* 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);
}
}
En este ejemplo, usted instanciaría la clase
Zend_View_Smarty en lugar de
Zend_View, y luego la usaría de forma aproximadamente igual
que Zend_View:
//Example 1. In initView() of initializer.
$view = new Zend_View_Smarty('/path/to/templates');
$viewRenderer =
Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$viewRenderer->setView($view)
->setViewBasePathSpec($view->_smarty->template_dir)
->setViewScriptPathSpec(':controller/:action.:suffix')
->setViewScriptPathNoControllerSpec(':action.:suffix')
->setViewSuffix('tpl');
//Example 2. Usage in action controller remains the same...
class FooController extends Zend_Controller_Action
{
public function barAction()
{
$this->view->book = 'Zend PHP 5 Certification Study Guide';
$this->view->author = 'Davey Shafik and Ben Ramsey'
}
}
//Example 3. Initializing view in action controller
class FooController extends Zend_Controller_Action
{
public function init()
{
$this->view = new Zend_View_Smarty('/path/to/templates');
$viewRenderer = $this->_helper->getHelper('viewRenderer');
$viewRenderer->setView($this->view)
->setViewBasePathSpec($view->_smarty->template_dir)
->setViewScriptPathSpec(':controller/:action.:suffix')
->setViewScriptPathNoControllerSpec(':action.:suffix')
->setViewSuffix('tpl');
}