Привет хабраюзеры!
В большинстве проектов на Yii которые я видел, работа с формами была организована самым простым способом, где рендеринг формы определялся в файле вида через виджет ActiveForm. Да, это безусловно оправдано для сложных форм, которые проблематично уместить в шаблон. Но сегодня я хочу поговорить о конструкторе форм и показать как это применяем мы.
Если вы плохо представляете, что такое конструктор форм, то прежде советую ознакомиться с соответствующим разделом документации www.yiiframework.ru/doc/guide/ru/form.builder.
Все просто. Работа с формами у нас построена по принципу «не смешивать модели формы и модели таблиц». А идея состоит в том, что бы в модель формы добавить функциональность конструктора форм.
Для этого создадим класс от которого будут наследоваться наши формы. Т.е. сделаем так, что бы модель формы сама определяла рендеринг исходя из конфигурации формы.
Пройдемся по классу более подробно. Массив "$_formConfig" позволяет задать конфигурацию формы. Например:
Так же для конфигурации формы можно переопределить метод "_formConfig()". Это удобно когда нужно во время конфигурации реализовать какую-то логику.
Свойство "$_formClass" позволяет изменить класс который используется для отображения формы (CForm или его потомок).
Заметьте, что теперь вам не обязательно указывать атрибуты формы. Для этого мы переопределили метод «attributeLabels()» и теперь атрибуты равны лейблам из конфигурации формы.
Получить объект формы (CForm) можно методом «getForm()».
Рендеринг формы:
Использование совместно с моделью таблицы.
Настройка отображения формы. Для каждого элемента в "$_formConfig" мы можем указать свой шаблон с переопределив свойство «layout»:
Одна из неприятностей которая встала при использовании конструктора форм, это невозможность автоматически добавлять двоеточие после заголовка поля. Если двоеточие вставить в конфиг формы в label, то оно будет видно и при отображении ошибок. Что бы исправить это, расширим классы «CForm» и «CFormInputElement» и чуть-чуть поправим наш «FormModel».
В «FormModel» добавляем:
И меняем $_formClass
Создадим новый класс «Form» наследник «CForm», в нем переопределим свойство "$inputElementClass".
Создадим класс «FormInputElement» (наследник «CFormInputElement»), в нем переопределим метод «renderLabel()»
Теперь используя свойство "$autoAddColonForRender" в «FormModel» возможно автоматически добавлять двоеточие после лейбла для всех элементов формы. Либо определять это для каждого элемента формы в отдельности во время конфиграции формы, установив соответствующее значение в «addColon».
На этом сегодня всё, спасибо всем кто дочитал до конца. Объективная критика приветствуется.
В большинстве проектов на Yii которые я видел, работа с формами была организована самым простым способом, где рендеринг формы определялся в файле вида через виджет ActiveForm. Да, это безусловно оправдано для сложных форм, которые проблематично уместить в шаблон. Но сегодня я хочу поговорить о конструкторе форм и показать как это применяем мы.
Если вы плохо представляете, что такое конструктор форм, то прежде советую ознакомиться с соответствующим разделом документации www.yiiframework.ru/doc/guide/ru/form.builder.
Все просто. Работа с формами у нас построена по принципу «не смешивать модели формы и модели таблиц». А идея состоит в том, что бы в модель формы добавить функциональность конструктора форм.
Для этого создадим класс от которого будут наследоваться наши формы. Т.е. сделаем так, что бы модель формы сама определяла рендеринг исходя из конфигурации формы.
/**
* FormModel.
*
* @author Andrey Nilov <nilov@glavweb.ru>
* @copyright Copyright (c) 2007-2012 Glavweb.Soft, Russia. (http://glavweb.ru)
*/
class FormModel extends CFormModel
{
/**
* Config of the form
* @var array
*/
protected $_formConfig = array();
/**
* Config of the form by default
* @var array
*/
private $_defaultFormConfig = array(
'method' => 'post'
);
/**
* Class name of form
* @var string
*/
protected $_formClass = 'CForm';
/**
* Object of Form
* @var Form
*/
private $_form = null;
/**
* Constructor
*
* @param string $scenario Name of the scenario that this model is used in
* @return void
*/
public function __construct($scenario = '')
{
parent::__construct($scenario);
$this->_setFormConfig();
}
/**
* Sets config of the form
*
* @return void
*/
private function _setFormConfig()
{
$this->_formConfig = array_replace_recursive(
$this->_defaultFormConfig,
$this->_formConfig()
);
}
/**
* Returns config of the form
*
* @return array
*/
protected function _formConfig()
{
return $this->_formConfig;
}
/**
* Returns the attribute labels
*
* @return array Attribute labels (name=>label)
*/
public function attributeLabels()
{
return $this->getLabels();
}
/**
* Returns the config of the form
*
* @return array
*/
public function getFromConfig()
{
return $this->_formConfig;
}
/**
* Sets the config of the form
*
* @param array $config
* @return void
*/
public function setFromConfig(array $config)
{
$this->_formConfig = $config;
}
/**
* Returns labels
*
* @return array
*/
public function getLabels()
{
$labels = array();
if (!empty($this->_formConfig['elements'])) {
foreach ($this->_formConfig['elements'] as $name => $data) {
if (isset($data['label'])) {
$labels[$name] = $data['label'];
}
}
}
return $labels;
}
/**
* Returns object of Form
*
* @return Form
*/
public function getForm()
{
if ($this->_form === null) {
$this->_form = new $this->_formClass($this->_formConfig, $this);
}
return $this->_form;
}
}
Пройдемся по классу более подробно. Массив "$_formConfig" позволяет задать конфигурацию формы. Например:
/**
* Config of the form
* @var array
*/
protected $_formConfig = array(
'activeForm' => array(
'class' => 'CActiveForm',
'id' => 'registration_form',
'enableClientValidation' => true,
'clientOptions' => array(
'validateOnSubmit' => true
)
),
'elements' => array(
....
'name' => array(
'type' => 'text',
'label' => 'ФИО'
),
'organization' => array(
'type' => 'text',
'label' => 'Организация'
),
....
),
'buttons' => array(
'register' => array(
'type' => 'submit',
'label' => 'Регистрация'
)
)
);
Так же для конфигурации формы можно переопределить метод "_formConfig()". Это удобно когда нужно во время конфигурации реализовать какую-то логику.
Свойство "$_formClass" позволяет изменить класс который используется для отображения формы (CForm или его потомок).
Заметьте, что теперь вам не обязательно указывать атрибуты формы. Для этого мы переопределили метод «attributeLabels()» и теперь атрибуты равны лейблам из конфигурации формы.
Получить объект формы (CForm) можно методом «getForm()».
Использование.
Рендеринг формы:
$formModel = new RegistrationForm();
$form = $formModel->getForm();
echo $form;
Использование совместно с моделью таблицы.
$user = new User();
$user->setAttributes($formModel->getAttributes());
$result = $user->save();
Настройка отображения формы. Для каждого элемента в "$_formConfig" мы можем указать свой шаблон с переопределив свойство «layout»:
protected $_formConfig = array(
....
'elements' => array(
....
'name' => array(
'type' => 'text',
'label' => 'ФИО',
'layout' => "{input}\n{label}\n{hint}\n{error}"
),
....
),
Автоматическое добавление двоеточия.
Одна из неприятностей которая встала при использовании конструктора форм, это невозможность автоматически добавлять двоеточие после заголовка поля. Если двоеточие вставить в конфиг формы в label, то оно будет видно и при отображении ошибок. Что бы исправить это, расширим классы «CForm» и «CFormInputElement» и чуть-чуть поправим наш «FormModel».
В «FormModel» добавляем:
/**
* Automatically add a colon in time rendering
* @var boolean
*/
public $autoAddColonForRender = true;
И меняем $_formClass
/**
* Class name of form
* @var string
*/
protected $_formClass = 'Form';
Создадим новый класс «Form» наследник «CForm», в нем переопределим свойство "$inputElementClass".
class Form extends CForm
{
/**
* The name of the class for representing a form input element.
* @var string
*/
public $inputElementClass = 'FormInputElement';
}
Создадим класс «FormInputElement» (наследник «CFormInputElement»), в нем переопределим метод «renderLabel()»
class FormInputElement extends CFormInputElement
{
/**
* @var string the layout used to render label, input, hint and error. They correspond to the placeholders
* "{label}", "{input}", "{hint}" and "{error}".
*/
public $layout = "{label}\n{input}\n{error}\n{hint}";
/**
* Automatically add a colon in time rendering
* @var boolean
*/
public $addColon = null;
/**
* Renders the label for this input.
*
* @return string
*/
public function renderLabel()
{
$model = $this->getParent()->getModel();
$addColon = $this->addColon !== null ?
$this->addColon :
$model instanceof FormModel && $model->autoAddColonForRender;
$label = $addColon ? $this->getLabel() . ':' : $this->getLabel();
$options = array(
'label' => $label,
'required' => $this->getRequired()
);
if (!empty($this->attributes['id'])) {
$options['for'] = $this->attributes['id'];
}
return CHtml::activeLabel($this->getParent()->getModel(), $this->name, $options);
}
}
Теперь используя свойство "$autoAddColonForRender" в «FormModel» возможно автоматически добавлять двоеточие после лейбла для всех элементов формы. Либо определять это для каждого элемента формы в отдельности во время конфиграции формы, установив соответствующее значение в «addColon».
protected $_formConfig = array(
....
'elements' => array(
....
'name' => array(
'type' => 'text',
'label' => 'ФИО',
'addColon' => true
),
....
),
На этом сегодня всё, спасибо всем кто дочитал до конца. Объективная критика приветствуется.