15.2. Zend_Form - Быстрый старт

Данное руководство должно охватывать основы создания форм, проверки корректности данных и рендеринга с использованием Zend_Form.

15.2.1. Создание объекта формы

Создавать объекты форм очень просто - просто инстанцируйте Zend_Form:

<?php
$form = new Zend_Form;
?>

Для более сложных случаев использования вы можете создавать подклассы Zend_Form, но простые форм вы можете создавать, используя объект Zend_Form.

Если вы хотите указать атрибуты action и method (что во всех случаях является хорошей идеей), то можете сделать это с использованием аксессоров setAction() и setMethod():

<?php
$form->setAction('/resource/process')
     ->setMethod('post');
?>

Приведенный выше код устанавливает значение атрибута action равным "/resource/process" и указывает способ отправки данных - HTTP POST. Эти атрибуты будут выведены после окончательного рендеринга формы.

Вы можете установить дополнительные HTML-атрибуты для тега <form>, используя методы setAttrib() и setAttribs(). Например, если вы хотите установить идентификатор элемента формы, то установите атрибут "id":

<?php
$form->setAttrib('id', 'login');
?>

15.2.2. Добавление элементов в форму

Форма без элементов бесмысленна. Zend_Form поставляется с некоторым начальным набором элементов, которые отвечают за рендеринг XHTML-кода с использованием помощников Zend_View. В этот список входят элементы:

  • button (кнопка)

  • checkbox (флажок опций, или несколько флажков опций через multiCheckbox)

  • hidden (спрятанное поле)

  • image (изображение)

  • password (пароль)

  • radio (переключатель)

  • reset (кнопка сброса)

  • select (выпадающий список, как обычный, так multi-select)

  • submit (кнопка отправки)

  • text (текстовое поле)

  • textarea (текстовая область)

Есть два способа добавления элементов в форму - вы можете инстанцировать нужные элементы и передавать их объекту формы, или передавать только тип элемента, в этом случае Zend_Form инстанцирует соответствующий объект за вас.

Некоторые примеры:

<?php
// Инстанцирование элемента и его передача объекту формы:
$form->addElement(new Zend_Form_Element_Text('username'));

// Передача типа элемента объекту формы 
$form->addElement('text', 'username');
?>

По умолчанию элементы не имеют никаких валидаторов или фильтров. Это означает, что вам нужно установить к своим элементам, как минимум, валидаторы, и, возможно, фильтры. Вы можете делать это (a) до передачи элементов в форму, (b) через опции конфигурирования, которые передаются при создании элемента через Zend_Form, или (с) путем извлечения элементов формы из объекта формы и их конфигурирования.

Сначала рассмотрим создание валидаторов для конкретного объекта элемента. Вы можете передавать объекты Zend_Validate_* или имена валидаторов:

<?php
$username = new Zend_Form_Element_Text('username');

// Передача объекта Zend_Validate_*:
$username->addValidator(new Zend_Validate_Alnum());

// Передача имени валидатора:
$username->addValidator('alnum');
?>

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

<?php
// Передача шаблона
$username->addValidator('regex', false, array('/^[a-z]/i'));
?>

(Второй параметр используется для указания того, должен ли валидатор в том случае, если данные не прошли проверку, прерывать дальнейшую проверку в цепочке валидаторов; по умолчанию он равен false.)

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

<?php
// Указание того, что элемент обязателен для заполнения:
$username->setRequired(true);
?>

Если элемент обязателен для заполнения, то в начало цепочки валидаторов добавляется валидатор 'NotEmpty', который проверяет, имеет ли элемент значение.

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

<?php
$username->addFilter('StringtoLower');
?>

Таким образом, наша установка элемента может выглядеть следующим образом:

<?php
$username->addValidator('alnum')
         ->addValidator('regex', false, array('/^[a-z]/'))
         ->setRequired(true)
         ->addFilter('StringToLower');

// or, more compactly:
$username->addValidators(array('alnum',
        array('regex', false, '/^[a-z]/i')
    ))
    ->setRequired(true)
    ->addFilters(array('StringToLower'));
?>

Выполнение этих действий для каждого элемента по отдельности может быть несколько утомительным. Давайте попробуем вариант (b) из перечисленных выше. Когда мы создаем новый элемент, используя Zend_Form::addElement() в качестве фабрики, то можем опционально передавать опции конфигурирования. Они могут включать в себя валидаторы и фильтры для использования. Таким образом, чтобы неявным образом сделать это, попробуйте следующее:

<?php
$form->addElement('text', 'username', array(
    'validators' => array(
        'alnum',
        array('regex', false, '/^[a-z]/i')
    ),
    'required' => true,
    'filters'  => array('StringToLower'),
));
?>
[Замечание] Замечание

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

15.2.3. Рендеринг формы

Рендеринг формы производится легко. Большинство элементов использует помощника Zend_View для генерации вывода и поэтому нуждаются в объекте вида для выполнения рендеринга. Есть два способа запустить рендеринг: использовать метод формы render() или просто вывести ее с помощью echo.

<?php
// Явный вызов render() с передачей объекта вида:
echo $form->render($view);

// Предполагается, что объект вида уже был установлен ранее через setView():
echo $form;
?>

По умолчанию Zend_Form будет пытаться использовать объект вида, инициализированный в ViewRenderer, это означает, что вам не нужно будет вручную устанавливать объект вида при использовании MVC Zend Framework-а. Код для рендеринга формы в скрипте вида весьма прост:

<?= $this->form ?>

Внутри себя Zend_Form использует "декораторы" для выполнения рендеринга. Эти декораторы могут замещать содержимое переданного элемента, производить добавления в его начало и конец, производить наблюдение за ним. В результате вы можете комбинировать несколько декораторов для достижения нужного эффекта. По умолчанию в Zend_Form_Element используется четыре декоратора для получения нужного вывода; их установка выглядит приблизительно так:

<?php
$element->addDecorators(array(
    'ViewHelper',
    'Errors',
    array('HtmlTag', array('tag' => 'dd')),
    array('Label', array('tag' => 'dt')),
));
?>

Код выше создает вывод наподобие следующего:

<dt><label for="username" class="required">Username</dt>
<dd>
    <input type="text" name="username" value="123-abc" />
    <ul class="errors">
        <li>'123-abc' has not only alphabetic and digit characters</li>
        <li>'123-abc' does not match against pattern '/^[a-z]/i'</li>
    </ul>
</dd>

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

Форма сама по себе просто производит обход содержащегося в ней списка элементов и окружает получившийся вывод тегами <form>. Переданные вами action и method устанавливаются в качестве атрибутов тега <form> - так же, как и остальные атрибуты, установленные через семейство методов setAttribs().

Элементы обходятся в том же порядке, в котором они были зарегистрированы, но если ваш элемент содержит атрибут order, то он используется для сортировки. Вы можете установить порядок элемента, используя:

<?php
$element->setOrder(10);
?>

Или путем передачи в качестве опции при создании элемента:

<?php
$form->addElement('text', 'username', array('order' => 10));
?>

15.2.4. Проверка корректности данных формы

После того, как форма отправлена, нужно сверить переданные данные и выяснить, проходит ли она проверку на корректность заполнения. Для всех элементов производится проверка переданных данных на наличие ключа, соответствующего имени элемента. Если этот ключ не найден, и элемент помечен как обязательный, то для проверки на корректность используется значение null.

Откуда идут данные? Вы можете использовать $_POST, $_GET, и любые другие имеющиеся источники данных (например, запросы веб-сервисов):

<?php
if ($form->isValid($_POST)) {
    // успех
} else {
    // неудача
}
?>

Вам может прийти в голову идея проверять данные одного элемента или группы элементов с помощью AJAX-запросов. Метод isValidPartial() будет проверять на корректность данные части формы. Его отличие от isValid() состоит в том, что если в данных формы отсутствует какой-либо ключ, то для этого элемента не будут производиться проверки на корректность заполнения:

<?php
if ($form->isValidPartial($_POST)) {
    // все предоставленные элементы прошли проверки на корректность
} else {
    // один или более элементов не прошли проверки на корректность
}
?>

Для проверки части формы может также использоваться метод processAjax(). В отличие от isValidPartial(), в случае неуспеха он возвращает строку в формате JSON, содержащую сообщения об ошибках заполнения.

Если проверка на корректность заполнения была пройдена успешно, то вы можете извлечь прошедшие фильтрацию данные:

<?php
$values = $form->getValues();
?>

Для того, чтобы извлечь нефильтрованные данные, используйте:

<?php
$unfiltered = $form->getUnfilteredValues();
?>

15.2.5. Получение статуса ошибки

А что, если форма не прошла проверку на корректность? В большинстве случаев вы можете просто снова вывести ее, и сообщения об ошибках будут отображены, если вы используете декораторы по умолчанию:

<?php
if (!$form->isValid($_POST)) {
    echo $form;

    // or assign to the view object and render a view...
    $this->view->form = $form;
    return $this->render('form');
}
?>

Если нужно проанализировать ошибки, то для их получения есть два метода. getErrors() возвращает ассоциативный массив имен элементов и кодов ошибок (где коды ошибок представлены в виде массива). getMessages() возвращает ассоциативный массив имен элементов и сообщений об ошибках (где сообщения об ошибках представлены в виде ассоциативного массива пар 'код ошибки'/'сообщение об ошибке'). Если элемент не имеет ошибок, то он не будет включен в массив.

15.2.6. Объединяя изложенное

Давайте создадим простую форму для входа на сайт. Для нее будут нужны следующие элементы:

  • username

  • password

  • submit

Для примера предположим, что корректное имя пользователя должно содержать только буквенно-цифровые символы, начинаться с буквы, иметь длину не меньше 6 и не больше 20 символов, кроме этого, имена пользователей должны быть приведены к нижнему регистру. Пароль должен содержать как минимум 6 символов. Переданное значение кнопки использоваться не будет, поэтому проверка для нее может не производиться.

Мы используем мощь конфигурационных опций Zend_Form для построения формы:

<?php


$form = new Zend_Form();
$form->setAction('/usr/login')
     ->setMethod('post');

// Создание и конфигурирование элемента username
$username = $form->createElement('text', 'username');
$username->addValidator('alnum')
         ->addValidator('regex', false, array('/^[a-z]+/'))
         ->addValidator('stringLength', false, array(6, 20))
         ->setRequired(true)
         ->addFilter('StringToLower');

// Создание и конфигурирование элемента password
$password = $form->createElement('password', 'password');
$password->addValidator('StringLength', false, array(6))
         ->setRequired(true);

// Добавление элементов в форму:
$form->addElement($username)
     ->addElement($password)
     // addElement() используется в качестве "фабрики" для создания кнопки 'Login':
     ->addElement('submit', 'login', array('label' => 'Login'));
?>

Затем создается контроллер для отображения формы и ее обработки:

<?php class UserController extends Zend_Controller_Action
{
    public function getForm()
    {
        // здесь должен быть код для создания формы, приведенный выше
        return $form;
    }

    public function indexAction()
    {
        // рендеринг user/form.phtml
        $this->view->form = $this->getForm();
        $this->render('form');
    }

    public function loginAction()
    {
        if (!$this->getRequest()->isPost()) {
            return $this->_forward('index');
        }
        $form = $this->getForm();
        if (!$form->isValid($_POST)) {
            // проверка на корректность не пройдена, выводим форму снова
            $this->form = $form;
            return $this->render('form');
        }
        
        $values = $form->getValues();
        // аутентификация...
    }
}
?>

...и скрипт вида для отображения формы:

<h2>Please login:</h2>
<?= $this->form ?>

Как вы, наверное, заметили, код контроллера не является полным, после успешно проведенной проверки должна производиться авторизация пользователя (например, используя Zend_Auth).

15.2.7. Использование объекта Zend_Config

Все классы Zend_Form можно конфигурировать, используя Zend_Config. Вы можете передавать объект Zend_Config либо конструктору, либо через метод setConfig(). Посмотрим, как можно создать описанную выше форму, используя файл INI. Во-первых, будем следовать рекомендации размещать конфигурации в разделах, отражающих местонахождение релиза, и сфокусируемся на разделе 'development'. Во-вторых, установим раздел для данного контроллера ('user') и ключ для формы ('login'):

[development]
; общие метаданные для формы
user.login.action = "/user/login"
user.login.method = "post"

; элемент username
user.login.elements.username.type = "text"
user.login.elements.username.options.validators.alnum.validator = "alnum"
user.login.elements.username.options.validators.regex.validator = "regex"
user.login.elements.username.options.validators.regex.options.pattern = "/^[a-z]/i"
user.login.elements.username.options.validators.strlen.validator = "StringLength"
user.login.elements.username.options.validators.strlen.options.min = "6"
user.login.elements.username.options.validators.strlen.options.max = "20"
user.login.elements.username.options.required = true
user.login.elements.username.options.filters.lower.filter = "StringToLower"

; элемент password
user.login.elements.password.type = "password"
user.login.elements.password.options.validators.strlen.validator = "StringLength"
user.login.elements.password.options.validators.strlen.options.min = "6"
user.login.elements.password.options.required = true

; элемент кнопки
user.login.elements.submit.type = "submit"

Вы можете потом передать это конструктору формы:

<?php
$config = new Zend_Config_Ini($configFile, 'development');
$form   = new Zend_Form($config->user->login);
?>

... и вся форма будет определена.

15.2.8. Заключение

Надеемся, благодаря этому небольшому обучающему руководству вы на верном пути к открытию для себя мощи и гибкости Zend_Form. Читайте далее для получения более подробной информации!

    Поддержать сайт на родительском проекте КГБ