35.3. Скрипты вида

После того, как ваш контроллер определил переменные и вызвал метод render(), Zend_View включает требуемый скрипт представления и выполняет его "внутри" области видимости Zend_View. Поэтому в вашем скрипте представления ссылки на $this в действительности будут ссылаться на сам экземляр Zend_View.

Переменные, объявленные для вида в контроллере, ссылаются на свойства экземпляра. Например, если контроллер объявил переменную 'something', вы можете ссылаться на нее как на $this->something в скрипте вида (это дает вам возможность отслеживать, какие переменные были объявлены для скрипта, и какие были объявлены самим скриптом).

Для напоминания, здесь приведен пример скрипта представления из введения.

<?php if ($this->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>Нет книг для отображения.</p>
    
<?php endif; ?>
    

35.3.1. Экранирование вывода

Одной из наиважнейших задач, которую должен решать скрипт вида, является обеспечение того, что выходные данные должным образом экранированы; помимо прочего, это помогает предотвратить XSS-атаки. За исключением тех случаев, когда используете функции, методы или вспомогательные классы, которые делают экранирование сами, вы должны всегда экранировать переменные, когда выводите их.

Zend_View снабжен методом escape(), который выполняет экранирование.

<?php
// плохая практика для скриптов вида
echo $this->variable;

// хорошая практика для скриптов вида
echo $this->escape($this->variable);
?>
        

По умолчанию метод escape() использует функцию PHP htmlspecialchars() для экранирования. Но, в зависимости от вашего окружения, может потребоваться выполнять экранирование по-иному. Используйте метод setEscape() на уровне контроллера, чтобы указать Zend_View, какую экранирующую функцию обратного вызова использовать.

<?php
// создание экземпляра Zend_View
$view = new Zend_View();

// приказываем ему использовать htmlentities
// в качестве экранирующей функции обратного вызова
$view->setEscape('htmlentities');

// либо приказываем ему использовать статический метод класса
$view->setEscape(array('SomeClass', 'methodName'));

// или даже метод экземпляра
$obj = new SomeClass();
$view->setEscape(array($obj, 'methodName'));

// и затем воспроизводим вид
echo $view->render(...);
?>
        

Функции или методы обратного вызова должны принимать значение, которое требуется экранировать как первый параметр, все остальные параметры должны быть необязателными.

35.3.2. Использование других шаблонизаторов

Хотя PHP сам по себе представляет собой мощный шаблонизатор, многие разработчики считают его избыточным или слишком сложным для верстальщиков и поэтому предпочитают использовать другие шаблонизаторы. Zend_View предоставляет 2 пути для этого: первый – через скрипты вида, второй - посредством реализации интерфейса Zend_View_Interface.

35.3.2.1. Шаблонизаторы c использованием скриптов видов

Скрипт вида может использоваться для инстанцирования и манипулирования отдельным объектом шаблона (это могут быть шаблоны в стиле PHPLIB).

<?php
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");
}
?>

Это может соответствовать следующему файлу шаблона:

<!-- 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>Нет книг для отображения.</p>

35.3.2.2. Шаблонизаторы с использованием Zend_View_Interface

Некоторым может быть удобнее использовать совместимый с Zend_View шаблонизатор. Zend_View_Interface предоставляет минимальный интерфейс, необходимый для совместимости:

/**
 * Возвращает объект используемого шаблонизатора
 */
public function getEngine();

/**
 * Устанавливает путь к шаблонам или скриптам вида
 */
public function setScriptPath($path);

/**
 * Переопределение методов для присвоения значений переменным шаблонов как
 * свойствам объекта
 */
public function __set($key, $value);
public function __get($key);
public function __isset($key);
public function __unset($key);

/**
 * "Ручная" установка значения переменной шаблона или одновременное присвоение
 * значений нескольким переменным
 */
public function assign($spec, $value = null);

/**
 * Удаление всех переменных шаблона
 */
public function clearVars();

/**
 * Вывод шаблона с именем $name
 */
public function render($name);

Используя этот интерфейс, можно легко сделать "обертку" для шаблонизаторов сторонних разработчиков. В примере показан вариант "обертки" для Smarty:

require_once 'Zend/View/Interface.php';
require_once 'Smarty.class.php';

class Zend_View_Smarty implements Zend_View_Interface
{
    /**
     * Объект Smarty 
     * @var Smarty
     */
    protected $_smarty;

    /**
     * Конструктор
     *
     * @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 Smarty
     */
    public function getEngine()
    {
        return $this->_smarty;
    }

    /**
     * Установка пути к шаблонам
     *
     * @param string $path Директория, устанавливаемая как путь к шаблонам
     * @return void
     */
    public function setScriptPath($path)
    {
        if (is_readable($path)) {
            $this->_smarty->template_dir = $path;
            return;
        }

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

    /**
     * Присвоение значения переменной шаблона
     *
     * @param string $key The variable name.
     * @param mixed $val The variable value.
     * @return void
     */
    public function __set($key, $val)
    {
        $this->_smarty->assign($key, $val);
    }

    /**
     * Получение значения переменной
     *
     * @param string $key The variable name.
     * @return mixed The variable value.
     */
    public function __get($key)
    {
        return $this->_smarty->get_template_vars($key);
    }

    /**
     * Позволяет проверять переменные через empty() и isset()
     *
     * @param string $key
     * @return boolean
     */
    public function __isset($key)
    {
        return (null !== $this->_smarty->get_template_vars($key));
    }

    /**
     * Позволяет удалять свойства объекта через unset()
     *
     * @param string $key
     * @return void
     */
    public function __unset($key)
    {
        $this->_smarty->clear_assign($key);
    }

    /**
     * Присвоение переменных шаблону
     *
     * Позволяет установить значение к определенному ключу или передать массив
     * пар ключ => значение
     *
     * @see __set()
     * @param string|array $spec Ключ или массив пар ключ => значение 
     * @param mixed $value (необязательный) Если присваивается значение одной
     * переменной, то через него передается значение переменной
     * @return void
     */
    public function assign($spec, $value = null)
    {
        if (is_array($spec)) {
            $this->_smarty->assign($spec);
            return;
        }

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

    /**
     * Удаление всех переменных
     *
     * @return void
     */
    public function clearVars()
    {
        $this->_smarty->clear_all_assign();
    }

    /**
     * Обрабатывает шаблон и возвращает вывод
     *
     * @param string $name Шаблон для обработки
     * @return string Вывод
     */
    public function render($name)
    {
        return $this->_smarty->fetch($name);
    }
}

В этом примере вы можете инстанцировать класс Zend_View_Smarty вместо Zend_View и использовать его подобно тому, как используется Zend_View.

$view = new Zend_View_Smarty();
$view->setScriptPath('/path/to/templates');
$view->book = 'Zend PHP 5 Certification Study Guide';
$view->author = 'Davey Shafik and Ben Ramsey'
$rendered = $view->render('bookinfo.tpl');