Некоторое время назад мне нужно было спросить пользователя о дате его рождения на Zend_Form. Дизайн показал три отдельных элемента для выбора:
Немного погуглив этот сайт нашел http://codecaine.co.za/posts/compound-elements-with-zend-form, который, к сожалению, не исчез, поэтому код в этой статье многим обязан автору этой статьи ,
Оказывается, очень просто создать один элемент Zend Form, который будет отображаться как несколько элементов формы. Мы создаем объект-элемент и вспомогательный объект вида, и все готово. Использование тогда выглядит как
<?php class Application_Form_Details extends Zend_Form { public function init() { $this->addPrefixPath('App_Form', 'App/Form/'); // other elements before $this->addElement('date', 'date_of_birth', array( 'label' => 'Date of birth:' )); // other elements after $this->addElement('submit', 'Go'); } }
Очевидно, что эта форма находится в application / forms / Detail.php и отображается как обычно в скрипте вида. В нашем определении формы мы добавили элемент с именем «date» и с добавлением вызова addPrefixPath сказали форме, что помимо использования стандартных элементов формы Zend Framework, также посмотрите в library / App / Form. (Кстати, теперь мы также можем переопределить любой предоставленный элемент формы, просто поместив замену в папку libraryApp / Form.)
Элемент формы даты находится в библиотеке / App / Form / Element / Date.php, поскольку Zend_Form знает, как искать в подпапке для App / Form, называемую Elements, любые объекты-элементы и искать в папке Decorator / подпапку для объектов-декораторов.
Элемент Date выглядит так:
// Based on code from // http://codecaine.co.za/posts/compound-elements-with-zend-form class App_Form_Element_Date extends Zend_Form_Element_Xhtml { public $helper = 'formDate'; public function isValid ($value, $context = null) { if (is_array($value)) { $value = $value['year'] . '-' . $value['month'] . '-' . $value['day']; if($value == '--') { $value = null; } } return parent::isValid($value, $context); } public function getValue() { if(is_array($this->_value)) { $value = $this->_value['year'] . '-' . $this->_value['month'] . '-' . $this->_value['day']; if($value == '--') { $value = null; } $this->setValue($value); } return parent::getValue(); } }
Здесь много цитат, но это должно быть довольно ясно. Сначала мы указываем имя помощника вида, который будет использоваться при рендеринге этого элемента в formDate, который мы напишем. Мы знаем, что этот элемент будет состоять из трех блоков выбора, и в результате они станут массивом опубликованных данных за день, месяц и год. В результате нам нужно переопределить isValid (), чтобы превратить наш массив обратно в строку, а затем вызвать родительский isValid (), чтобы выполнить фактическую требуемую проверку. Нам также необходимо переопределить getValue () таким же образом, чтобы убедиться, что это также строка. Снова мы вызываем функцию getValue () родителя, поскольку она выполняет фильтрацию.
Это все, что есть в самом элементе, поэтому теперь обратим внимание на помощник вида, который будет визуализировать элемент. Он находится в библиотеке / App / View / Helpers / FormDate.php и, согласно моему сообщению о помощниках , нам нужно сообщить представление об этой папке через application.ini:
autoloadernamespaces[] = "App_" resources.view.helperPath.App_View_Helper = "App/View/Helper"
Код помощника вида formDate выглядит следующим образом
<?php // based on code from // http://codecaine.co.za/posts/compound-elements-with-zend-form class App_View_Helper_FormDate extends Zend_View_Helper_FormElement { public function formDate ($name, $value = null, $attribs = null) { // separate value into day, month and year $day = ''; $month = ''; $year = ''; if (is_array($value)) { $day = $value['day']; $month = $value['month']; $year = $value['year']; } elseif (strtotime($value)) { list($year, $month, $day) = explode('-', date('Y-m-d', strtotime($value))); } // build select options $dayAttribs = isset($attribs['dayAttribs']) ? $attribs['dayAttribs'] : array(); $monthAttribs = isset($attribs['monthAttribs']) ? $attribs['monthAttribs'] : array(); $yearAttribs = isset($attribs['yearAttribs']) ? $attribs['yearAttribs'] : array(); $dayMultiOptions = array('' => ''); for ($i = 1; $i < 32; $i ++) { $index = str_pad($i, 2, '0', STR_PAD_LEFT); $dayMultiOptions[$index] = str_pad($i, 2, '0', STR_PAD_LEFT); } $monthMultiOptions = array('' => ''); for ($i = 1; $i < 13; $i ++) { $index = str_pad($i, 2, '0', STR_PAD_LEFT); $monthMultiOptions[$index] = date('F', mktime(null, null, null, $i, 01)); } $startYear = date('Y'); if (isset($attribs['startYear'])) { $startYear = $attribs['startYear']; unset($attribs['startYear']); } $stopYear = $startYear + 10; if (isset($attribs['stopYear'])) { $stopYear = $attribs['stopYear']; unset($attribs['stopYear']); } $yearMultiOptions = array('' => ''); if ($stopYear < $startYear) { for ($i = $startYear; $i >= $stopYear; $i--) { $yearMultiOptions[$i] = $i; } } else { for ($i = $startYear; $i <= $stopYear; $i++) { $yearMultiOptions[$i] = $i; } } // return the 3 selects separated by return $this->view->formSelect( $name . '[day]', $day, $dayAttribs, $dayMultiOptions) . ' ' . $this->view->formSelect( $name . '[month]', $month, $monthAttribs, $monthMultiOptions) . ' ' . $this->view->formSelect( $name . '[year]', $year, $yearAttribs, $yearMultiOptions ); } }
Опять же, кода довольно много, но я ожидаю, что он довольно понятен. По сути, у нас много настроек для отображения трех блоков выбора; один на день, месяц и год. Я решил использовать названия месяцев, но это довольно легко изменить на цифры. С точки зрения конфигурации, вы должны быть в состоянии указать номера начала и окончания года. Затем они передаются как параметры при вызове addElement.
Вот и все. Два отдельных файла — это все, что вам нужно для создания объекта элемента Zend_Form, который реализуется через составные элементы. Из этого также следует, что вы можете сделать то же самое для любого другого концептуального элемента, который вы хотите отобразить как несколько элементов на странице.