ZF2 - Создание пользовательских помощников для представления формы

Некоторое время назад Мэтью Вейер О'Финни опубликовал эту статью. в своем блоге о создании составных элементов формы в Zend Framework 1.

Я пытаюсь создать тот же элемент для своей пользовательской библиотеки в Zend Framewor 2, но у меня возникают проблемы с поиском помощника по представлению формы при рендеринге формы.

Вот мой элемент (DateSegmented.php):

<?php

namespace Si\Form\Element;

use Zend\Form\Element;
use Zend\ModuleManager\Feature\ViewHelperProviderInterface;

class DateSegmented extends Element implements ViewHelperProviderInterface
{

    public function getViewHelperConfig(){
          return array( 'type' => '\Si\Form\View\Helper\DateSegment' );
     }

    protected $_dateFormat = '%year%-%month%-%day%';
    protected $_day;
    protected $_month;
    protected $_year;

    /**
     * Seed attributes
     *
     * @var array
     */
    protected $attributes = array(
        'type' => 'datesegmented',
    );

    public function setDay($value)
    {
        $this->_day = (int) $value;
        return $this;
    }

    public function getDay()
    {
        return $this->_day;
    }

    public function setMonth($value)
    {
        $this->_month = (int) $value;
        return $this;
    }

    public function getMonth()
    {
        return $this->_month;
    }

    public function setYear($value)
    {
        $this->_year = (int) $value;
        return $this;
    }

    public function getYear()
    {
        return $this->_year;
    }

    public function setValue($value)
    {
        if (is_int($value)) {
            $this->setDay(date('d', $value))
                 ->setMonth(date('m', $value))
                 ->setYear(date('Y', $value));
        } elseif (is_string($value)) {
            $date = strtotime($value);
            $this->setDay(date('d', $date))
                 ->setMonth(date('m', $date))
                 ->setYear(date('Y', $date));
        } elseif (is_array($value)
            && (isset($value['day']) 
                && isset($value['month']) 
                && isset($value['year'])
            )
        ) {
            $this->setDay($value['day'])
                 ->setMonth($value['month'])
                 ->setYear($value['year']);
        } else {
            throw new Exception('Invalid date value provided');
        }

        return $this;
    }

    public function getValue()
    {
        return str_replace(
            array('%year%', '%month%', '%day%'),
            array($this->getYear(), $this->getMonth(), $this->getDay()),
            $this->_dateFormat
        );
    }
}

И вот мой помощник по представлению формы:

<?php

    namespace Si\Form\View\Helper;

    use Zend\Form\ElementInterface;
    use Si\Form\Element\DateSegmented as DateSegmented;
    use Zend\Form\Exception;

    class DateSegmented extends FormInput
    {
        /**
         * Render a form <input> element from the provided $element
         *
         * @param  ElementInterface $element
         * @throws Exception\InvalidArgumentException
         * @throws Exception\DomainException
         * @return string
         */
        public function render(ElementInterface $element)
        {
            $content = "";

            if (!$element instanceof DateSegmented) {
                throw new Exception\InvalidArgumentException(sprintf(
                    '%s requires that the element is of type Si\Form\Input\DateSegmented',
                    __METHOD__
                ));
            }

            $name = $element->getName();
            if (empty($name) && $name !== 0) {
                throw new Exception\DomainException(sprintf(
                    '%s requires that the element has an assigned name; none discovered',
                    __METHOD__
                ));
            }

            $view = $element->getView();
            if (!$view instanceof \Zend\View\View) {
                // using view helpers, so do nothing if no view present
                return $content;
            }

            $day   = $element->getDay();
            $month = $element->getMonth();
            $year  = $element->getYear();
            $name  = $element->getFullyQualifiedName();

            $params = array(
                'size'      => 2,
                'maxlength' => 2,
            );
            $yearParams = array(
                'size'      => 4,
                'maxlength' => 4,
            );

            $markup = $view->formText($name . '[day]', $day, $params)
                    . ' / ' . $view->formText($name . '[month]', $month, $params)
                    . ' / ' . $view->formText($name . '[year]', $year, $yearParams);

            switch ($this->getPlacement()) {
                case self::PREPEND:
                    return $markup . $this->getSeparator() . $content;
                case self::APPEND:
                default:
                    return $content . $this->getSeparator() . $markup;
            }

            $attributes            = $element->getAttributes();
            $attributes['name']    = $name;
            $attributes['type']    = $this->getInputType();
            $attributes['value']   = $element->getCheckedValue();
            $closingBracket        = $this->getInlineClosingBracket();

            if ($element->isChecked()) {
                $attributes['checked'] = 'checked';
            }

            $rendered = sprintf(
                '<input %s%s',
                $this->createAttributesString($attributes),
                $closingBracket
            );

            if ($element->useHiddenElement()) {
                $hiddenAttributes = array(
                    'name'  => $attributes['name'],
                    'value' => $element->getUncheckedValue(),
                );

                $rendered = sprintf(
                    '<input type="hidden" %s%s',
                    $this->createAttributesString($hiddenAttributes),
                    $closingBracket
                ) . $rendered;
            }

            return $rendered;
        }

        /**
         * Return input type
         *
         * @return string
         */
        protected function getInputType()
        {
            return 'datesegmented';
        }

    }

Этот вопрос описывает добавление помощника представления в качестве вызываемого, но это уже объявляется, так как моя пользовательская библиотека (Si) была добавлена ​​в «StandardAutoLoader».


person MrNorm    schedule 17.01.2013    source источник


Ответы (2)


Хорошо, в конце концов разобрался с этим.

Скопируйте Zend/Form/View/HelperConfig.php в то же место в вашей пользовательской библиотеке. Отрегулируйте содержимое, чтобы оно отражало ваши помощники представления.

Добавьте следующее в событие или начальную загрузку в вашем Module.php

$app = $e->getApplication();
$serviceManager = $app->getServiceManager();
$phpRenderer = $serviceManager->get('ViewRenderer');

$plugins = $phpRenderer->getHelperPluginManager();
$config  = new \Si\Form\View\HelperConfig;
$config->configureServiceManager($plugins);

Обновите пространство имен «Si» своим собственным.

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

use Zend\Form\View\Helper\FormElement;

use Zend\Form\Element;
use Zend\Form\ElementInterface;
use Zend\Form\Exception;

Я также обновил оператор instanceof до абсолютного местоположения из-за повторяющихся имен классов:

if (!$element instanceof \Si\Form\Element\DateSegmented) {

Были и другие ошибки при переводе с ZF1 на 2, но они не связаны с этой проблемой.

person MrNorm    schedule 17.01.2013

Как я понимаю ваш код: вы создаете новый Form\Element, а также новый Form\View\Helper. В этом случае вам необходима следующая информация:

StandardAutoloader заботится только о фактическом поиске классов. Объявление invokables внутри getViewHelperConfig() есть, поэтому фреймворк знает, какой Class загружать при вызове ViewHelper.

В вашем случае вы бы сделали это так:

public function getViewHelperConfig() 
{
    return array(
        'invokables' => array(
            'dateSegmented' => 'Si\Form\View\Helper\DateSegmented'
        )
    );
}

Zend Framework 2 делает это для своего собственного ViewHelpers внутри / Zend/Form/View/HelperConfig.php

person Sam    schedule 17.01.2013
comment
К сожалению для меня, добавление вызвало эту ошибку PHP Fatal error: Cannot declare class Si\\Form\\View\\Helper\\DateSegmented because the name is already in use in /Users/oliver/Sites/xxx-qe-zf2/trunk/vendor/Si/Form/View/Helper/DateSegmented.php on line 10 - person MrNorm; 17.01.2013
comment
Ах, я только что заметил, что вы реализуете ViewHelperProviderInterface, который делает всю работу за вас. К сожалению, в этом случае у меня нет дальнейших подсказок, я еще этого не делал, извините. - person Sam; 17.01.2013
comment
Не волнуйтесь! Спасибо за вклад в любом случае - person MrNorm; 17.01.2013