# Помощники видов

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

Помощник представляет собой просто класс. Скажем, нам нужен помощник 'fooBar'. По умолчанию имя класса помощника начинается с `'Zend_View_Helper_'` (вы можете указать другой префикс при установке путей к помощникам видов), последней частью имени класа является имя помощника. Все слова этой части должны писаться слитно, первые буквы слов - в верхнем регистре (TitleCapped); таким образом мы получаем имя класа `Zend_View_Helper_FooBar`. Класс должен содержать как минимум один метод, названный по имени помощника в формате camelCase: `fooBar()`.

## Следите за регистром

Имена помощников всегда должны быть в стиле camelCased, т.е. они никогда не начинаются с символа в верхнем регистре. Имя класса имеет стиль MixedCase (т.е. начинается с символа в верхнем регистре), но реально выполняемый метод должен быть в стиле camelCase.

## Используемый по умолчанию путь к помощникам

Используемый по умолчанию путь к помощникам всегда указывает на помощники Zend Framework-а, т.е. 'Zend/View/Helper/'. Даже если вы вызываете `setHelperPath()` для перезаписи существующих путей, этот путь всегда будет использоваться для обеспечения работы помощников, входящих в поставку Zend Framework-а

Для того, чтобы использовать помощника в своем скрипте вида, вызывайте его, используя `$this->имяПомощника()`. В этом случае `Zend_View` загрузит класс `Zend_View_Helper_ИмяПомощника`, создаст его экземпляр и вызовет его метод `имяПомощника()`. Экземпляр объекта сохраняется в экземпляре `Zend_View` и будет повторно использоваться им во всех будущих вызовах `$this->имяПомощника()`.

## Начальный набор помощников

`Zend_View` поставляется с начальным набором помощников, большинство из которых связано с генерацией элементов форм и автоматически экранирует весь вывод. Кроме этого, есть помощники для создания HTML-списков, URL-ов на основе маршрутов, и объявления переменных. В настоящее время в поставляемый набор входят:

- `declareVars():` В основном предназначен для использования вместе с `strictVars()`. Этот помощник может использоваться для объявления переменных шаблонов, которые не обязательно присутствуют в объекте вида, и для установки значений по умолчанию. Массивы, переданные методу в качестве аргуметов, будут использованы для установки значений по умолчанию; иначе, если переменная не существует, то ее значением будет пустая строка.

- `fieldset($name, $content, $attribs):` Создает XHTML-элемент `fieldset` (набор полей). Если массив `$attribs` содержит в ключ 'legend', то это значение используется для элемента `legend`. Элемент `fieldset` будет содержать в себе значение параметра `$content`, переданного помощнику.

- `form($name, $attribs, $content):` Генерирует XHTML-элемент `form` (форма). Все элементы массива `$attribs` и добавляются как аттрибуты тега `form`. Если параметр `$content` передан и не имеет значение false, то это содержимое добавляется между открывающим и закрывающим тегами формы. Если же `$content` имеет булево значение false (значение по умолчанию), то будет сгенерирован только открывающий тег формы.

- `formButton($name, $value, $attribs)`: Создает элемент `<button />`.

- `formCheckbox($name, $value, $attribs, $options)`: Создает элемент `<input type="checkbox" />` (флажок опций).

  По умолчанию, если не был передан параметры `$value` и `$options`, то значение '1' соотвествует выбранному состоянию, '0' - не выбранному. Если был передан параметр `$value`, но не передан `$options`, то значение `$value` соотвествует выбранному состоянию.

  `$options` должен быть массивом. Если это индексный массив, то первое значение соответствует выбранному состоянию, второе - не выбранному состоянию, все остальные значения игнорируются. Вы можете также передавать массив с ключами 'checked' и 'unChecked'.

  Если параметр $options был передан, и `$value` соответствует значению в выбранном состоянии, то элемент будет помечен как выбранный. Вы можете также помечать элемент как выбранный или не выбранный путем передачи значения булевого типа для атрибута 'checked'.

  Наверное, лучше всего проиллюстрировать это примерами:

      // '1' и '0' в качестве значений для выбранного/ не выбранного состояний
      // флажок не выбран
      echo $this->formCheckbox('foo');

      // '1' и '0' в качестве значений для выбранного/ не выбранного состояний
      // флажок выбран
      echo $this->formCheckbox('foo', null, array('checked' => true));

      // 'bar' и '0' в качестве значений для выбранного/ не выбранного состояний
      // флажок не выбран
      echo $this->formCheckbox('foo', 'bar');

      // 'bar' и '0' в качестве значений для выбранного/ не выбранного состояний
      // флажок выбран
      echo $this->formCheckbox('foo', 'bar', array('checked' => true));

      // 'bar' и 'baz' в качестве значений для выбранного/ не выбранного состояний
      // флажок не выбран
      echo $this->formCheckbox('foo', null, null, array('bar', 'baz');

      // 'bar' и 'baz' в качестве значений для выбранного/ не выбранного состояний
      // флажок не выбран
      echo $this->formCheckbox('foo', null, null, array(
          'checked' => 'bar',
          'unChecked' => 'baz'
      ));

      // 'bar' и 'baz' в качестве значений для выбранного/ не выбранного состояний
      // флажок выбран
      echo $this->formCheckbox('foo', 'bar', null, array('bar', 'baz');
      echo $this->formCheckbox('foo',
                               null,
                               array('checked' => true),
                               array('bar', 'baz');

      // 'bar' и 'baz' в качестве значений для выбранного/ не выбранного состояний
      // флажок не выбран
      echo $this->formCheckbox('foo', 'baz', null, array('bar', 'baz');
      echo $this->formCheckbox('foo',
                               null,
                               array('checked' => false),
                               array('bar', 'baz');

  Во всех случаях разметка предваряется скрытым элементом `<input type="hidden" />` со значением для не выбранного состояния. Таким образом, и в том случае, если флажок опций не был выбран, вы будете получать корректное значение, возвращаемое вашей форме.

- `formErrors($errors, $options):` Генерирует ненумерованный список XHTML для вывода сообщений об ошибках. `$errors` должен быть строкой или массивом строк. `$options` должен заключать в себе все аттрибуты, которые вы хотите поместить в открывающий тег списка.

  Вы можете указать альтернативный открывающий, закрывающий и разделяющий код путем вызова нескольких методов данного помощника:

  - `setElementStart($string)`; по умолчанию используется '<ul class="errors"%s"><li>', где %s заменяется аттрибутами, указанными в `$options`.

  - `setElementSeparator($string)`; по умолчанию используется '</li><li>'.

  - `setElementEnd($string)`; по умолчанию используется '</li></ul>'.

- `formFile($name, $attribs)`: Создает элемент `<input type="file" />`.

- `formHidden($name, $value, $attribs)`: Создает элемент `<input type="hidden" />`.

- `formLabel($name, $value, $attribs):` Создает элемент <label>, устанавливая значение аттрибута `for` равным значению `$name`, и содержимое элемента равным значению `$value`. Если в `$attribs` был передан `disable`, то ничего не будет возвращено.

- `formMultiCheckbox($name, $value, $attribs, $options, $listsep):` Создает список флажков опций. `$options` должен быть ассоциативным массивом, который может быть произвольной глубины. `$value` может быть скалярным значением или массивом выбранных значений, которые соответствуют ключам в массиве `$options`. `$listsep` по умолчанию является переносом строки в HTML ("<br />"). По умолчанию этот элемент интерпретируется как массив - все флажки опций имеют одно и то же имя и передаются как массив.

- `formPassword($name, $value, $attribs)`: Создает элемент `<input type="password" />`.

- `formRadio($name, $value, $attribs, $options)`: Создает последовательность элементов `<input type="radio" />` (переключатель опций). В массиве `$options` ключ является значением переключателя, значение является содержимым элемента `label` к переключателю. Переключатель опций со значением `$value` будет предварительно выбранным.

- `formReset($name, $value, $attribs)`: Создает элемент `<input type="reset" />`.

- `formSelect($name, $value, $attribs, $options)`: Создает блок `<select>...</select>`, с опциями `<option>`, соотвествующими элементам массива `$options`. В массиве `$options` ключ является значением опции, значение - текстом опции. Опция со значением `$value` будет предварительно выбранной.

- `formSubmit($name, $value, $attribs)`: Создает элемент `<input type="submit" />`.

- `formText($name, $value, $attribs)`: Создает элемент `<input type="text" />`.

- `formTextarea($name, $value, $attribs)`: Создает блок `<textarea>...</textarea>`.

- `url($urlOptions, $name, $reset):` Создает строку URL, основываясь на машруте с именем `$name`. `$urlOptions` должен быть ассоциативным массивом пар ключ-значение для использования в данном маршруте.

- `htmlList($items, $ordered, $attribs, $escape):` Генерирует маркированный или нумерованный список на основе `$items`. Если `$items` является многомерным массивом, то будут построены вложенные списки. Если `$escape` установлен в true (значение по умолчанию), то все пункты будут экранированы с использованием механизма, зарегистрированного в объекте вида. Передавайте значение false, если хотите использовать разметку в своих списках. Если `$ordered` установлен в false (значение по умолчанию), то генерируется маркированный список, иначе - нумерованный.

Использовать их в скрипте вида очень просто, вот пример. Обратите внимание, все, что вам нужно - это вызывать их, помощники будут загружаться и инстанцироваться автоматически, по мере необходимости.

    // в скрипте вида $this ссылается на экземпляр Zend_View
    //
    // предположим, вы уже имеете последовательность опций $countries
    // в виде массива ('us' => 'United States', 'il' =>
    // 'Israel', 'de' => 'Germany')
    ?>
    <form action="action.php" method="post">
        <p><label>Your Email:
    <?php echo $this->formText('email', 'you@example.com', array('size' => 32)) ?>
        </label></p>
        <p><label>Your Country:
    <?php echo $this->formSelect('country', 'us', null, $this->countries) ?>
        </label></p>
        <p><label>Would you like to opt in?
    <?php echo $this->formCheckbox('opt_in', 'yes', null, array('yes', 'no')) ?>
        </label></p>
    </form>

Результирующие выходные данные этого скрипта вида будут выглядеть примерно следующим образом:

    <form action="action.php" method="post">
        <p><label>Your Email:
            <input type="text" name="email" value="you@example.com" size="32" />
        </label></p>
        <p><label>Your Country:
            <select name="country">
                <option value="us" selected="selected">United States</option>
                <option value="il">Israel</option>
                <option value="de">Germany</option>
            </select>
        </label></p>
        <p><label>Would you like to opt in?
            <input type="hidden" name="opt_in" value="no" />
            <input type="checkbox" name="opt_in" value="yes" checked="checked" />
        </label></p>
    </form>

## Пути к классам помощников

Как и для скриптов вида, ваш контроллер может задать стек путей, в которых `Zend_View` должен искать классы помощников. По умолчанию `Zend_View` ищет классы помощников в `Zend/View/Helper/*`. Используя методы `setHelperPath()` и `addHelperPath()`, вы можете укзать `Zend_View`, чтобы он искал классы помощников в других местах. Кроме этого, вы можете указать префикс класса, используемый для помощников, находящихся в данном пути; префикс обеспечивает пространство имен. Если префикс не указан, то по умолчанию используется 'Zend_View_Helper_'.

    $view = new Zend_View();

    // Устанавливает путь /path/to/more/helpers с префиксом 'My_View_Helper'
    $view->setHelperPath('/path/to/more/helpers', 'My_View_Helper');

Вы можете "складывать" в стек пути, используя метод `addHelperPath()`. Если вы добавили пути в стек, то `Zend_View` будет искать запрошенный класс помощника в этих путях, начиная с пути, добавленного последним. Это дает возможность добавлять своих помощников к начальному набору (или даже замещать имеющиеся).

    $view = new Zend_View();
    // Добавить /path/to/some/helpers с префиксом для классов 'My_View_Helper'
    $view->addHelperPath('/path/to/some/helpers', 'My_View_Helper);
    // Добавить /other/path/to/helpers с префиксом для классов 'Your_View_Helper'
    $view->addHelperPath('/other/path/to/helpers', 'Your_View_Helper');

    // теперь, когда вы вызываете $this->helperName(), Zend_View будет искать
    // "/path/to/some/helpers/HelperName" с классом
    // "Your_View_Helper_HelperName", затем "/other/path/to/helpers/HelperName.php"
    // с классом "My_View_Helper_HelperName", и под конец
    // "Zend/View/Helper/HelperName.php" с классом "Zend_View_Helper_HelperName".

## Написание собственных помощников

Написать собственного помощника довольно легко, просто следуйте этим правилам:

- Хотя это и не является совершенно необходимым, мы рекомендуем при создании своего помощника реализовывать интерфейс `Zend_View_Helper_Interface` или наследовать от класса `Zend_View_Helper_Abstract`. Добавленные в версии 1.6.0, они определяют только метод `setView()`, но в будущих релизах мы планируем реализовать паттерн "стратегия", который значительно упростит следование правилам по именованию, изложенным ниже. Следование этой рекомендации сейчас поможет в будущем избежать изменений в вашем коде.

- Имя класса должно, как минимум, заканчиваться именем помощника в стиле MixedCaps (СмешанныйРегистр). Т.е. если вы пишете помощника с именем "specialPurpose", то наиболее короткое имя класса должно быть "SpecialPurpose". Вы можете (и должны) давать классам имена с префиксом, рекомендуется использовать 'View_Helper' как часть этого префикса: "My_View_Helper_SpecialPurpose". Вам нужно будет передать этот префикс с или без завершающего знака подчеркивания методу `addHelperPath()` или `setHelperPath()`.

- Класс должен иметь открытый метод, имя которого соответствует имени помощника. Это метод, который будет вызываться, когда в вашем шаблоне производится вызов `$this->specialPurpose()`. В нашем примере с помощником "specialPurpose" объявление требуемого метода должно быть `public function specialPurpose()`.

- Обычно класс не должен выполнять вывод, вместо этого он должен возвращать значение для вывода. Возвращаемое значение должно быть экранировано должным образом.

- Класс должен быть в файле, названном по имени класса. Снова используя пример с помощником "specialPurpose", мы должны дать файлу имя "SpecialPurpose.php".

Размещайте класс помощника где-либо в одном из находящихся в стеке путей к помощникам, и `Zend_View` будет автоматически загружать, инстанцировать, сохранять и выполнять его.

Вот пример кода нашего помощника `SpecialPurpose`:

    class My_View_Helper_SpecialPurpose extends Zend_View_Helper_Abstract
    {
        protected $_count = 0;
        public function specialPurpose()
        {
            $this->_count++;
            $output = "I have seen 'The Jerk' {$this->_count} time(s).";
            return htmlspecialchars($output);
        }
    }

Далее в скрипте вида вы можете вызывать помощника `SpecialPurpose` сколько угодно раз. Он будет инстанцирован один раз, и существует, пока существует экземпляр `Zend_View`.

    // помните, что в скрипте вида $this ссылается на экземпляр Zend_View
    echo $this->specialPurpose();
    echo $this->specialPurpose();
    echo $this->specialPurpose();

Результат должен быть примерно следующим:

    I have seen 'The Jerk' 1 time(s).
    I have seen 'The Jerk' 2 time(s).
    I have seen 'The Jerk' 3 time(s).

Иногда бывает, что нужен доступ к объекту `Zend_View` - например, нужно получить зарегистрированное значение кодировки или произвести рендеринг другого скрипта вида как часть действий, выполняемых вашим помощником. Для того, чтобы можно было получить доступ к объекту вида, ваш класс помощника должен иметь метод `setView($view)`, его пример показан ниже:

    class My_View_Helper_ScriptPath
    {
        public $view;

        public function setView(Zend_View_Interface $view)
        {
            $this->view = $view;
        }

        public function scriptPath($script)
        {
            return $this->view->getScriptPath($script);
        }
    }

Если ваш класс помощника имеет метод `setView()`, то он будет вызываться при первом инстанцировании класса помощника и его передаче текущему объекту вида. Реализация сохранения объекта вида и доступа к нему в вашем классе помощника остаются на ваше усмотрение.

Если вы наследуете своего помощника от `Zend_View_Helper_Abstract`, то вам не нужно определять этот метод, поскольку он уже определен в родительском классе.