У меня довольно сложная форма, которая представлена в виде вкладок. Любой из наборов полей в форме должен быть заполнен, поэтому я ищу возможность использования OptionalInputFilter. Набор полей, с которым у меня проблема, представляет собой коллекцию. Я настроил входной фильтр для работы с коллекцией нормально, но дополнительный аспект, похоже, не работает. Чтобы было ясно, желаемый эффект заключается в том, что пользователь может либо добавить коллекцию элементов, каждый из которых соответствует / подтвержден, либо пользователь оставляет его пустым, и он проходит проверку.
Рассматриваемый набор полей :
class EventFieldset extends Fieldset
{
public function __construct($name = null, $options = [])
{
parent::__construct('Events', $options);
}
public function init()
{
$this->add([
'name' => 'date',
'type' => Date::class,
'options' => [
'label' => 'Date',
'label_attributes' => [
'class' => 'col-form-label'
],
],
'attributes' => [
'class' => 'form-control ',
'required' => true,
],
]);
$this->add([
'name' => 'description',
'type' => Textarea::class,
'options' => [
'label' => 'Description',
'label_attributes' => [
'column' => 'md-2',
'class' => 'col-form-label'
],
],
'attributes' => [
'class' => 'form-control',
'minlength' => '10',
'required' => true,
],
]);
$this->add([
'name' => 'hours',
'type' => Text::class,
'options' => [
'label' => 'Hours',
'label_attributes' => [
'column' => 'md-2',
'class' => 'col-form-label'
],
'column' => 'md-10'
],
'attributes' => [
'class' => 'has-event-duration duration-only form-control'
],
]);
}
}
Входной фильтр для указанного выше набора полей:
class EventInputFilter extends OptionalInputFilter
{
public function init()
{
parent::init();
$this->add([
'name' => 'date',
'validators' => [
[
'name' => Date::class,
'options' => [
'format' => 'Y-m-d',
'strict' => true,
]
],
],
'filters' => [
['name' => StripTags::class],
[
'name' => DateTimeFormatter::class,
'options' => [
'format' => 'Y-m-d'
]
]
]
]);
$this->add([
'name' => 'description',
'required' => true,
'validators' => [
[
'name' => StringLength::class,
'options' => [
'min' => 5,
'max' => 25600
]
]
],
'filters' => [
['name' => StripTags::class],
['name' => StringTrim::class]
]
]);
$this->add([
'name' => 'hours',
'required' => true,
'validators' => [
['name' => AlnumValidator::class],
],
'filters' => [
['name' => StripTags::class],
['name' => Alnum::class]
]
]);
}
}
Обратите внимание, как он расширяет OptionalInputFilter.
Форма:
class MyForm extends Form
{
public function init()
{
parent::init();
//other elements / fieldsets removed for brevity
$this->add([
'name' => 'manualRecords',
'type' => ManuallyEnteredRecordsFieldset::class,
]);
$this->add([
'type' => Csrf::class,
'name' => 'csrf',
'options' => [
'csrf_options' => [
'timeout' => 600,
],
],
]);
$this->add([
'name' => 'Submit',
'type' => Submit::class,
'options' => [
'label' => 'Submit',
'variant' => 'outline-primary'
],
'attributes' => [
'class' => 'btn btn-primary',
'value' => 'Submit'
]
]);
}
}
class ManuallyEnteredRecordFieldset extends Fieldset
{
public function init()
{
//other elements here - removed for brevity
$this->add([
'name' => 'Events',
'type' => Collection::class,
'options' => [
'count' => 1,
'allow_add' => true,
'should_create_template' => true,
'target_element' => [
'type' => EventFieldset::class
],
]
]);
Наконец, в фабрику форм добавлен входной фильтр:
class MyFormFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$form = new MyForm();
$form->setInputFilter($this->getInputFilter($container->get('InputFilterManager')));
return $form;
}
protected function getInputFilter(InputFilterPluginManager $inputFilterPluginManager) : InputFilter
{
//other input filters applied - removed for brevity
$eventInputFilter = $inputFilterPluginManager->get(EventInputFilter::class);
$baseInputFilter = new InputFilter();
$collectionInputFilter = new CollectionInputFilter();
$collectionInputFilter->setInputFilter($eventInputFilter);
$manualRecordInputFilter = new OptionalInputFilter(); //note - also an OptionalInputFilter
$manualRecordInputFilter->add($collectionInputFilter, 'Events');
$baseInputFilter->add($manualRecordInputFilter, 'manualRecords');
return $baseInputFilter;
}
}
Когда я отправляю эту форму с имеющимися данными, даже с добавленными 1-> N строками коллекции, она проверяется нормально. Без каких-либо введенных данных (которые, как я ожидал, все же пройдут, поскольку он построен из дополнительного входного фильтра), я получаю следующие сообщения об ошибках входного фильтра:
["manualRecords"] => array(2) {
["Events"] => array(1) {
[0] => array(3) {
["date"] => array(2) {
["isEmpty"] => string(36) "Value is required and can't be empty"
}
["description"] => array(1) {
["isEmpty"] => string(36) "Value is required and can't be empty"
}
["hours"] => array(1) {
["isEmpty"] => string(36) "Value is required and can't be empty"
}
}
}
Это не то, как должно быть поведение согласно: https://docs.laminas.dev/laminas-inputfilter/optional-input-filters/