Zend Framework 3 пользовательский формат ошибок формы

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

Конкретный пример:

скажем, я хочу визуализировать набор полей с радиоэлементом, который имеет 3 варианта, и только один является правильным. Идея состоит в том, чтобы обернуть каждую опцию в некоторый div для применения классов начальной загрузки, а затем выделить опцию (добавив класс has-error), когда (пользовательская) проверка не удалась.

Рендеринг может быть что-то вроде этого (здесь непосредственно в сценарии представления):

foreach($form->getFieldsets() as  $fieldset) {

echo "<fieldset><legend>".$fieldset->getName()."</legend>";

foreach ($fieldset as $element) {

$opt=$element->getOption('value_options');

foreach ($opt as $key=>$val) {
if($element->getValue()==$key){$check="checked='checked'";}else{$check="";}

echo"<div class='form-group (HERE ADD `has-error` CLASS IF VALIDATION FAILS)'>".
"<label class='custom-control'>".
"<input type='radio' class='custom-control-input' name='".$element->getName()."' value='".$key."' ".$check.">".
"<span class='custom-control-indicator'></span>".
"<span class='custom-control-description'>*TEXT*</span>".
"</label>".
"</div>";
}//3rd foreach
}//2nd foreach
echo "</fieldset>
}//1st foreach

И вот вопрос: как определить (после проверки), есть ли у элемента ошибка, чтобы добавить класс ошибки начальной загрузки?

Я думал, что возможное решение может быть:

   //custom validator

[...]

public function isValid($value, array $context = null)
{
$this->setValue($value);if ($value==1) {
$this->error(self::MESSAGE1); //Your answer (radio with value=1) is wrong!
$this->error(self::CODE1);  //1
return false;
}

[...]
return true;
}

затем:

//updated view script
$messages=$form->getMessages();

foreach($form->getFieldsets() as  $fieldset) {

echo "<fieldset><legend>".$fieldset->getName()."</legend>";

foreach ($fieldset as $element) {

$opt=$element->getOption('value_options');

foreach ($opt as $key=>$val) {
if($element->getValue()==$key){$check="checked='checked'";}else{$check=null;}

$field=$fieldset->getName();
$radio=$element->getName();
if(isset($messages[$fieldset][$radio]) && $messages[$fieldset][$radio]==$key){$class='has-error';}else{$class=null;}

echo"<div class='form-group ".$class."'>".
"<label class='custom-control'>".
"<input type='radio' class='custom-control-input' name='".$element->getName()."' value='".$key."' ".$check.">".
"<span class='custom-control-indicator'></span>".
"<span class='custom-control-description'>*TEXT*</span>".
"</label>".
"</div>";
}//3rd foreach
}//2nd foreach
echo "</fieldset>
}//1st foreach

Единственная проблема в том, что $element->getName() возвращает строку с подобным: "fieldsetName[elementName]" в то время как $form->getMessages() возвращает многомерный массив, как fieldsetName=array(elementName=array(/*MESSAGES*/),);

Возможным хаком может быть добавление пользовательского атрибута к определению элемента в классе формы.

Я знаю, что это довольно сыро, но это просто концепция. Как вы думаете? Есть ли лучшее решение для выявления ошибок?


РЕДАКТИРОВАТЬ:

Вероятно, мое первое объяснение не было очень ясным (моя вина).
Для большей ясности ЭТО должно быть (визуальный) ожидаемый результат.

Очевидно, что идея довольно разная, поскольку вся логика (фильтрация / проверка / визуализация /) должна обрабатываться php / zend. Jquery должен только отправлять форму асинхронно (метод ajax + serializeArray) и затем возвращать визуализированное представление (используя новый viewmodel-> setTerminal ()).
Но это не проблема.

Проблема в том, что радиоэлемент расширяет Zend \ Form \ View \ Helper \ FormMultiCheckbox, тогда невозможно обернуть отдельные параметры.

//Module/src/Form/ExampleForm
[...]
$this->add([
'name' => 'radio_element',
'type' => 'radio',
'options' => [
'label' => 'radio_element',
'value_options' => [
1 => 'one',
2 => 'two',
3 => 'three',
],
],

]);

[...]

//the view
echo "<div class='MY_CUSTOM_WRAPPER'>";
echo $this->formRadio($form->get('radio_element'));
echo "</div>";

//Output:
<div class='MY_CUSTOM_WRAPPER'>
<label><input type='radio' name='radio_element' value='1'>one</label>
<label><input type='radio' name='radio_element' value='2'>two</label>
<label><input type='radio' name='radio_element' value='3'>three</label>
</div>

Единственный способ обернуть каждую опцию (насколько я знаю) — это использовать пользовательский помощник (для простоты я фактически обошел этот шаг, действуя непосредственно в скрипт вида).

И вот настоящая проблема: так как три опции НЕ являются ЭЛЕМЕНТАМИ (но являются опциями элемента), мне нужно:

  1. проверить выбранное значение и установить сообщение об ошибке (пользовательский валидатор)
  2. визуализируйте элемент и отформатируйте параметр, связанный с ошибкой (а не весь элемент, или все параметры).

Мое решение (обновлено):

//custom validator
public function isValid($value, array $context = null)
{
$this->setValue($value);

if ($value==1) {
$this->setMessage('Your answer is wrong because...',self::ERRDESC);

$this->error(self::ERRNO); //defined above as %value% -> =1
$this->error(self::ERRDESC);
return false;
}
if ($value==2) {
$this->setMessage('That\'s right!!!',self::ERRDESC);
$this->setMessage("correct".$value,self::ERRNO);

$this->error(self::ERRNO);
$this->error(self::ERRDESC);
return false;
}
if ($value==3) {
$this->setMessage('That\'s really wrong! ',self::ERRDESC);

$this->error(self::ERRNO);//defined above as %value% -> =3
$this->error(self::ERRDESC);
return false;
}
[...]
return true;
}

//view script

foreach($form->getFieldsets() as  $fieldset) {

echo "<fieldset><legend>".$fieldset->getName()."</legend>";

foreach ($fieldset as $element) {

$opt=$element->getOption('value_options');

$class2=null;
foreach ($opt as $key=>$val) {

if($element->getValue()==$key){$check="checked='checked'";}else{$check=null;}

$class=null;
if(isset($element->getMessages()['ERRNO'])){

switch($element->getMessages()['ERRNO']){
case $key: $class='is-invalid'; $class2='alert-danger';
break;
case "correct".$key: $class='is-valid'; $class2='alert-success';
break;
}
}

echo"<div class='custom-control custom-radio'>
<input type='radio' id='radio_".$key."' name='".$element->getName()."' class='custom-control-input ".$class."' value='".$key."' ".$check.">
<label class='custom-control-label' for='radio_".$key."'>$val</label>
</div>
";

}//3rd foreach (radio element's options)
echo"<div class='alert $class2' role='alert'>";
echo isset($element->getMessages()['ERRDESC']) ? $element->getMessages()['ERRDESC']:null;
echo "</div>";
}//2nd foreach (radio element)
echo "</fieldset>";

}//1st foreach (fieldset)

Знаете ли вы лучшее решение, чтобы получить и отформатировать параметры радио Signle?

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …