Построение приложения на базе Zend Framework. Часть 2. Zend_Form, Zend_Validate, Zend_Filter, Zend_Captcha, Zend_Translate
Опубликовано: 07.01.2009
|
- Введение
- Доработка архитектуры
- Основные принципы работы с Zend_Form
- Работа с элементами формы (Zend_Form_Element_*)
- Zend_Form и Zend_Validate, создание валидатора
- Zend_Form и Zend_Filter, создание фильтра
- Декораторы Zend_Form, создание декоратора
- Zend_Captcha и Zend_Form_Element_Captcha
- Визуальные группы
- Перевод сообщений об ошибках
- Вывод формы в скрипте вида
- Настройка внешнего вида формы
- Обработка формы
- Добавление данных в базу данных
- FlashMessenger и создание плагина для front контроллера
- Заключение
Данная статья – это вторая часть туториала «Построение приложения на базе Zend Framework». С первой частью вы можете ознакомиться по ссылке. В первой статье мы создали простой сайт, функциональность которого ограничивалась отображением данных, полученных из базы. Такой функциональности может хватить для простого сайта визитки, состоящего из нескольких информационных страниц. Но, если мы хотим, чтобы пользователи не только читали информацию на нашем сайте, но и сами наполняли сайт, более активно участвовали в его жизни, тогда нам не обойтись без html форм. Zend Framework приходит на помощь, предлагая компонент Zend_Form – мощное и гибкое средство по генерации и обработке html форм. Вокруг него и будет строиться наше повествование.
Если вы работаете с Zend Framework 1.8.0 и старше прочтите это.
В этой статье рассматриваются следующие вопросы:
- Работа с формами с помощью Zend_Form, включая работу с элементами формы, валидаторами, фильтрами, декораторами и визуальными группами;
- Создание элементов формы на примере электронной почты;
- Создание валидаторов на примере валидатора пароля, валидатора совпадения двух строк и валидатора проверки отсутствия записи в базе;
- Создание фильтров на примере фильтра, переводящего строку в транслит;
- Создание декораторов на примере декоратора, интегрирующего javascript-календарь для выбора даты;
- Использования компонента Zend_Captcha и элемента формы Zend_Form_Element_Captcha для защиты от спама;
- Перевод ошибок формы с помощью Zend_Translate;
- Вставка информации в базу данных;
- Вывод сообщений с использованием помощника FlashMessenger.
Код приложения, разрабатываемого в этой статье, базируется на коде из предыдущей части туториала. Для лучшего понимания статьи желательно сразу скачать код и просматривать его по ходу чтения материала. Код написан и протестирован для Zend Framework 1.7.1, но, скорее всего, будет работать как на предыдущих (>= 1.5), так и на последующих версиях. Работу с формами мы рассмотрим на примере формы регистрации.
Ввиду того, что приложение становится более сложным, мы выполним небольшой рефакторинг архитектуры и кода из первой части. Изменим структуру директорий. В каталоге library добавим папку App. Эта папка будет содержать нашу библиотеку, которая будет «надстройкой» над Zend Framework. В нашу библиотеку будет попадать код достаточно общий и независимый от самого приложения, которое находится в папке application. Это будут классы наследники от классов фреймворка, самописные валидаторы, фильтры, элементы форм, декораторы и т д. То есть, все то, что может быть достаточно легко переносимо между различными приложениями.
Классы в нашей библиотеке будут именоваться согласно стандартам Zend Framework, например имя класса App_Form_Element_Email будет соответствовать пути App/Form/Element/Email.php. Приставка App необходима для того, чтобы ваши классы не конфликтовали с классами фреймворка. Если же вы хотите в дальнейшем распространять свою библиотеку среди других разработчиков то приставка должна быть уникальной, например, это может быть ваш никнейм.
Изменится также структура папки models. Если в первой части в качестве модели у нас выступали только классы работы с базой, то теперь модель расширяется, становится более «толстой». В папке models мы добавим две новые папки – DbTable и Form, в которых будут размещаться классы, работающие с таблицами базы данных и наши формы, соответственно. Названиями этих папок мы четко определяем суть классов, которые лежат в них.
Здесь у вас могут возникнуть сомнения, ведь на первый взгляд формы это часть вида, а не модели. Это не совсем так, Zend_Form агрегирует элементы, метаданные, декораторы. Каждый элемент в свою очередь агрегирует метаданные, цепочки валидаторов и фильтров и декораторы. Декораторы действительно отвечают за представление формы, но ведь вы можете и не отображать форму вовсе. С интересным подходом интеграции форм и модели вы можете ознакомится в статье.
Папку application/system мы удалим, класс Error перенесем в library/App/Error.php, он получит новое имя App_Error. Bootstrap.php перемещается на уровень выше в application/Bootstrap.php, а файл с маршрутами перемещается в папку settings, так как по сути своей файл маршрутов является конфигурационным. В итоге, мы получим следующую структуру директорий:

Теперь о том, что касается непосредственно регистрации. Нам необходим новый маршрут для страницы регистрации и новый контроллер AuthController, который будет содержать в себе действия, относящиеся к идентификации пользователя в системе. Регистрация относится к таким действиям, поэтому мы создадим пустое действие registerAction и соответствующий, пустой скрипт вида. В процессе статьи мы наполним действие и скрипт вида кодом.
Кроме этого, для работы с новыми функциями нам необходимо добавить следующие компоненты фреймворка в папку library/Zend - Zend_Form, Zend_Translate, Zend_Captcha, Zend_Session(необходим для Zend_Captcha и FlashMessenger), Zend_Validate, Zend_Date.
Хочу отметить, что компонент Zend_Form достаточно хорошо описан в официальном мануале на
Компонент Zend_Form предоставляет нам полный набор функционала по работе с формами, при этом он избавляет нас от массы рутинной работы. Zend_Form это:
- Генерация html кода форм;
- Группирование и конфигурирование элементов и форм;
- Фильтрация и проверка корректности данных, введенных в форму;
- Встроенный механиз вывода сообщений об ошибках.
Компонент Zend_Form тесно связан с компонентами Zend_Validate, Zend_Filter, Zend_Config. Zend_Validate предоставляет валидаторы для использования в формах, Zend_Filter дает фильтры, а Zend_Config возможность задавать формы в текстовых конфигурационных файлах.
Основные понятия, напрямую связанные с Zend_Form, это:
- Элементы формы (Zend_Form_Element_*)
- Декораторы (Zend_Form_Decorator_*)
- Визуальные группы (Display Groups)
- Вложенные формы (Sub Forms)
Элементы Zend_Form отвечают реальным элементам html форм. Декораторы дают возможность настраивать внешний вид форм, то есть отвечают за html код. Визуальные группы позволяют объединять схожие по сути элементы, обычно, и по умолчанию, это происходит с помощью тега fieldset. Вложенные формы позволяют объединять элементы логически, это, в свою очередь, дает нам возможность создавать многостраничные формы, то есть такие формы, которые заполняются поэтапно на нескольких страницах.
Благодаря Zend_Form, мы избавляемся от дублирования кода, вся информация о конкретной форме хранится вместе с формой, и таким образом, наши формы можно использовать по нескольку раз.
В нашем приложении каждой сущности будет отвечать своя форма, а за каждую форму будет отвечать свой файл, расположенный в папке application/models/Form/. Например, класс формы регистрации, который мы рассмотрим далее, будет расположен в application/models/Form/Register.php и будет иметь название Form_Register.
Во избежание дублирования кода мы создадим класс App_Form, который будет наследником Zend_Form. В нем мы проведем все необходимые настройки наших форм, и, далее, каждая создаваемая форма будет уже наследоваться от App_Form.
Рассмотрим код класса App_Form:
class App_Form extends Zend_Form
{
/**
* Инициализация формы
*
* return void
*/
public function init()
{
// Вызов родительского метода
parent::init();
// Создаем объект переводчика, он нам необходим для перевода сообщений об ошибках.
// В качестве адаптера используется php массив
$translator = new Zend_Translate('array', Zend_Registry::get('config')->path->languages . 'errors.php');
// Задаем объект переводчика для формы
$this->setTranslator($translator);
/* Задаем префиксы для самописных элементов, валидаторов, фильтров и декораторов.
Благодаря этому Zend_Form будет знать где искать наши самописные элементы */
$this->addElementPrefixPath('App_Validate', 'App/Validate/', 'validate');
$this->addElementPrefixPath('App_Filter', 'App/Filter/', 'filter');
$this->addElementPrefixPath('App_Form_Decorator', 'App/Form/Decorator/', 'decorator');
}
}
Вся настройка формы будет происходить в методе init(), он выполняется при инициализации формы, в конце конструктора Zend_Form.
Общий алгоритм работы с формами выглядит следующим образом:
- Создание объекта формы;
- Настройка элементов формы;
- Вывод html кода формы;
- Заполнение данных формы и отправка на сервер;
- Проверка и фильтрация данных;
- В случае, если данные прошли проверку, происходит дальнейшая обработка данных, например, занесение их в базу. В обратном случае форма снова отображается вместе с сообщениями об ошибках. Следует отметить, что форма сохраняет введенные пользователем данные и, при их выводе, производит замену потенциально опасных символов на их коды.
Каждый из этих пунктов будет подробно рассмотрен далее.
Итак, мы создаем форму регистрации, опишем все параметры полей.
- Электронная почта
- Обязательное text поле;
- Максимальная длина 80 символов;
- Значение должно быть валидным адресом электронной почты;
- Значение почты должно быть уникальным в базе данных.
- Пароль
- Обязательное password поле;
- Максимальная длина 30 символов;
- Значение должно быть валидным паролем.
- Подтверждение пароля
- Обязательное password поле;
- Максимальная длина 30 символов;
- Значение должно быть валидным паролем;
- Значение поля должно совпадать с Паролем.
- Имя
- Обязательное text поле;
- Максимальная длина 30 символов;
- Значение должно состоять из алфавитных символов, цифр и пробелов.
- Пол
- Необязательное radio поле;
- Содержит два значения, «Муж» и «Жен»
- Дата рождения
- Необязательное text поле;
- Значение должно быть валидной датой в формате ДД.ММ.ГГГГ;
- Для выбора даты используется javascript календарь от dynarch.com.
- Возраст
- Необязательное select поле.
- О себе
- Необязательное textarea поле.
- CAPTCHA элемент
- Обязательное text поле, использующееся для защиты от спама.
- Согласие с правилами
- Обязательное checkbox поле.
- Кнопка «Зарегистрировать»
- Кнопка типа submit для отправки формы.
- Кнопка «Очистить»
- Кнопка типа reset для очистки формы.
У нас получилась достаточно реальная форма регистрации, содержащая в себе практически все основные элементы форм.
Далее я привожу полный код формы с подробными комментариями.
class Form_Register extends App_Form
{
/**
* Создание формы
*/
public function init()
{
// Вызываем родительский метод
parent::init();
// Указываем action формы
$helperUrl = new Zend_View_Helper_Url();
$this->setAction($helperUrl->url(array(), 'auth_register'));
// Указываем метод формы
$this->setMethod('post');
// Задаем атрибут class для формы
$this->setAttrib('class', 'register');
// Используемый собственный элемент App_Form_Element_Email
$email = new App_Form_Element_Email('email', array(
'required' => true,
));
// Добавление элемента в форму
$this->addElement($email);
// Password элемент "Пароль". Значение проверяется валидатором App_Validate_Password
$password = new Zend_Form_Element_Password('password', array(
'required' => true,
'label' => 'Пароль:',
'maxlength' => '30',
'validators' => array('Password'),
));
$this->addElement($password);
// Элемент "Подтверждение пароля".
// Проверяется на совпадение с полем "Пароль" валидатором App_Validate_EqualInputs
$passwordApprove = new Zend_Form_Element_Password('password_approve', array(
'required' => true,
'label' => 'Подтвердите пароль:',
'maxlength' => '30',
'validators' => array(array('EqualInputs', true, array('password'))),
));
$this->addElement($passwordApprove);
// Text элемент "Имя". Проверяется на алфавитные символы и цифры, а также на длину
// Валидатор Alnum использует установленную локаль для определения алфавита символов.
$name = new Zend_Form_Element_Text('name', array(
'required' => true,
'label' => 'Имя:',
'maxlength' => '30',
'validators' => array(
array('Alnum', true, array(true)),
array('StringLength', true, array(0, 30))
),
'filters' => array('StringTrim'),
));
$this->addElement($name);
$name->setName('name');
// Radio элемент "Пол".
$sex = new Zend_Form_Element_Radio('sex', array(
'label' => 'Пол:',
'multiOptions'=> array('m' => 'Муж', 'f' => 'Жен'),
'validators' => array(array('InArray', true, array(array('m', 'f'), true)))
));
// Задаем разделитель пробел, для того что бы радио кнопки располагались в ряд
$sex->setSeparator(' ');
$this->addElement($sex);
// Элемент "Дата рождения". Элемент содержит нестандартный декоратор - javascript календарь
$dateBirth = new Zend_Form_Element_Text('date_birth', array(
'label' => 'Дата рождения:',
'maxlength' => '10',
'validators' => array(array('Date', true, array('dd.MM.yyyy'))),
'filters' => array('StringTrim'),
));
// Удаляем все существующие декораторы, назначенные по умолчанию
$dateBirth->clearDecorators();
// Назначаем новые, включая наш декоратор Calendar
// Это необходимо для того что бы изображение календаря размещалось сразу за полем ввода
$dateBirth
->addDecorator('ViewHelper')
->addDecorator('Calendar')
->addDecorator('Errors')
->addDecorator('HtmlTag', array('tag' => 'dd'))
->addDecorator('Label', array('tag' => 'dt'));
$this->addElement($dateBirth);
// Select элемент "Возраст".
$age = new Zend_Form_Element_Select('age', array(
'label' => 'Возраст:',
'multiOptions'=> array('', '11 - 20', '21 - 30', '31 - 40'),
'filters' => array('Int'),
));
$this->addElement($age);
// Textarea элемент "О себе"
$about = new Zend_Form_Element_Textarea('about', array(
'label' => 'О себе:',
'rows' => '5',
'cols' => '45',
'validators' => array(
array('StringLength', true, array(0, 5000))
),
'filters' => array('StringTrim'),
));
$this->addElement($about);
// Элемент CAPTCHA, защита от спама
$captcha = new Zend_Form_Element_Captcha('captcha', array(
'label' => "Введите символы:",
'captcha' => array(
'captcha' => 'Image', // Тип CAPTCHA
'wordLen' => 4, // Количество генерируемых символов
'width' => 260, // Ширина изображения
'timeout' => 120, // Время жизни сессии хранящей символы
'expiration'=> 300, // Время жизни изображения в файловой системе
'font' => Zend_Registry::get('config')->path->rootPublic . 'fonts/arial.ttf', // Путь к шрифту
'imgDir' => Zend_Registry::get('config')->path->rootPublic . 'images/captcha/', // Путь к изобр.
'imgUrl' => '/images/captcha/', // Адрес папки с изображениями
'gcFreq' => 5 // Частота вызова сборщика мусора
),
));
$this->addElement($captcha);
// Переопределяем сообщение об ошибке для валидатора NotEmpty
$validatorNotEmpty = new Zend_Validate_NotEmpty();
$validatorNotEmpty->setMessages(array(
Zend_Validate_NotEmpty::IS_EMPTY => 'agreeRules'));
// Checkbox элемент "Согласен с правилами".
$agreeRules = new Zend_Form_Element_Checkbox('agreeRules', array(
'required' => true,
'label' => 'Обещаю следовать правилам и любить отечество:',
'filters' => array('Int'),
'validators' => array($validatorNotEmpty),
));
$this->addElement($agreeRules);
// Кнопка Submit
$submit = new Zend_Form_Element_Submit('submit', array(
'label' => 'Зарегистрироваться',
));
$submit->setDecorators(array('ViewHelper'));
$this->addElement($submit);
// Кнопка Reset, возвращает форму в начальное состояние
$reset = new Zend_Form_Element_Reset('reset', array(
'label' => 'Очистить',
));
// Перезаписываем декораторы, что-бы выставить две кнопки в ряд
$reset->setDecorators(array('ViewHelper'));
$this->addElement($reset);
// Группируем элементы
// Группа полей связанных с авторизационными данными
$this->addDisplayGroup(
array('email', 'password', 'password_approve'), 'authDataGroup',
array(
'legend' => 'Авторизационные данные'
)
);
// Группа полей связанных с личной информацией
$this->addDisplayGroup(
array('name', 'last_name', 'sex', 'date_birth', 'age', 'about'), 'privateDataGroup',
array(
'legend' => 'Личная информация'
)
);
// Защита от спама
$this->addDisplayGroup(
array('captcha'), 'captchaGroup',
array(
'legend' => 'Будьте человеком!'
)
);
// Группа полей кнопок
$this->addDisplayGroup(
array('agreeRules', 'submit', 'reset'), 'buttonsGroup'
);
}
}
Zend_Form содержит все элементы, соответствующие реальным элементам html форм. Например, Zend_Form_Element_Text соответствует элементу <input type="text">. Сейчас Zend_Form поставляется вместе со следующими элементами: Button, Captcha, Checkbox, File, Hash, Hidden, Image, MultiCheckbox, Multiselect, Password, Radio, Reset, Select, Submit, Text, Textarea. Большая часть из них имеет html аналоги.
Элемент Hash позволяет защититься от CSRF (Cross-Site Request Forgery) атак. Данный тип атак направлен на имитирование запроса пользователя к стороннему сайту, другими словами, данные на ваш сайт пытаются передать не через форму на вашем сайте, а с помощью стороннего скрипта. Элемент Hash гарантирует, что запрос на вывод формы и запрос обработки данных формы будут использовать одинаковую пользовательскую сессию. Например, если заполнение какой-либо формы защищено авторизацией, злоумышленник не сможет отослать данные с помощью стороннего скрипта, не пройдя предварительно авторизацию.
Работа с элементами обычно происходит следующим образом:
1. Инициализация элемента. При этом нужно, как минимум, указать имя элемента.
$name = new Zend_Form_Element_Text("name");
2. Настройка элемента. Обычно при этом для элемента настраиваются: метка, значение, обязателен элемент или нет, валидаторы, фильтры, декораторы, атрибуты, специфические настройки элемента. Например, для элемента типа text настройка может выглядеть следующим образом:
// Метка
$name->setLabel('Имя:');
// Элемент обязателен
$name->setRequired(true);
// Значение элемента
$name->setValue('Инокентий');
// Валидатор Alnum - проверка на недопустимые символы,
$name->addValidator('Alnum', true, array(true));
// Валидатор StringLength - проверка длины,
$name->addValidator('StringLength', true, array(0, 30));
// Фильтр обрезающий пробелы по краям значения
$name->addFilter('StringTrim');
// Аттрибут maxlength со значением 30
$name->setAttrib('maxlength', 30);
Хочу отметить разницу между методами set+Параметр и add+Параметр. Рассмотрим, например, метку элемента. У текстового элемента не может быть несколько меток, поэтому Zend_Form предлагает единственный метод, устанавливающий это значение setLabel, при этом предыдущее значение (если оно было) будет затерто. Но есть параметры, которых может быть несколько. Например, валидаторы, одно значение можно проверять несколькими валидаторами, поэтому мы используем метод addValidator, при этом каждое значение добавляется к предыдущему, так образуется цепочка. Также существуют методы: addValidators – позволяет добавить сразу набор валидаторов, и метод setValidators который добавляет сразу набор валидаторов, но в отличии от addValidators удаляет все валидаторы что были заданы до этого. Подобная схема работает и в других подобных случаях (фильтры, декораторы).
3. Добавление. После настройки элемента его необходимо добавить в нашу форму:
$this->addElement($name);
Кроме описанного выше подхода Zend_Form предоставляет возможность задать параметры элемента сразу при создании объекта элемента, передав параметры в конструктор. Например, описанный выше текстовый элемент можно создать следующим образом:
$name = new Zend_Form_Element_Text('name', array(
'required' => true,
'label' => 'Имя:',
'value' => 'Инокентий',
'maxlength' => '30',
'validators' => array(
array('Alnum', true, array(true)),
array('StringLength', true, array(0, 30))
),
'filters' => array('StringTrim'),
));
$this->addElement($name);
Принцип обработки массива довольно простой, Zend_Form пробегает по циклу параметров, проверяет существование метода (set+Параметр), задающего определенный параметр, например, по ключу required проверяется метод setRequired; если метод существует, он вызывается, если же нет, то применяется метод setAttrib, задающий атрибут.
Альтернативным способом задания элементов является использование конфигурационных файлов и Zend_Config
Если вы используете один и тот же элемент в нескольких формах, разумно будет создать свой собственный элемент, это избавит вас от дублирования при настройке элемента. В нашем приложении мы создали собственный элемент – электронную почту:
class App_Form_Element_Email extends Zend_Form_Element_Text
{
public function init()
{
$this->setLabel('Электронная почта:');
$this->setAttrib('maxlength', 80);
$this->addValidator('EmailAddress', true);
$this->addValidator('NoDbRecordExists', true, array('users', 'email'));
$this->addFilter('StringTrim');
}
}
Так как электронная почта – это текстовое поле, то элемент является наследником Zend_Form_Element_Text. Далее мы сможем многократно использовать этот элемент в любых формах.
Необходимо также отметить, что Zend_Form генерирует верстку элементов формы в соответствии с заданным DocType объекта view, который использует Zend_Form.
Валидаторы позволяют проверять данные на соответствие определенным правилам. Zend Framework содержит компонент
Валидаторы можно использовать независимо, но чаще всего они используются в связке с Zend_Form. Следующий пример демонстрирует независимое использование валидаторов:
$validator = new Zend_Validate_EmailAddress();
if ($validator->isValid($email)) {
// email прошел валидацию
} else {
// email не прошел валидацию; вывод причин этого
foreach ($validator->getMessages() as $message) {
echo "$message\n";
}
}
Ключевой метод isValid непосредственно производит валидацию и возвращает результат, булевое значение.
Но, как я уже писал выше, гораздо удобнее использовать валидаторы совместно с Zend_Form. Валидаторы добавляются для элементов формы. Существует несколько методов для этого - addValidator(s) и setValidators, различие между этими методами я уже описывал выше.
С помощью нескольких валидаторов мы можем строить цепочки валидаторов, это удобно, когда мы хотим проверить значение сразу несколькими валидаторами. Объявление метода addValidator выглядит следующим образом:
addValidator($validator, $breakChainOnFailure = false, $options = array())
Параметр breakChainOnFailure позволяет прекратить проход по всей цепочке валидаторов, если один из валидаторов выдал отрицательный результат.
Например, в следующем коде мы строим цепочку из двух валидаторов, при этом, если первый валидатор определяет значение как не корректное, второй валидатор уже не будет выполнять проверку:
$name->addValidator('Alnum', true, array(true));
$name->addValidator('StringLength', true, array(0, 30));
Достаточно много задач можно решить с помощью стандартных валидаторов, но иногда приходится писать свои. В нашем приложении возникла необходимость в трех валидаторах, аналогов которых нет в стандартной поставке Zend_Validate. Рассмотрим создание валидаторов на примере валидатора пароля. В целом этот валидатор можно было бы заменить на стандартный Zend_Validate_Regex, но создание собственного валидатора позволит более гибко управлять им в будущем, ведь требования к паролю могут меняться.
Предположим, пароль может содержать любые символы из следующего набора: [email protected]#$%^&*()-_+=\/{}[].,?<>:;a-z0-9 и должен быть длинной от 6ти до 30ти символов.
Код валидатора пароля:
class App_Validate_Password extends Zend_Validate_Abstract
{
/**
* Метка ошибки
* @var const
*/
const INVALID = 'passwordInvalid';
/**
* Метка ошибки
* @var const
*/
const INVALID_LENGTH = 'passwordBadLength';
/**
* Текст ошибки
* @var array
*/
protected $_messageTemplates = array(
self::INVALID => 'Value does not appear to be a valid password',
self::INVALID_LENGTH => 'Value should have more than 6 and less then 30 symbols'
);
/**
* Проверка пароля
*
* @param string $value значение которое поддается валидации
*/
public function isValid($value)
{
// Благодаря этому методу значение будет автоматически подставлено в текст ошибки при необходимости
$this->_setValue($value);
// Валидатор проверки длины
$validatorStringLength = new Zend_Validate_StringLength(7, 30);
// Проверка на допустимые символы
if (!preg_match("/^[[email protected]#\\$%\\^&\\*\\(\\)\\-_\\+=\\\\\/\\{\\}\\[\\].,\\?<>:;a-z0-9]*$/i", $value)) {
// С помощью этого метода мы указываем какая именно ошибка произошла
$this->_error(self::INVALID);
return false;
}
elseif (!$validatorStringLength->isValid($value)) {
$this->_error(self::INVALID_LENGTH);
return false;
}
return true;
}
}
Итак, во первых, все наши валидаторы будут наследниками класса Zend_Validate_Abstract. Во вторых, минимальное, что нам нужно сделать, для того, чтобы наш валидатор был достаточно полноценным, это определить метод isValid и задать сообщения об ошибках. В этом примере мы имеем только два типа ошибок, поэтому мы создаем две константы с метками ошибок. Констант должно быть столько, сколько различных ошибок может иметь проверяемое значение.
Обычно валидаторы используются для проверки значения одного определенного поля. Но, иногда нам необходимо выполнить проверку, в которой участвуют сразу два поля, например для проверки совпадения пароля и его подтверждения. Для этих целей мы написали валидатор проверки совпадения двух строк, App_Validate_EqualInputs
И последний, созданный в статье, валидатор позволяет проверять отсутствие некоторой записи в таблице базы данных. Например, при регистрации мы должны быть уверены, что электронная почта, которую мы указываем, уникальна. Валидатор имеет имя App_Validate_NoDbRecordExists
Я не буду приводить здесь код этих валидаторов, чтобы не перегружать статью, вы можете скачать код и ознакомиться с ними, позже я выложу их в виде отдельной заметки
class App_Filter_Translit implements Zend_Filter_Interface
{
/**
* Производит фильтрацию в соответствии с назначением фильтра
*
* @param string $value
* @return string
*/
public function filter($value)
{
// Массив символов
$letters = array(
"а" => "a", "б" => "b", "в" => "v", "г" => "g", "д" => "d", "е" => "e",
"ё" => "e", "ж" => "zh", "з" => "z", "и" => "i", "й" => "j", "к" => "k",
"л" => "l", "м" => "m", "н" => "n", "о" => "o", "п" => "p", "р" => "r",
"с" => "s", "т" => "t", "у" => "u", "ф" => "f", "х" => "h", "ц" => "c",
"ч" => "ch", "ш" => "sh", "щ" => "sh", "ы" => "i", "ь" => "", "ъ" => "",
"э" => "e", "ю" => "yu", "я" => "ya",
"А" => "A", "Б" => "B", "В" => "V", "Г" => "G", "Д" => "D", "Е" => "E",
"Ё" => "E", "Ж" => "ZH", "З" => "Z", "И" => "I", "Й" => "J", "К" => "K",
"Л" => "L", "М" => "M", "Н" => "N", "О" => "O", "П" => "P", "Р" => "R",
"С" => "S", "Т" => "T", "У" => "U", "Ф" => "F", "Х" => "H", "Ц" => "C",
"Ч" => "CH", "Ш" => "SH", "Щ" => "SH", "Ы" => "I", "Ь" => "", "Ъ" => "",
"Э" => "E", "Ю" => "YU", "Я" => "YA",
);
// Проходим по массиву и заменяем каждый символ фильтруемого значения
foreach($letters as $letterVal => $letterKey) {
$value = str_replace($letterVal, $letterKey, $value);
}
return $value;
}
}
Минимальное, что должен сделать наш фильтр – это реализовать интерфейс Zend_Filter_Interface и определить метод filter.
Достаточно много затруднений при работе с Zend_Form у разработчиков вызывают декораторы. На самом деле, совершенно не обязательно выводить форму (вы можете не использовать метод render()). Но, если же вы решите это сделать, то декораторы будут использоваться для формирования html кода различных составляющих формы.
Если выражаться по-простому, то декораторы отвечают за html код формы и ее составляющих. От декораторов зависит, в каком теге будет выведена метка поля, какие теги будут обрамлять элементы и метки и т д.
Произвольное число декораторов может быть применено к любой составляющей формы (элементы, визуальные группы, вложенные формы или сам объект формы). Декораторы вызываются в том же порядке, в котором они регистрируются. Декоратор может заменять содержимое, переданное ему или добавлять что-либо после или перед содержимым.
Я не буду подробно останавливаться на декораторах, так как, помимо
Регистрация декораторов происходит с помощью методов addDecorator(s) и setDecorators. По умолчанию для различных составляющих формы регистрируется набор стандартных декораторов. Если мы хотим этого избежать, при создании элемента необходимо указать параметр disableLoadDefaultDecorators.
Например, загрузка декораторов по умолчанию для элементов формы выглядит следующим образом:
$this->addDecorator('ViewHelper')
->addDecorator('Errors')
->addDecorator('Description', array('tag' => 'p', 'class' => 'description'))
->addDecorator('HtmlTag', array('tag' => 'dd'))
->addDecorator('Label', array('tag' => 'dt'));
Эти декораторы используются чаще всего. ViewHelper формирует непосредственно html код элемента (например <input type="text">). Errors добавляет html код в котором, будут выводиться ошибки формы. Description позволяет задавать описание элемента, HtmlTag обрамляет содержимое указанным тегом, в данном случае dd. И, наконец, декоратор Label обрамляет метку элемента указанным тегом, в данном случае dt.
Манипулируя декораторами, можно добиться практически любого html кода формы. Для сброса назначенных декораторов используется метод clearDecorators(). Итак, предположим, что стандартный набор декораторов какого-либо элемента нас не удовлетворяет. В таком случае мы сбрасываем стандартный набор и прописываем свои. Рассмотрим это на примере.
В форме регистрации нам необходимо, чтобы дату рождения можно было выбирать с помощью javascript календаря. Но для работы с javascript календарем нам необходимо подключить его и настроить. Для этого мы создадим свой декоратор App_Form_Decorator_Calendar, его код мы разместим в файле library/App/Form/Decorator/Calendar:
class App_Form_Decorator_Calendar extends Zend_Form_Decorator_Abstract
{
/**
* Получение строк подключения Javacript и CSS для календаря
* Статическая переменная $jsAndCss отвечает за то, чтобу подключение
* осуществлялось только один раз
*
* @return string
*/
private function _getJsAndCss()
{
static $jsAndCss = null;
if($jsAndCss === null) {
$jsAndCss = '
<style type="text/css">@import url(/js/calendar/skins/aqua/theme.css);</style>
<script type="text/javascript" src="/js/calendar/calendar.js"></script>
<script type="text/javascript" src="/js/calendar/lang/calendar-ru.js"></script>
<script type="text/javascript" src="/js/calendar/calendar-setup.js"></script>
';
return $jsAndCss;
}
return '';
}
/**
* Получение кода ссылки и изображения каледаря. Настройка календаря
*
* @return string
*/
private function _getCalendarLink()
{
$calendarLink = '
<a href="#" id="' . $this->getElement()->getName() . '_calendar">
<img class="calendar-image" src = "/js/calendar/calendar.gif">
</a>
<script type="text/javascript">
Calendar.setup(
{
inputField : "' . $this->getElement()->getName() . '",
ifFormat : "%d.%m.%Y",
button : "' . $this->getElement()->getName() . '_calendar",
firstDay : 1
}
);
</script>
';
return $calendarLink;
}
/**
* Рендеринг декоратора
*
* @param string $content
* @return string
*/
public function render($content)
{
// Получаем объект элемента к которому применяется декоратор
$element = $this->getElement();
if (!$element instanceof Zend_Form_Element) {
return $content;
}
// Проверяем объект вида зарегистрированного для формы
if (null === $element->getView()) {
return $content;
}
// Расположение декоратора, "после" или "перед" элементом, по умолчанию "после"
$placement = $this->getPlacement();
// Разделитель между элементом и декоратором
$separator = $this->getSeparator();
// Взависимости от настроек расположения декоратора возвращаем содержимое
switch ($placement) {
// После элемента
case 'APPEND':
return $this->_getJsAndCss() . $content . $separator . $this->_getCalendarLink();
// Перед элементом
case 'PREPEND':
return $this->_getJsAndCss() . $this->_getCalendarLink() . $separator . $content;
case null:
// По умолчанию просто возвращаем содержимое календаря
default:
return $this->_getJsAndCss() . $this->_getCalendarLink();
}
}
}
Наши декораторы будут наследниками класса Zend_Form_Decorator_Abstract и должны реализовать метод render(). Как видно из кода, javascript, отвечающий за загрузку, просто присоединяется к предыдущему содержимому, причем, в зависимости от настроек до или после содержимого.
Теперь нам необходимо «пересобрать» декораторы, потому что мы не можем просто добавить наш декоратор Calendar к стандартному набору. Нам необходимо, чтобы календарь был сразу после тега input, этого мы добиваемся следующим кодом:
$dateBirth->clearDecorators();
$dateBirth
->addDecorator('ViewHelper')
->addDecorator('Calendar')
->addDecorator('Errors')
->addDecorator('HtmlTag', array('tag' => 'dd'))
->addDecorator('Label', array('tag' => 'dt'));
CAPTCHA - это технология, созданная для отличия человека от программы. На современных сайтах данная технология используется для защиты от спама. Пользователю предлагается решить задачу, с которой легко справляется человек, в отличии от программы. Самая распространенная реализация такого алгоритма - это генерация зашумленного изображения с символами. Пользователю предлагается ввести данные символы, именно задача распознавания изображений является достаточно ресурсоемкой и тяжелой для программы.
- Word
- Dumb
- Figlet
- Image
- ReCaptcha
Адаптер Word является абстрактным, от него наследуются все, кроме ReCaptcha. Адаптер Dumb генерирует строку, которая должна быть вписана в обратном порядке, Figlet генерирует строку с помощью псевдографики, Image - зашумленное изображение, а ReCaptcha использует Zend_Service_ReCaptcha. Подробнее с технологией ReCaptcha вы можете ознакомиться на
Работа с компонентом Zend_Captcha происходит в два шага. Первый - это генерация и отображение условий задачи, второй - это проверка данных, введенных пользователем на предмет решения предложенной задачи.
Например, код для работы с адаптером Figlet может выглядеть следующим образом:
// Создание объекта вида
$view = new Zend_View();
// Настройка параметров
$captcha = new Zend_Captcha_Figlet(array(
'name' => 'foo',
'wordLen' => 6,
'timeout' => 300,
));
// Генерация символов и вывод
$id = $captcha->generate();
echo $captcha->render($view);
Проверка данных введенных пользователем или программой:
if ($captcha->isValid($_POST['foo'], $_POST)) {
// Validated!
}
Мы будем использовать самый распространенный вариант CAPTCHA – генерацию зашумленного изображения с символами. Для этого нам понадобится три вещи: компонент Zend_Captcha, расширение GD, скомпилированное с поддержкой TrueType или Freetype и файл шрифта.
Zend_Captcha_Image генерирует PNG изображения, хранящиеся, на вашей файловой системе. Периодически при генерации запускается сборщик мусора и удаляет старые файлы изображений.
Есть несколько основных параметров, которые можно настраивать для нашего адаптера:
- Timeout - Время жизни сессии, содержащей сгенерированную строку символов
- WordLen – Количество генерируемых символов
- Expiration – Время жизни файла изображения, хранящегося в файловой системе
- GcFreq – Параметр, отвечающий за частоту запуска сборщика мусора. Сборщик будет запускаться каждый 1/$gcFreq вызов. По умолчанию GcFreq = 100. Очевидно, что если выставить этот параметр в 1, то сборщик будет запускаться при каждой новой генерации изображения.
- Font – Путь к файлу шрифта
- ImgDir – Физический путь к папке, где хранятся изображения
- ImgUrl – URL папки, где хранятся изображения
Есть еще параметры FontSize, Height, Width, отвечающие за размер шрифта, высоту и ширину изображения соответственно. Каждый из этих параметров можно либо передать в виде опции в конструктор (как показано на примере адаптера Figlet выше), либо задать методом с названием set+Имяпараметра, например setWordLen().
Чаще всего CAPTCHA используется при заполнении форм. Zend Framework уже позаботился о нас и предлагает использовать Zend_Form_Element_Captcha, который всю черную работу по генерации, выводу и проверке он сделает сам, нам же останется только настроить его:
$captcha = new Zend_Form_Element_Captcha('captcha', array(
'label' => "Введите символы:",
'captcha' => array(
'captcha' => 'Image', // Тип CAPTCHA
'wordLen' => 4,
'width' => 260,
'timeout' => 120,
'expiration'=> 300,
'font' => Zend_Registry::get('config')->path->rootPublic . 'fonts/arial.ttf',
'imgDir' => Zend_Registry::get('config')->path->rootPublic . 'images/captcha/',
'imgUrl' => '/images/captcha/',
'gcFreq' => 5
),
));
Полученное изображение будет выглядеть примерно следующим образом:

Для CAPTCHA мы выделим отдельную визуальную группу.
Zend_Form предоставляет возможность группировать элементы форм в визуальные группы. Как я уже писал выше, обычно это объединение происходит с помощью тега fieldset. Например, следующим кодом мы создаем группу «Авторизационные данные»:
$this->addDisplayGroup(
array('email', 'password', 'password_approve'), 'authDataGroup',
array(
'legend' => 'Авторизационные данные'
)
);
Здесь первый массив содержит набор элементов группы, далее идет имя группы и настройки. Название группы попадает в тег legend по умолчанию. Элементы группы будут выведены в том порядке, в котором они заданы.
Стандартные, поставляемые с Zend_Validate, валидаторы, содержат сообщения об ошибках на английском языке. Резонно, что мы хотим, чтобы наши ошибки отображались на русском. Кроме этого, мы можем захотеть изменить текст некоторых ошибок, чтобы он был приближен к нашему приложению. Для всего этого нам понадобится компонент Zend_Translate. Zend_Translate имеет возможность работать с несколькими адаптерами. Адаптеры – это, грубо говоря, хранилища, в которых мы будем держать наши переводы.
Так как на текущем этапе мы еще не создаем полнофункционального многоязычного приложения, то нам вполне подойдет адаптер в виде php массива, ведь это еще и самый быстрый адаптер. Настройку переводчика мы проведем в файле library/App/Form.php в методе init() класса App_Form
Итак, создаем экземпляр Zend_Translate, указываем тип адаптера и путь к нему
$translator = new Zend_Translate('array', Zend_Registry::get('config')->path->languages . 'errors.php');
Выдержка из адаптера выглядит следующим образом:
Zend_Validate_Int::NOT_INT => 'Значение не является целочисленным значением',
Zend_Validate_NotEmpty::IS_EMPTY => 'Поле не может быть пустым',
Zend_Validate_StringLength::TOO_SHORT => 'Длина введённого значения меньше чем %min% символов',
Zend_Validate_StringLength::TOO_LONG => 'Длина введённого значения больше чем %max% символов',
App_Validate_EqualInputs::NOT_EQUAL => 'Пароли не совпадают',
Как можно заметить, ключи массива совпадают с константами ошибок, которые мы рассматривали в разделе работы с валидаторами. Именно за счет этого достигается перевод сообщений об ошибках.
Теперь нам останется только сообщить нашей форме о «переводчике»
$this->setTranslator($translator);
Как следует поступить, если для определенного элемента мы хотим задать особое сообщение. Например, у нас есть чекбокс, отвечающий за согласие с правилами. Если мы оставим все как есть, то в случае невыставления чекбокса, мы получим текст ошибки - «Поле не может быть пустым». Это не так красиво, как, например, текст «Регистрируясь, вы должны согласиться с правилами». Но ведь мы уже перевели константу:
Zend_Validate_NotEmpty::IS_EMPTY => 'Поле не может быть пустым',
Для переопределения этого значения нам нужен следующий код отвечающий за чекбокс:
// Переопределяем сообщение об ошибке для валидатора NotEmpty
$validatorNotEmpty = new Zend_Validate_NotEmpty();
$validatorNotEmpty->setMessages(array(
Zend_Validate_NotEmpty::IS_EMPTY => 'agreeRules'));
// Checkbox элемент "Согласен с правилами".
$agreeRules = new Zend_Form_Element_Checkbox('agreeRules', array(
'required' => true,
'label' => 'Обещаю следовать правилам и любить отечество:',
'filters' => array('Int'),
'validators' => array($validatorNotEmpty),
));
Таким образом, мы добавим в наш адаптер перевод для ключа agreeRules и добьемся желаемого результата.
Итак, мы создали форму, нам нужно вывести ее на экран. Теперь мы начнем наполнять наше пустое действие registerAction контроллера AuthController. Запишем туда следующий код:
// Инициализируем форму регистрации
$formRegister = new Form_Register();
// Передаем форму в скрипт вида
$this->view->formRegister = $formRegister;
Таким образом, объект формы станет доступным в скрипте вида application/views/scripts/auth/register.tpl. Нам остается лишь ее вывести:
<?php echo $this->formRegister ?>
Не правда ли, просто? Ведь все настройки собраны в нашем объекте App_Form_Register и нам не пришлось писать практически ни одной строчки html кода. Однако, такая простота имеет и обратную сторону. У нас возникает проблема настройки внешнего вида формы, точнее, эта проблема возникает у верстальщика. Ведь раньше он мог внести правки путем изменения только шаблона, а теперь он будет вынужден модифицировать декораторы или обращаться к программисту.
Возможным решением проблемы может быть отображение вашей формы поэлементно, для этого вам необходимо обращаться к элементам формы следующим образом:
<?php echo $this->form->element; ?>
Где element - это имя элемента формы. Таким образом, верстальщик сможет вставлять html код между элементами и менять их местами. Но, таким образом, вы все равно не сможете, например, в шаблоне(скрипте вида) указать css класс для определенного элемента формы. Еще одним, более "гибким" вариантом вывода формы, может быть использование помощников вида (FormLabel, FormText и другие). Можно пойти еще дальше и выводить элементы следующим образом:
<?php echo $this->formRegister->name->getLabel(); ?>
<input
type="text"
name="<?php echo $this->formRegister->name->getName(); ?>"
value="<?php echo $this->formRegister->name->getValue(); ?>"
maxlength="<?php echo $this->formRegister->name->getAttrib('maxlength'); ?>"
/>
Здесь я вывел элемент «Имя» из нашей формы регистрации. Таким образом, мы можем добиться полной настройки внешнего вида форм из шаблона. Правда, в таком случае вам еще прийдется самим позаботиться о выводе ошибок. Лично я рекомендую использовать подобную практику лишь в особых случаях, а, по возможности, сразу договариваться с верстальщиком и настраивать внешний вид формы через декораторы; это избавит вас от массы лишнего кода.
Также обратите внимание на декоратор ViewScript, он позволяет указывать для формы определенный скрипт вида.
Кроме того, в руках у верстальщика есть еще CSS. В следующем разделе вы убедитесь, что достаточно симпатичный внешний вид формы можно создать, используя лишь CSS и стандартные декораторы. Итак, повтороюсь: Zend_Form не навязывает обязательное использование декораторов, вы можете использовать свой вариант вывода формы, при этом, не теряя все остальные прелести Zend_Form. Поэтому не стоит отказываться от Zend_Form только потому, что вам не нравятся декораторы.
Для настройки внешнего вида формы был использован следующий css код:
form.register dt, dd{padding:2px;}
form.register label {color:#3E4E68}
form.register label.required {font-weight:bold}
form.register dd{padding-bottom:10px;}
form.register fieldset{margin-left:-60px;width:450px;padding:10px;border:1px solid #A3B1C9}
form.register fieldset legend{color:#3E4E68;font-size:1.4em;}
form.register #captcha-input{margin-top:5px;}
form.register ul.errors {color:red}
form.register #fieldset-buttonsGroup{border:0px;}
В результате мы получили такую форму:

С еще одним примером оформления формы использующей стандартные декораторы вы можете найти по
Мы рассмотрели все, что необходимо для генерации формы. Как же происходит обработка данных после нажатия кнопки submit. Доработаем код действия registerAction контроллера AuthController:
public function registerAction()
{
// Инициализируем форму регистрации
$formRegister = new Form_Register();
// Проверяем типа запроса, если POST значит пришли данные формы
if ($this->_request->isPost()) {
// Проверяем на валидность поля формы
if ($formRegister->isValid($this->_getAllParams())) {
// Инициализируем объект отвечающий за таблицу пользователей
$tableUsers = new DbTable_Users();
// Формируем масив для вставки в базу данных
// Пароль преобразовываем в sha1 хеш добавляя "соль" для безопасности
$userData = array(
'email' => $formRegister->getValue('email'),
'password' => sha1($formRegister->getValue('password') . 'jdh37dgvs'),
'name' => $formRegister->getValue('name'),
'sex' => $formRegister->getValue('sex'),
'date_birth' => $formRegister->getValue('date_birth'),
'age' => $formRegister->getValue('age'),
'about' => $formRegister->getValue('about'),
);
// Вставляем данные в базу данных
$tableUsers->insert($userData);
// Задаем сообщение о успешной регистрации
$this->_helper->FlashMessenger->setNamespace('messages')->addMessage('Поздравляем с успешной рег-ей');
// Перенаправление на главную страницу
$this->_helper->redirector->gotoRoute(array(), 'default');
}
}
// Передаем форму в скрипт вида
$this->view->formRegister = $formRegister;
}
Алгоритм обработки достаточно прост: мы проверяем тип запроса страницы, если это POST, то вызываем функцию валидации формы isValid. Если данные не содержат ошибок, мы добавляем нового пользователя в базу данных, в противном случае отображаем форму и сообщения об ошибках.
Если данные были успешно добавлены в базу, логично сообщить об этом пользователю каким-нибудь красивым сообщением, вроде «Поздравляем с успешной регистрацией». Для этих целей в Zend Framework есть специальный помощник действий –
После добавления сообщения мы выполняем перенаправление с помощью помощника действий redirector.
Таким образом, нам осталось отобразить сообщение на экран. Для этого мы создадим
Таблица пользователей, с которой мы работали в прошлой части туториала, расширилась, теперь она состоит из следующих полей:
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(80) NOT NULL,
`password` varchar(80) NOT NULL,
`name` varchar(30) NOT NULL,
`name_translit` varchar(50) NOT NULL,
`sex` enum('m','f') DEFAULT NULL,
`date_birth` date DEFAULT NULL,
`age` tinyint(4) DEFAULT NULL,
`about` text,
Все поля, кроме id и name_translit, имеют аналогичные поля в форме регистрации, причем имена полей и имена элементов формы совпадают. Это удобно при вставке или изменении данных в базе, а также для заполнения значений формы данными из базы с помощью функции populate() (обратите на нее внимание). Поле name_translit введено для демонстрации работы фильтра, переводящего строку в транслит. То есть, в этом поле хранится имя, написанное транслитом.
Для добавления данных в базу создадим новую модель DbTable_Users, она будет отвечать за работу с таблицей пользователей. Определим в ней метод insert:
public function insert($userData)
{
// Создаем объект фильтра
$filterTranslit = new App_Filter_Translit();
// Производим транслитерацию имени
$userData['name_translit'] = $filterTranslit->filter($userData['name']);
// Приводим дату к формату Mysql
if ($userData['date_birth'] != '') {
$dateBirth = new Zend_Date($userData['date_birth'], 'dd.MM.yyyy');
$userData['date_birth'] = $dateBirth->toString('yyyy-MM-dd');
}
else {
$userData['date_birth'] = null;
}
// Вызываем родительский метод вставки в базу данных
parent::insert($userData);
return true;
}
Как вы можете увидеть, в коде мы производим некоторые манипуляции перед вставкой в базу данных, это - транслитерации имени и перевод даты в формат, понятный для СУБД Mysql. Для этого мы используем компонент
Zend_Date позволяет производить форматированный вывод даты, в соответствии с временной зоной и локалью. Кроме этого, позволяет добавлять, отнимать и сравнивать даты, а также многое другое. Мы используем этот компонент для перевода даты из формата, пришедшего с формы, в формат, понятный для Mysql. Для этого мы сначала создаем объект Zend_Date, передавая ему, в качестве параметров, значение даты и формат в котором она содержится. Далее мы используем метод toString для создания строки в нужном формате.
После выполнения всех действий мы хотим отобразить сообщения об успешных результатах. Для этого нам необходимо получить эти сообщения и передать в объект вида для отображения. Мы не хотим делать это вручную в каждом действии, где это может понадобиться, поэтому мы создадим front контроллер плагин, который будет перехватывать событие postDispatch (Момент окончания этапа диспетчеризации):
class App_Controller_Plugin_FlashMessenger extends Zend_Controller_Plugin_Abstract
{
public function postDispatch(Zend_Controller_Request_Abstract $request)
{
// Инициализируем помощник FlashMessenger и получаем сообщения
$actionHelperFlashMessenger = new Zend_Controller_Action_Helper_FlashMessenger();
$messagesSuccess = $actionHelperFlashMessenger->setNamespace('messages')->getMessages();
// Если сообщений нет, или процес диспетчеризации не закончен успешно, просто выходим из плагина
if (empty($messagesSuccess) || !$request->isDispatched()) {
return;
}
// Получаем объект Zend_Layout
$layout = Zend_Layout::getMvcInstance();
// Получаем объект вида
$view = $layout->getView();
// Добавляем переменную для вида
$view->messages = $messagesSuccess;
// Устанавливаем объект вида с новыми переменным и производим рендеринг скрипта вида в сегмент messages
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$viewRenderer
->setView($view)
->renderScript('messages.tpl', 'messages')
;
}
}
Далее нам необходимо создать скрипт вида messages.tpl, в котором собственно и будет происходить вывод сообщений об ошибках. Мы расположим его в папке application/views/. Этот скрипт имеет следующий код:
<div class="success">
<?php foreach ($this->messages as $message) : ?>
<p> <?php echo $message; ?> </p>
<?php endforeach;?>
</div>
Так как мы произвели рендеринг скрипта вида в сегмент messages, то, добавив в главном макете layout.tpl следующий код:
<?php echo $this->layout()->messages; ?>
мы добьемся необходимого результата.
И, в завершение, нужно не забыть зарегистрировать наш плагин в front контроллере:
$front->registerPlugin(new App_Controller_Plugin_FlashMessenger())
Скачать код с библиотеками Zend вы можете по ссылке (2.3 мб), без библиотек по ссылке (351 Кб)
Для установки скрипта вам будет необходимо выполнить действия, аналогичные к действиями в части 1. Посмотреть скрипт в работе можно по ссылке.
Выражаю благодарность Александру Стешенку за помощь при написании статьи.
В следующей части серии статей основной упор планируется сделать на идентификацию и аутентификацию с помощью компонент Zend_Auth, Zend_Acl, Zend_Session.
P.S. Вышеизложенная информация это не свод инструкций, это в первую очередь информация для размышления, не забывайте что у вас своя голова на плечах.
P.P.S. Для обсуждения статьи я создал тему на форуме. Если вы хотите обсудить код, или выразить объемное мнение, пожалуйста пишите в эту тему. Механизм комментариев пока плохо приспособлен для объемного полноценного обсуждения с кодом.
- Спрашивать почему у вас не работает код, для этого есть тема форума закрепленная за статьей.
- Спрашивать как реализовать ту или иную функциональность, для этого необходимо создать свою тему на форуме.
Комментарии для того чтобы: высказать свое аргументированное мнение о статье, указать какие участки вызывают непонимание, что нужно исправить/улучшить, просто сказать спасибо.
Комментарии имеют древовидную структуру.
Если вы хотите ответить на определенный комментарий - нажмите на ссылку "Ответить" возле этого комментария.