Change Fieldset Fields' required parameter dynamically - php

I have a moneyFieldset with 2 fields, amount and currency.
class MoneyFieldset ...
{
public function __construct($name = null, $options = array())
{
parent::__construct($name, $options);
$this->setHydrator(...);
$this->add(array(
'name' => 'currency',
'type' => 'select',
'options' => array(
'value_options' => \Core\Service\Money::getAvailableCurrencies(true),
),
'attributes' => array(
'value' => \Core\Service\Money::DEFAULT_CURRENCY,
),
));
$this->add(array(
'name' => 'amount',
'type' => 'text',
));
}
}
public function getInputFilterSpecification()
{
$default = [
'amount' => [
'required' => false,
'allow_empty' => true,
'filters' => [
['name' => AmountFilter::class]
],
'validators' => [
]
],
'currency' => [
'required' => false,
'allow_empty' => true,
'filters' => [
['name' => StringToUpper::class]
],
'validators' => [
]
]
];
return \Zend\Stdlib\ArrayUtils::merge($default, $this->filterSpec, true);
}
I'm using moneyFieldset in my other fieldsets like this:
// Price Field
$this->add(array(
'name' => 'price',
'type' => 'form.fieldset.moneyFieldset',
'attributes' => array(
'required' => true,
'invalidText' => 'Please type an amount'
),
'options' => array(
...
),
));
When I set filter like this:
function getInputFilterSpecification()
{
'price' => [
'required' => true,
'allow_empty' => false,
],
}
It's not working because price has 2 fields, so how can I say price[amount] and price[curreny] is required?

You can provide the input specifications for the nested fieldset (within the context of the form) using the following array structure.
public function getInputFilterSpecification()
{
return [
// ...
'price' => [
'type' => 'Zend\InputFilter\InputFilter',
'amount' => [
'required' => true,
],
'currency' => [
'required' => true,
]
],
//...
];
}
If you are dynamically modifying the values of the input filter it might be worth considering creating the validator using a service factory class and then attaching it to a form using the object API rather than arrays.

As I said in #AlexP's comment, a field, or a group of field declared as Required like this :
function getInputFilterSpecification()
{
'price' => [
'required' => true,
'allow_empty' => false,
],
}
Not means that it will be print an html like this :
<input type="text" required="required"/>
It just check when you'll do $form->isValid() if your fields are empty and required or other checks.
To achieve that, you just have to set in attributes that you want to require those fields. As you already did. Attributes can add, same as class attribute, html code to an input.
P.S : AlexP's answer is the best answer I just give more info about it.

Related

PHP Laminas DoctrineObjectInputFilter get value of other property in Callback input filter

I am working with Laminas DoctrineObjectInputFilter and want to get value of other property in Callback input filter like this code is in init function of Filter class which extends DoctrineObjectInputFilter
// input filter whose value is required
$this->add([
'name' => 'name',
'allow_empty' => false,
'filters' => []
]);
// Input filter in which I want value of input name
$this->add([
'name' => 'value',
'allow_empty' => true,
'filters' => [
[
'name' => 'Callback',
'options' => [
'callback' => function ($value) {
$name = // want to get property name value here
if (key_exists($name, $this->applicationConfig) && gettype($value) === 'string') {
return trim(strip_tags($value));
}
else {
return trim($value);
}
return $value;
},
],
],
],
]);
have checked $this->getRawValues() but its returning null for all inputs.
a bit late but I guess you 're searching for $context. Since the value of name is in the same InputFilter instance, you can simply use $context in your callback function.
<?php
declare(strict_types=1);
namespace Marcel\InputFilter;
use Laminas\Filter\StringTrim;
use Laminas\Filter\StripTags;
use Laminas\Filter\ToNull;
use Laminas\InputFilter\InputFilter;
use Laminas\Validator\Callback;
class ExampleInputFilter extends InputFilter
{
public function init()
{
parent::init();
$this->add([
'name' => 'name',
'required' => true,
'allow_empty' => false,
'filters' => [
[ 'name' => StripTags::class ],
[ 'name' => StringTrim::class ],
[
'name' => ToNull::class,
'options' => [
'type' => ToNull::TYPE_STRING,
],
],
],
]);
$this->add([
'name' => 'value',
'required' => true,
'allow_empty' => true,
'filters' => [],
'validators' => [
[
'name' => Callback::class,
'options' => [
'callback' => function($value, $context) {
$name = $context['name'];
...
},
],
],
],
]);
}
}

DoctrineModule\Form\Element\ObjectSelect - Selected values and auto submit on change

I have the following code of select form:
$this->add([
'name' => 'username',
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'options' => [
'object_manager' => $this->getObjectManager(),
'target_class' => 'Application\Entity\Player',
'property' => 'username',
'is_method' => true,
'empty_option' => '-- Please select Unsername --',
'find_method' => [
'name' => 'getUsername',
],
'label_generator' => function ($targetEntity) {
return $targetEntity->getId() ;
},
],
]);
My questions are:
Is it posible selected value to display as default?
(example: https://www.w3schools.com/tags/att_option_selected.asp)
Is it possible to do submit when changing position
Thank in advance for your help

Zend Form 2 multiselect field is empty after validation

I'm not sure what's going on. I'm using Zend Form 2 with a multiselect field. When I submit the code, the values exist in post. When I run the values through zend form 2, I get no validation errors but the multiselect field is suddenly empty.
class Form extends \Zend\Form\Form
{
// input filter to set up filters and validators
protected $myInputFilter;
public function __construct()
{
// create the zend form
parent::__construct();
// make it a bootstrap form
$this->setAttribute('class', 'form-horizontal');
$this->setAttribute('role', 'form');
// set the default objects we'll use to build the form validator
$this->myInputFilter = new \Zend\InputFilter\InputFilter();
}
}
class AddPublicationForm extends Form
{
public function __construct()
{
// create the zend form
parent::__construct();
$this->setAttribute('class', 'form-horizontal');
$this->setAttribute('id', 'add-publication-form');
$this->add([
'name' => 'author[]',
'attributes' => [
'class' => 'form-control',
'data-placeholder' => 'Author',
'multiple' => 'multiple',
'placeholder' => 'Author',
],
'required' => false,
'type' => \Zend\Form\Element\Select::class,
'options' => [
'value_options' => [
'check1' => 'check1',
'check2' => 'check2',
],
],
]);
$this->myInputFilter->add([
'filters' => [],
'name' => 'author[]',
'required' => false,
'validators' => [],
]);
// attach validators and filters
$this->setInputFilter($this->myInputFilter);
// prepare the form
$this->prepare();
}
}
These are the zend form objects that I am using. I am using Slim Framework 2 as my backend. Here is the controller object:
public function addAction()
{
$request = $this->app->request;
$form = new Form\AddPublicationForm();
if ($request->isPost()) {
$params = $request->params();
// DUMP 1: exit('<pre>'.print_r($params, true).'</pre>');
$form->setData($params);
if ($form->isValid()) {
$data = $form->getData();
// DUMP 2: exit('<pre>'.print_r($data, true).'</pre>');
}
}
}
DUMP 1:
Array
(
[author] => Array
(
[0] => check1
[1] => check2
)
}
DUMP 2:
Array
(
[author[]] =>
)
I realize that I could very easily just bypass the validation here because I'm not using any validators on that field. I'm more concerned with the underlying cause though.
Why is the validated author data empty?
When you specify multiple in attributes, Zend\Form and Zend\InputFilter add []after the name. You should not do it yourself otherwise, in the html code, the element appears under the name author[][] and the setData method don't match.
To see it, replace required by true and look at the html code of the form.
$this->add([
'name' => 'author',
'attributes' => [
'class' => 'form-control',
'data-placeholder' => 'Author',
'multiple' => 'multiple',
'placeholder' => 'Author',
],
'required' => false,
'type' => \Zend\Form\Element\Select::class,
'options' => [
'value_options' => [
'check1' => 'check1',
'check2' => 'check2',
],
],
]);
$this->myInputFilter->add([
'filters' => [],
'name' => 'author',
'required' => false,
'validators' => [],
]);

zend framework 3 Select tag validation

I am getting the error:
The input was not found in the haystack
After form post. Please see the selection tag code lines below:
// Add "roles" field
$this->add([
'type' => 'select',
'name' => 'roles',
'attributes' => [
'multiple' => 'multiple',
'options'=>$this->role_desc,
'inarrayvalidator' => false,
'class'=>'form-control'
],
'options' => [
'label' => 'Role(s)',
],
]);
// Add input for "roles" field
$inputFilter->add([
'class' => ArrayInput::class,
'name' => 'roles',
'required' => true,
'haystack'=>$this->role_ids,
'filters' => [
['name' => 'ToInt'],
],
'validators' => [
['name'=>'GreaterThan', 'options'=>['min'=>1]],
['name'=>'InArray', 'options'=>['haystack'=>$this-
>role_ids]]
],
]);
The InArray seems to be validating well, lm just no sure what is bringing up the exception. Thank you in advance.
Actually , your issue is similar to link
To solve this, change your validators definition to:
'validators' => [
['name'=>'GreaterThan', 'options'=>['min'=>1]],
[
'name' => 'Explode',
'options' => array(
'validator' => [
'name'=>'InArray',
'options'=> [
'haystack'=>$this->role_ids
]
]
)
]
],
Unfortunately, I do not think there is a "cleaner" way to do this.
Alternately, Maybe you could use the MultiCheckbox.

zf2/zf3 how to validate dependent inputs in collection's fieldset?

I have a form. The form has a Collection whose target element is a fieldset with a checkbox and a couple of text fields. The fieldset attached as the target element to Collection looks like this (simplified to avoid too much code):
class AFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct(HydratorInterface $hydrator)
{
parent::__construct();
$this->setHydrator($hydrator)
->setObject(new SomeObject());
$this->add([
'type' => Hidden::class,
'name' => 'id',
]);
$this->add([
'type' => Checkbox::class,
'name' => 'selectedInForm',
]);
$this->add([
'type' => Text::class,
'name' => 'textField1',
]);
$this->add([
'type' => Text::class,
'name' => 'textField2',
]);
}
public function getInputFilterSpecification()
{
return [
'selectedInForm' => [
'required' => false,
'continue_if_empty' => true,
'validators' => [
['name' => Callback::class // + options for the validator],
],
],
'id' => [
'requred' => false,
'continue_if_empty' => true,
],
'textField1' => [
'required' => false,
'continue_if_empty' => true,
'validators' => [
['name' => SomeValidator::class],
],
],
'textField2' => [
'required' => true,
'validators' => [
['name' => SomeValidator::class],
],
],
],
}
}
I'd like to validate textField1 and textField2 based on if selectedInForm checkbox is checked in the form.
How could I do this?
I though of using a Callback validator for selectedInForm checkbox like this:
'callback' => function($value) {
if ($value) {
$this->get('textField1')->isValid();
// or $this->get('textField1')->getValue() and do some validation with it
}
}
but the problem with it is that, for some reason, the posted value of textField1 value isn't attached to the input yet. Same is true for textField2.
Two option is available. One is where you started, with callback validators.
The other one is to write a custom validator, and to make it reusable I recommend this solution.
<?php
use Zend\Validator\NotEmpty;
class IfSelectedInFormThanNotEmpty extends NotEmpty
{
public function isValid($value, array $context = null): bool
{
if (! empty($context['selectedInForm']) && $context['selectedInForm']) {
return parent::isValid($value);
}
return true;
}
}
And then you can use it as every other validator:
'textField2' => [
'required' => true,
'validators' => [
['name' => IfSelectedInFormThanNotEmpty::class],
],
],
This may not be your exact case, but I hope it helped to get the idea.
You may define options to make it more reusable with a configurable conditional field in public function __construct($options = null).

Categories