Pull to refresh

Comments 75

Да, работать с Zend_Form одно удовольствие. Спасибо.
Ничуть не умаляя возможностей Zend (и даже в чем-то преклоняюсь), но логика вида
Если у Вас поле типа VARCHAR(255), то ограничьте поле ввода 255 символами, и Вам не придется пользоваться функциями обрезания строк.

неправильная.
«Первое» правило безопасного веб-приложения гласит: «ВСЕГДА фильтруйте пользовательский ввод».
В данном случае «псевдохакеру» не составит труда передать переменную ровно той длины, которая ему нужна.
При этом если вы ее не будете фильтровать в обработчике, то рискуете получить много проблем.

За статью спасибо, заставила задуматься о некоторых вещах.
передать то хакер сможет, а вот валидатор как раз при проверке и заругается что пришло слишком длинное поле, и данные в БД не попадут…

>При этом если вы ее не будете фильтровать в обработчике, то рискуете получить много проблем.
так а Zend_Form это и есть обработчик в данном случае, валидация то отрабатывает на стороне сервера
Ну если все так, то это хорошо. Мне просто почему-то показалось, что это типа добавления к полю ограничения maxlength=«255» с соответствующим выводом на экран сообщения об ошибке.
А если дописать к нему автогенерацию форм на основе метаинформации из БД, то Zend_Form становится «золотым» компонентом!
а есть ли менее многословный способ описания формы? типа:
$form->add( new Zend_Form_Element_Text('username', 'Username', 'required minlen:3 regex:^[a-zA-Z0-9]+' ) );
Валидаторы/фильтры синтаксически сократить нельзя, но в целом создание формы можно писать короче, без явного применения оператора new

        $form->addElements(array(
            array ('text', 'email', array (
                'label'         =>  'E-mail',
                'required'      =>  false,
                'filters'       =>  array(
                    'StringTrim'
                ),    
                'validators'    =>  array(
                    'EmailAddress'
                )
            ))
        ));
я описание всех форм храню в YAML; выходит что-то вроде:

fetchpassword:
  _extends: base
  action: /account/password/fetch
  method: post
  elements:
    email:
      type: text
      options:
        label: 'E-mail:'
        required: '1'
        validators: [ { validator: EmailAddress } ]
        attribs: { tabIndex: '1', maxLength: '320' }
    requestPassword:
      type: submit
      options:
        label: 'Request Password'
        attribs: { tabIndex: '2' }
        decorators: [ { decorator: ViewHelper } ]


(извиняюсь, предыдущий случайно отправил)
Маленький вопрос:
Что значит вторая строчка: _extends: base?
Где почитать?
почему в zend_form нет такой простой вещи, как возможность задать определенный класс невалидному инпуту?
Как минимум потому, что Элемент формы != Инпут.
В общем случае элементом формы может быть любая конструкция HTML. (Например: 3 селекта для выбора даты, и hidden input для придуманных дизайнерами чекбоксов).
Но есть декоратор error. Встроенная его версия — добавляет список ошибок рядом с элементом формы. Ничто не мешет заменить его на свой декоратор, который помимо этого будет оборачивать сам элемент формы в с каким-либо классом
При передаче деталей типа элементы и валидаторы лучше писать el->setName('dsa')->setRequired(tru),
точбы не ошибаться потом.

А то как в 1970-х годах — без code-completeion`а с этими массивами.
Все в зендовых формах хорошо, до тех пор пока не начинаешь писать действительно сложные формы с динамическим количеством полей, связей многие ко многим у которых кроме самой связи присутствует целый ворох полей данных.
Мы в таком случае переопределяли колбэки декораторов элементов формы на свои собственные. А какие-то динамические вещи вешали на jQuery.
Недавно взялся за изучение Zend Framework, лучшее вступление — это статья Rob Allen-а Getting Started with Zend Framework И вот там я тоже читал про формы и был там пример с двумя submit буттонами с одинаковым именем. Автор реализует эту форму вручную, ссылаясь на ее простоту. Но я попробовал и ее сделать на Zend Framework. И знаете что? В Zend Framework нельзя создать два элемента с одинаковым именем. Речь идет не о параметре, передаваемом конструктору элемента и его идентифицирующем, а о самом html аттрибуте name="". Я потратил минут двадцать, чтоб разобраться как же быть )
Забыли о стандартах. Такая запись не разрешена.
А вы случайно не мне ответили? Если мне, то я всегда считал, что значение аттрибута id должно быть всегда уникально, а имя может повторяться.
Нет. Парсер съел теги.
Цитата:
Парсер не пощадил никого.
Это всё речь о строке кода из «Скрипты представления и декораторы»
Если спросить меня, какой самый плохой компонент в Zend Framework, я отвечу: формы. Это ужасающее, душераздирающее нарушение MVC. Смешение, столпотворение и каша.
Категорически согласен. Валидация данных должна происходить в модели, а не в форме. Например, как в Ruby ActiveRecord.

Насчет декораторов в Zend_Form — считаю их ужасной вещью. В больших формах очень сложно разобраться, особенно новичкам. Синтаксис php этому явно не способствует. В языках, в которых можно легко писать в стиле DSL, декораторы куда более к месту.
а чем плох сугубо сишный синтаксис? к чему эти глупые отмазки типа синтаксис пхп плох а я не умею управляться со сложными формами?
если все сделать правильно, то выходят очень даже понятные и симпатичные формы (в плане кода), если хорошо почитать мануал, они уже не кажутся такими жуткими и страшными, другое дело если сразу не разобравшись лезешь в бой, тогда конечно много будет казаться глупым…
кстати формы в зенде задуманы как модели, просто используют свои виды + декораторы
формы — модели, они занимаются валидацией и обработкой данных пришедших извне, используют свой вью для рендера, что плохого? без них вы всеравно сделаете модель для валидации данных, и в шаблон напихаете HTML кода… выйдет тот же результат, но не такой гибкий
Форма по самой своей природе является контроллером. В этом легко убедиться, записав форму без использования Zend_Form. Вынести в отдельный компонент захочется код, расположенный в SomeController::someAction.

Захочется вынести и HTML-код представления формы и её элементов. Но это уровень представления, а не контроллера и не модели. Для этого нужно сделать отдельный слой компонентов (похожих на зэндовские форм-декораторы), который будет привязываться к форме на уровне представления.
впервые слышу чтоб контроллер по своей природе группировал элементы, проводил валидацию, обрабатывал данные… это Вам в зенде сказали что форма — контроллер?
Можете начать хотя бы с «Википедии», русской и английской. Узнаете много нового. Потом приступайте к чтению серьёзной литературы.
отличный аргумент: сам я сказать ничего не могу, так что идите читайте википедию
Какой аргумент? У Вас отсутствуют знания о базовых принципах архитектуры MVC («впервые слышите»). Я предлагаю Вам восполнить этот проблем и рекомендую, с чего начать.
Пробел восполнить, конечно же.
ну естественно у меня не хватает знаний… могу лишь сказать что принципов MVC несть несколько и тот что использует зенд — один из нескольких, есть так же принцип C -> M -> V (именно в такой последовательности) поэтому если класс общается напрямую с видом, не значит что он контроллер, в идеале изначально у формы была такая структура:
элемент1…
элемент2…
форма — добавить элемент1
форма — добавить элемент2
затем форма их обрабатывает (контроллер обрабатывает данные полученные из вне? что-то мне подсказывает что только подгатавливает их для обработки)
форма так же производит проверку введенных данных (неужели этми контроллер занимается?)
и форма к тому-же возвращает результат обработки… опять же, конечно же этим занимается контроллер…
еще учтите, что форма — не MVC, форма — MV… это так, для общего развития
Форма в том виде, в котором она представлена в Zend_Form, — это CV. И это очень плохо, как и MV, как и MC, как и любое другое смешение. M, V и C все должны быть строго отдельно, а как они взаимодействуют, уже дело другое.

Сделать форму как отдельную область контролирования; отдельно сделать набор вью-хэлперов или тех же декораторов как отдельную область представления — так я вижу формы.
сама форма — модель, она не делает ни одного действия что должен делать контроллер, вид для нее находится отдельно — декораторы, по сути это некий симбиоз, так вот сама форма — хорошо, а сам симбиоз модели и вида это уже другой разговор, лично меня такой подход устраивает, так как разделяли вид от кода для того чтоб в хтмл не было тех же контроллеров и моделей, в данном случае их там нет, декораторы отрабатывают отдельно от всего остального и код от них не зависит
Форма — это НЕ модель. Zend_Form делает строго то, что без неё делают контроллер и представление.

Ещё раз повторяю, запишите форму без использования Zend_Form — увидите сами.

Хорошо, сделаю это за вас.

Простейший пример: форма редактирования имени контакта.

Контроллер:
public function editAction() {
    $contact = Contact::find($this->_request->id);
    if (empty($contact)) {
        throw new PageException_NotFound();
    }
    $errors = array();
    if ($this->_request->isPost()) {
        if (mb_strlen($this->_request->name) < 5) {
            $errors []= "Имя должно быть длиннее 4 символов";
        }
        if (empty($errors)) {
            $contact->setName($this->_request->name);
            $this->_redirect(self::getUrl($contact));
        }
    }
    $this->view->errors = $errors;
    $this->view->contact = $contact;
}


Представление:
<form action="" method="post">
    <p>
        <input type="text" name="name"
            value="<?= $this->escape($this->contact->getName()) ?>" />
        <button type="submit">Сохранить</button>
    </p>
</form>

public function editAction()
{
    $error = null;
    if( $this->_request->isPost() )
    {
        if( $model->isValidData($this->_request->getPost()) )
        {
            // store data
        }
        else
        {
            $errors = $model->getErrors();
        }
    }
    $this->view->error = $error;
}
так делал, и так буду делать, никаких проверок в контроллере, только подготовка данных
Валидацию можно сделать ответственностью модели, но совершенно не в той форме, в которой Вы предлагаете.

Можно сделать, чтобы сэттеры при передаче им некорректных данных выбрасывали исключение. Которое отлавливать в контроллере и информировать представление.

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

Поэтому делать валидацию данных ответственностью модели не следует, а вместо этого следует поручить это контроллеру, который и будет это контролировать.
$model->isValidData($this->_request->getPost())

Очень грубая ошибка.

Попробуйте всё-таки почитать «Википедию».
не думайте что вы самый умный, самомнение портит человека, это был пример а не реальная модель, проверка не должна быть в контроллере, а если у меня форма из 50 полей (были и больше, генерились динамически) вы все будете проверять в контроллере? вот это очень грубая ошибка
Конечно же, это должен делать контроллер. Я сделаю форму, в которой укажу эти 50 полей и назначу им валидаторы.
кроме mvc есть великий и могучий принципы DRY и KISS. Вы пытаетесь один в один перетащить гуишный паттерн в вэбразработку :).
совету понимать mvc как «разделяй и властвуй» + «каждый занимается свои делом»
Я не против того, чтобы делать «худые» контроллеры, возлагая почти всю логику на модели (хотя к тому есть практические возражения, некоторые из которых я изложил выше).

Но я категорически против смешивания логики (моделирующей ли, контролирующей ли) с представлением — что и является главным грехом Zend_Form.
вопросы

1) каким образом можно указать дополнительные элементы
[label][/label][input /][span]required[/span]
[label][/label][input /][span]required[/span][i]Ex: 1-XXX-200[/i]
[input type=«radio» /][label class=«radio»][/label]

и тд.

2) каким образом задается вывод результатов проверок

3) каким образом можно задать свою проверку, которая не покрывается стандартными

4) на сколько больше кода потребуется на 1-3 по сравнению с ручной формой ;)

и в оригинальной статье не показано сколько потребуется кода и дополнительных файлов для
«любимой» компоненты формы

P.S. потерял ссылку на статью, где все элементы, участвующие в рисовании формы разобраны на классы и файлы… сходу нашел akrabat.com/2008/02/21/simple-zend_form-example/, что все же лучше, чем оригинальная статья
1. не совсем понятно, все что вы указали, присутствует в стандартных декораторах, для required, это в параметрах:
'escape' => false,
'requiredSuffix' => '*:',
'optionalSuffix' => ':'
Description — для описания, это совсем просто, как и добавить label

2. для этого есть 2 варианта, прерывать chain валидаторов или нет, true/false. Можно написать кастомный валидатор, который выводит ошибки в одну кучу, а не под каждым элементом

3. для этого вы можете переписать метод isValid вашей формы. Например:

class Form_Login extends App_Form
{

public function init()
{
//конструктор формы
}

public function isValid($data)
{
//проверка данных на подлинность
}
}

4. на сколько больше или меньше кода, это не показатель, в результате хардкодить формы получается дольше, но прошу, не начинайте холивар, т.к формы у разных проектов разные, + вам встречный вопрос, как вы напишите unit-test'ы для хтмл форм?;)
на формы нужно писать приёмочные/функциональные тесты, а не модульные. а ваш вопрос спровоцирован зендовской философией смешения всего-всего в одном компоненте.
1. unit тест нужно писать к коду

if ($this->_request->isPost())
{
if ($form->isValid($this->_request->getPost()))
{
$user->register($form->getValues()

а он по сути дела не зависит от того — как сделана форма, ручками или zend`ом, а внешний вид формы и все валидации тестировать ручками в среднем проекте получится быстрее, чем писать unit тесты

2. на самом деле цель моих вопросов — это понять как делать формы, используя zend и получать при этом удовольствие от того, что код проще или меньше или его удобнее сопровождать… пока я сам реализовал свою функцию isValid и в форме использую код вида

[input type=«text» name=«name» value="[?= $this->params['login'] ?]"/]
[? if (isset($this->errs['login'])){ ?][span class=«err»][?= $this->errs['login'] ?]

3. Если есть у вас красивый пример формы, то не затруднит ли вас прислать его в личку?

я делал элемент group в который можно было влаживать другие элементы, выглядело примерно так:
$elemLabel = new Label(...)
$elemSpan = new Span(...)
… тут куча нужных элементов
$elemGroup = new Group(...)
$elemGroup->addElement($elemLabel)->addElement($elemSpan)->etc…
так есть возможность дать каждому элементу свой декоратор + группе декоратор + группы можно группировать
Вывод результата тоже изменял, у нас результат появлялся над формой в своем оформлении
стандартная проверка — декоратор поумолчанию который нужно убрать, у нас был свой декоратор для формы который менял вид самой формы + выносил ошибки наружу (это если вы имеете ввиду показ ошибок) вообще валидация идет с помошью валидаторов, пишете свой валидатор, добавляете и все работает как вам нужно (это если вы имеете ввиду проверку ошибок)

4 был замечательный мультик, и там звучала фраза: «лучше день потерять, но потом за один час долететь»… так и получается, один раз посидеть долго, но потом все будет намного проще
Посмотрите Yii и увидите наскольно там все вместе связано и насколько все проще делается. Вот там реально удовольствие валить формы с валидацией.
подход зхенда к формам просто ужасен. зачем делать генератор object -> html, если все эти декораторы можно реализовать прозрачно в подшаблонах. да и вообще форма не должна знать об html, который является только одним из форм передачи. элементы не должны описываться типом, наоборот тип — это один из атрибутом эллемента. после появления форм я ушёл от zf за которым следил ещё с версии 0.6
разгребусь с делами и заоупенсуршу свой подход, с которым формы делать гораздо удобнее, быстре и они позволяют делать вывод, валидацию, фильтрацию, сохранение. сейчас завязано всё на моём фреймворке, постараюсь немного развязать.
блин, сколько раз я говорил себе фразу "… разгребусь с делами, и..!"
а форма и не знает об html она знает о декораторе, что он там делает ей уже плевать, она отдает данные, и получает завуалированный результат, будь то html, xml, JSON, etc
Да, не совсем удачная статья в плане того, вся удобность этого класса не показана, поэтому так и много критики пошло ниже.

В действительности, это довольно удобный класс для простых и средней сложности форм, кои подавляющее большинство в интернет-проектах. Поддерживается AJAX валидация форм, очень гибкая система информирования о конкретной ошибки при валидации введенных данных, кода в действительно довольно мало в итоге получается, ну и т.д.

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

По-моему, это подход к Zend_Form, практикуемый в статье ужасен.
Создавать объемные формы без инициализации через Zend_Config_Ini/Xml/… (т.е. соответственно инициализируя форму и добавляя элементы напрямую в коде) — это сущий ад.
Да и предназначается компонент совсем не для элементарных форм (которые можно сделать и «обычным» способом) — его преимущества очень хорошо раскрываются при создании динамических форм, которые изменяются в зависимости от разных условий.
Одним словом, компонент очень нужный и полезный :)
вообще, все зависит кто и как его использует, Zend_Form для полноты всегда нужно «подпиливать» под свой проект, редко можно увидеть крупные, серьезные проекты (я не говорю о всяких там личных страничках, да и интернет магазинах), которые работают со стандартными не затюниным Zend_Form, в статье действительно немного подход, скажем так, для обычного начала.

К автору появляется вопрос:

Вы перевели статью просто из личного интереса, или вы всетаки напрямую работали с Zend_Form'ами и вам эта статья помогла в них освоиться?
формы можно наследовать, с ней оч удобно работать как с объектом =)
Если несложно можно прислать пример формы на Zend'e мне в личку? В ответ, после разбора кода и написания кода по аналогии для cвоих проектов — обязуюсь написать статью в хабр ;)
особенно удобно работать с формами, когда есть своя библиотека декораторов — гибкость достигается путем визова одних декораторов из других ($this->getElement()->getDecorator('name')); если правильно подойти к делу — можно одной лиш заменой базового класа форм слелать из простой — многошаговую. загрузка файлов тоже интересна (например, можно сделать, чтоб большой мп3 файл оставался на сервере и привязанним к форме даже если в других полях есть ошибки); для разработки форм совет — держать набори полей разного назначения в разних класах (например, Form_User, Form_UserLogin), поскольну введение свойства идентификатора групи полей иногда накладно (но гибко))). при таком проектировании можно добится гибкости, если нужна валидация посложнее, нежели та, что предлагается через методи addValidators (нужно просто дополнить метод isValid()).
может на ету тему и заметку напишу (паралельно с кодогенерацией для zend_framework)
детораторы и без этого вызываются рекурсивно, результат одного передается другому, не стоит вызывать декоратор из декоратора
Zend_Form конечно вешь хорошая, но производительность совсем не радует
К сожалению производительность — плата за гибкость
Сборка всего Зенда в один файл и eAccelerator/APC спасут отца русской демократии :)
Давно хотел это проверить :)
хотелось бы понять в чем преимущества Zend_Form, внятной статьи нигде не видел, но видел много статей, после которых сложилось впечатление, что Zend_Form неудобен
Я тоже, когда первый раз попробовал, решил, что это не для меня. Со второго раза решил, что все-таки годная вещь. Правда, до сих пор не уверен, что время, потраченное на освоение Zend_Form, когда-нибудь окупится:)
По существу вопроса:
1) автоматическая генерация html-кода
2) валидация введенных данных (тоже)
3) интеграция с остальными компонентами ZF

ох щи, отправил недописанное. Впрочем, неважно
хотел добавить, что все это гибко настраивается
Бедноватая статья. Как начнешь разбираться с зендовыми формами — появится очень много нюансов.
Сам в своих проектах создаю директорию, например fields, которая выглядит примерно так:
[rap-kasta@acerAspire serebro]$ find application/fields/
....
application/fields/Login
application/fields/Login/Validator.php
application/fields/Login/Field.php
application/fields/Login/Validator
application/fields/Login/Validator/Used.php
....

Думаю смысл понятен: в основном в системе большинство «полей» повторяются: поле логина, например, используется при авторизации и регистрации, e-mail при регистрации, восстановлении пароля и, мб, тоже авторизации…
Специфичные валидаторы (например проверку на существование логина в системе) выношу отдельно.
В Field (по сути-расширение необходимого *Element* )определяю параметры поля, фильтры, прикрепляю основной валидатор.
В форме, например регистрации, устанавливаю, если нужно, доп. валидаторы и ставлю нужное значение для setRequired.

В результате имеем полное структурирование: валидаторы, поля и форма, которая очень даже локанично выглядит, вот кусок из формы для того же логина:
$login = new fields_Login_Field('login');
$login->setRequired(true);
$login->addValidator(new fields_Login_Validator_Used());
$this->addElement($login)
Ерунда этот Zend Form. Во-первых, декораторы описываются уродливо в самом контроллере — а должны описываться в шаблоне View. Во-вторых, как Zend Form связан с моделью? Никак. А должен бы, так как большинство форм соответсвуют моделям. В-третьих, придется для каждой формы писать один и тот же код:

$f = new Zend_Form(...)
if ($this->_request->isPost)

и так далее? Где средства автоматизации этого рутинного кода? (по правде, как решить 3ю проблему я тоже не представляю).
В самом общем случае форма понятия о моделях не имеет.
Но соглашусь, что часто имеет место потребность в некотором строителе форм на основе моделей.

p.s. быть может framework.zend.com/wiki/display/ZFPROP/Zend_Form_Generator вызреет когда-нибудь
Кто мешает написать наследника от Zend_Form и прописать в него то, что вы часто используете?
Я так и делаю.
Модели привязать к форме тоже проблем не вижу, если это необходимо.
Zend_Form и Zend_Form_Element — это базовые классы. Расширяйте их как угодно, все же объектно.
У меня, например, есть элемент с автодополнением, выбора даты, вкладок, визуального редактора,… это очень удобно. Один раз пишешь, потом просто используешь.

По производительности — фникто не запрещает формы кэшировать — подключите к ней Zend_Cache — хоть на уровне объектов, хоть на уровне HTML.

По декораторам — они реально удобны для быстрого парсинга. Делаете несколько вариантов и используете в зависимости от требований. В основном, управляя структурой. У меня, например, по типам полей добавляются классы контейнерам в декораторах. А все оформление делается в CSS.
Нарушения MVC не вижу, считаю декораторы частью View.
Если хочется чистого разделения — кто мешает? Отключаете все декораторы, форму рендерите вручную, с помощью view, причем, как угодно.

Zend_Form очень гибок и функционален, впрочем, как и весь Zend Framework.
UFO just landed and posted this here
Управляйте. Назначайте форме рендер через view и парсите — хоть через цикл, хоть вручную поэлементно.
UFO just landed and posted this here
Sign up to leave a comment.

Articles