Элемент формы Zend Framework 2 error-class + пользовательский ViewHelper для рендеринга формы

Это мой третий вопрос на этой неделе (и вообще) - надеюсь, меня здесь не забанят :D В любом случае, я поискал и не смог найти точного объяснения для решения моей проблемы (проблем).

О. Я поискал и нашел пользовательский ViewHelper для отображения моих форм. Что он делает, так это рекурсивно получает все наборы полей, и когда он достигает уровня элемента, он выглядит следующим образом:

    public function renderElement($element) {
        $html = '
            <div class="row">' . 
            '<label class="col-md-12" for="' . $element->getAttribute('id') . '">' . $element->getLabel() . '</label>' . 
            $this->view->formElement($element) . 
            $this->view->FormElementErrors($element) .
            '<div class="clearfix" style="height: 15px;"></div>';

        return $html . PHP_EOL;
    }

Форма отображается нормально, за исключением: 1) Как я могу добавить класс ошибки к элементу формы? (например, если я использую помощник formRow в своем представлении, он автоматически объявляет класс «ошибка ввода», а также сохраняет начальный класс, указанный в моем наборе полей при создании элемента - «атрибуты» => массив («класс» => ' some-class')), поэтому атрибут class элемента становится "some-class input-error", если он недействителен. 2) Как я могу установить класс для 'ul', содержащего сообщения об ошибках ('ul', отображаемый $this->view->FormElementErrors($element))? Надеюсь, что это однострочник, и мне не нужно переходить от сообщения к сообщению и составлять html для списка сообщений об ошибках, но если нет, то пусть будет так (я тоже не знаю, как это сделать).

B. Допустим, иногда я не использую этот пользовательский ViewHelper для рендеринга моей формы. Помощник представления Zend formRow иногда может быть удобен. Это подводит меня к следующему коду, на мой взгляд:

    echo $this->formRow($this->form->get('user_fieldset')->get('user_name'));

Я заметил, что это автоматически добавляет класс «input-error» к моему элементу (в случае, если он недействителен), что идеально, НО как я могу также указать formRow, чтобы дать класс «ul», который отображает сообщения об ошибках?

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

    echo $this->formLabel($this->form->get('user_fieldset')->get('user_name'));
    echo $this->formInput($this->form->get('user_fieldset')->get('user_name'));
    echo $this->formElementErrors($this->form->get('user_fieldset')->get('user_name'), array('class' => 'form-validation-error'));

во что-то, что также добавляет класс ошибок к элементу, а не только к списку сообщений об ошибках, но если кто-то ответит на пункт A, я думаю, что это та же проблема.


person MrCroft    schedule 29.12.2013    source источник
comment
Для чего вам нужно установить класс для элемента ‹ul›?   -  person Microbe    schedule 30.12.2013
comment
Мне нужно установить класс для этого ul, чтобы стилизовать его с помощью css. Я не хочу делать это каскадно из класса формы (.frm-class ul) или идентификатора формы, я хочу сделать это непосредственно с помощью атрибута ul.   -  person MrCroft    schedule 30.12.2013


Ответы (2)


Мне удалось сделать это так:

public function renderElement($element) {
    // FORM ROW
    $html = '<div class="form-group">';

    // LABEL
    $html .= '<label class="form-label" for="' . $element->getAttribute('id') . '">' . $element->getLabel() . '</label>';

    // ELEMENT
    /*
     - Check if element has error messages
     - If it does, add my error-class to the element's existing one(s),
       to style the element differently on error
    */
    if (count($element->getMessages()) > 0) {
        $classAttribute = ($element->hasAttribute('class') ? $element->getAttribute('class') . ' ' : '');
        $classAttribute .= 'input-error';
        /* 
         * Normally, here I would have added a space in my string (' input-error')
         * Logically, I would figure that if the element already has a class "cls"
         * and I would do $element->getAttribute('class') . 'another-class'
         * then the class attribute would become "clsanother-class"
         * BUT it seems that, even if I don't intentionally add a space in my string,
         * I still get "cls another-class" as the resulted concatenated string
         * I assume that when building the form, ZF2 automatically
         * adds spaces after attributes values? so you/it won't have to
         * consider that later, when you'd eventually need to add another
         * value to an attribute?
         */
        $element->setAttribute('class', $classAttribute);
    }
    $html .= $this->view->formElement($element);
    /*
     * Of course, you could decide/need to do things differently,
     * depending on the element's type

       switch ($element->getAttribute('type')) {
           case 'text':
           case 'email': {

               break;
           }
           default: {

           }
       }
     */
    // ERROR MESSAGES
    // Custom class (.form-validation-error) for the default html wrapper - <ul>
    $html .= $this->view->FormElementErrors($element, array('class' => 'form-validation-error'));

    $html .= '</div>'; # /.form-group
    $html .= '<div class="clearfix" style="height: 15px;"></div>';

    return $html . PHP_EOL;
}

Я не в восторге от этого, но я полагаю, что нет более короткого пути. Я думал, что в ZF2 должно быть что-то вроде:

if ($element->hasErrors()) { $element->addClass('some-class'); }

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

В любом случае, если кому-то это когда-нибудь понадобится, вот весь помощник представления RenderForm:

namespace User\View\Helper;

use Zend\View\Helper\AbstractHelper;

class RenderForm extends AbstractHelper {

    public function __invoke($form) {
        $form->prepare();
        $html = $this->view->form()->openTag($form) . PHP_EOL;
        $html .= $this->renderFieldsets($form->getFieldsets());
        $html .= $this->renderElements($form->getElements());
        $html .= $this->view->form()->closeTag($form) . PHP_EOL;
        return $html;
    }

    public function renderFieldsets($fieldsets) {

        foreach ($fieldsets as $fieldset) {
            if (count($fieldset->getFieldsets()) > 0) {
                $html = $this->renderFieldsets($fieldset->getFieldsets());
            } else {
                $html = '<fieldset>';
                    // You can use fieldset's name for the legend (if that's not inappropriate)
                    $html .= '<legend>' . ucfirst($fieldset->getName()) . '</legend>';
                    // or it's label (if you had set one)
                    // $html .= '<legend>' . ucfirst($fieldset->getLabel()) . '</legend>';
                    $html .= $this->renderElements($fieldset->getElements());
                $html .= '</fieldset>';
                // I actually never use the <fieldset> html tag.
                // Feel free to use anything you like, if you do have to
                // make grouping certain elements stand out to the user
            }
        }

        return $html;
    }

    public function renderElements($elements) {
        $html = '';
        foreach ($elements as $element) {
            $html .= $this->renderElement($element);
        }
        return $html;
    }

    public function renderElement($element) {
        // FORM ROW
        $html = '<div class="form-group">';

        // LABEL
        $html .= '<label class="form-label" for="' . $element->getAttribute('id') . '">' . $element->getLabel() . '</label>'; # add translation here

        // ELEMENT
        /*
         - Check if element has error messages
         - If it does, add my error-class to the element's existing one(s),
           to style the element differently on error
        */
        if (count($element->getMessages()) > 0) {
            $classAttribute = ($element->hasAttribute('class') ? $element->getAttribute('class') . ' ' : '');
            $classAttribute .= 'input-error';

            $element->setAttribute('class', $classAttribute);
        }
        $html .= $this->view->formElement($element);

        // ERROR MESSAGES
        $html .= $this->view->FormElementErrors($element, array('class' => 'form-validation-error'));


        $html .= '</div>'; # /.row
        $html .= '<div class="clearfix" style="height: 15px;"></div>';

        return $html . PHP_EOL;
    }

}

Пользователь - мой модуль. Я создал «viewhelper.config.php» в папке конфигурации:

return array(
    'invokables' => array(
        'renderForm' => 'User\View\Helper\RenderForm',
    ),
);

и в Module.php:

public function getViewHelperConfig() {
    return include __DIR__ . '/config/viewhelper.config.php';
}

Затем, на ваш взгляд, просто позвоните:

$this->renderForm($form);

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

'view_helpers' => array(
    'invokables' => array(
        'renderForm' => 'User\View\Helper\RenderForm',
    ),
),

в любой файл конфигурации.

person MrCroft    schedule 31.12.2013

Я использую метод getMessages(), чтобы проверить, есть ли у элемента проверочное сообщение. для например.

<div class="form-group <?=($this->form->get('user_fieldset')->get('user_name')->getMessages())?'has-error':'';?>">
    ...
</div>

Этот вопрос кажется очень старым, и вы, должно быть, решили его самостоятельно. :)

person Laxman    schedule 04.01.2015