Custom Form Element Factory - where are the options? - php

I'm trying to create a custom form element, fundamentally everything works -- but I'd like to intake 'name' properly. Let me explain:
use Application\Form\Element\Custom;
class CustomForm extends Form
{
public function init(){
$this->add([
'name' => 'themagicname',
'type' => Custom::class,
]);
}
}
I have a form that instantiates a Custom element, the custom element is mapped in my module.config.php as:
use Application\Form\Element\Custom;
use Application\Factory\Form\Element\CustomFactory;
return [
//...
'form_elements' => [
'factories' => [
Custom::class => CustomFactory::class,
],
],
//...
];
The factory looks like this, and gets fired properly:
class CustomFactory implements Factory
{
public function createService( ServiceLocatorInterface $serviceLocator )
{
/**
* #var \Doctrine\Common\Persistence\ObjectRepository $userRepository
* #var \Zend\InputFilter\InputFilterPluginManager $serviceLocator
*/
// bunch of factory-ish things here
return new Custom( 'helpppp', ... );
}
}
Now the conundrum: Where I wrote 'helpppp', one would ideally transport'themagicname' that was passed during creation at the Form level. How does that config array, get ferried over to the factory? I've tried MutableCreationOptionsInterface but it doesn't seem to apply here.
Thanks for your guidance.

Related

Zend Form without binding object and access to fieldset data

I have Zend Framework 2 Form:
$form = new Form();
$form->add(
[
'name' => 'input1',
'type' => 'Text',
]
);
$fieldset1 = new Fieldset();
$fieldset1->setName('field1');
$fieldset1->add(
[
'name' => 'input2',
'type' => 'Text',
]
);
and controller for it:
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$data = $form->getData();
var_dump($this->params()->fromPost(),$data);
exit;
}
}
and problem is that when i dump values i get this:
array (size=3)
'input1' => string 'a' (length=1)
'input2' => string 'b' (length=1)
array (size=3)
'input1' => string 'a' (length=1)
'field1' =>
array (size=1)
'input2' => null
So what i do wrong? Because now in "field2" key i get "nulll". how i can get access to fieldset(s) data (after filters, validation etc) in that case?
Update: as i see, when i add to POST
<input name="field1[input2]" value="test" />
i get expected result. but why zendform not generate html like that, but (wrongly) generate:
<input name="input2" />
what i do wrong?
here is a complete more or less simple example with entities, input filters, hydrators and validators für zf2 form use with fieldsets.
First set up the fieldset class you want to use.
namespace Application\Form;
use Zend\Filter\StripTags;
use Zend\Form\Fieldset;
use Zend\Form\Element\Text;
use Zend\InputFilter\InputFilterProviderInterface;
class MyFieldset extends Fieldset implements InputFilterProviderInterface
{
/**
* #see \Zend\Form\Element::init()
*/
public function init()
{
$this->add([
'name' => 'input2',
'type' => Text::class,
'required' => true,
'attributes' => [
'id' => 'input2',
'required' => true,
],
'options' => [
'label' => 'The label for input2 of this fieldset',
],
]);
}
/**
* #see \Zend\InputFilter\InputFilterProviderInterface::getInputFilterSpecification()
*/
public function getInputFilterSpecification()
{
return [
'input2' => [
'required' => true,
'filters' => [
[
'name' => StripTags::class,
],
],
],
];
}
}
Your fieldset class defines all input elements within the fieldset. I encurage you to work with entity classes and factories. this is also the reason this example works with the init method. The init method is called after the constructor of the class. While using factories you can use the constructor for defining stuff you need for your fieldset or form class. For example depending input fields and so on.
Next you should write an entity for your fieldset.
namespace Application\Entity;
class MyFieldsetEntity
{
protected $input2;
public function getInput2()
{
return $this->input2;
}
public function setInput2($input2)
{
$this->input2 = $input2;
return $this;
}
}
This simple entity class will handle the data you have sent to your controller. One of the benefits of a entity class is, that you can define default values in it. If the post data should be empty for some reason, the entity can return default values. Let 's put it all together in a factory for your fieldset.
namespace Application\Form\Service;
class MyFieldsetFactory
{
public function __invoke(ContainerInterface $container)
{
$hydrator = new ClassMethods(false);
$entity = new MyFieldsetEntity();
return (new MyFieldset())
->setObject($entity)
->setHydrator($hydrator);
}
}
Why is using a factory smart? Because you can use all the favors of an object orientated environment. You can define all the stuff you need in a factory. for this purpose we create a fieldset instance with an entity and a hydrator. This will hydrate the fieldset with the filtered and validated data.
All that we need now is the form and an entity for the form.
namespace ApplicationForm;
use Zend\Form\Element\Text;
use Zend\Form\Form;
class MyForm extends Form
{
public function __construct($name = null, array $options = [])
{
parent::__construct($name, $options);
$this->setAttribute('method', 'post');
$this->add([
'name' => 'input1',
'type' => Text::class,
'required' => true,
'attributes' => [
'id' => 'input2',
'required' => true,
],
'options' => [
'label' => 'The label for input2 of this fieldset',
],
]);
// here goes your fieldset (provided, that your fieldset class is defined in the form elements config in your module.config.php file)
$this->add([
'name' => 'fieldset1',
'type' => MyFieldset::class,
]);
}
}
That 's all for your form. This form is implementing your fieldset. That 's all. Now we need a validator and an entity for this form.
namespace Application\Entity;
class MyFormEntity
{
protected $input1;
// we will hydrate this property with the MyFieldsetEntity
protected $fieldset1;
public function getInput1()
{
return $this->input1;
}
public function setInput1($input1)
{
$this->input1 = $input1;
return $this;
}
public function getFieldset1()
{
return $fieldset1;
}
public function setFieldset1($fieldset1)
{
$this->fieldset1 = $fieldset1;
return $this;
}
}
... and finally the input filter class for your form. An input filter filters and validates your form data. You should use always an input filter for security reasons and many more.
namespace Application\InputFilter;
use Zend\InputFilter\InputFilter;
use Zend\Filter\StripTags;
use Zend\Filter\StringTrim;
class MyFormInputFilter extends InputFilter
{
public function __construct()
{
$this->add([
'name' => 'input1',
'required' => true,
'filters' => [
[
'name' => StripTags::class,
],
[
'name' => StringTrim::class,
],
],
]);
}
}
Simple, hm? This input filter class just sets some input filters for your input 1 form element. The fieldset element is filtered by itself because it implements the InputFilterProviderInterface interface. You don 't hav to define more in the input filter class for your form.
Put it together in a factory ...
namespace Application\Form\Service;
class MyFormFactory
{
public function __invoke(ContainerInterface $container)
{
$entity = new MyFormEntity();
$inputFilter = new MyFormInputFilter();
$hydrator = (new ClassMethods(false))
->addStrategy('fieldset1', new Fieldset1Strategy());
$form = (new MyForm())
->setHydrator($hydrator)
->setObject($entity)
->setInputFilter($inputFilter);
return $form;
}
}
This is the factory for your form. This factory contains a special feature. It adds a hydrator strategy to your hydrator instance. this strategy will hydrate your entity with the fieldset data, if there is a 'fieldset1' key in your post array.
This will be the hydrator strategy class ...
namespace Application\Hydrator\Strategy;
use Zend\Hydrator\Strategy\DefaultStrategy;
use Zend\Hydrator\ClassMethods;
use Application\Entity\MyFieldsetEntity;
class Fieldset1Strategy extends DefaultStrategy
{
public function hydrate($value)
{
if (!$value instanceof MyFieldsetEntity) {
return (new ClassMethods(false))->hydrate($value, new MyFieldsetEntity());
}
return $value;
}
}
This strategy will add the MyFieldsetEntity to your form entity.
The last step is defining all that stuff in the config file module.config.php
// for the forms config provides the form elements key
'form_elements' => [
'factories' => [
YourForm::class => YourFormFactory::class,
YourFormFieldset::class => YourFormFactory::class,
]
],
// can be accessed with $container->get('FormElementsManager')->get(YourFormFieldset::class);
Usage Example
This is a small example how to use it in a controller.
class ExampleController extends AbstractActionController
{
protected $form;
public function __construct(Form $form)
{
$this->form = $form;
}
public function indexAction()
{
if ($this->getRequest()->isPost()) {
$this->form->setData($this->getRequest()->getPost());
if ($this->form->isValid()) {
$data = $this->form->getData();
\Zend\Debug\Debug::dump($data);
die();
// output will be
// MyFormEntity object
// string input1
// MyFieldsetEntity fieldset1
// string input2
// for fetching the filtered data
// $data->getInput1();
// $data->getFieldset1()->getInput2();
}
}
return [
'form' => $this->form,
];
}
}
In your view / template you can display the form with the different form view helpers zf2 provides.
$form = $this->form;
$form->setAttribute('action', $this->url('application/example'));
$form->prepare();
echo $this->form()->openTag($form);
// outputs the single text input element
echo $this->formRow($form->get('input1'));
// outputs the complete fieldset
echo $this->formCollection($form->get('fieldset1'));
Sure, this answer is a bit complex. But I encurage you to have a try. Once implemented in your application, this kind of form management is the easiest way you can use. Keep in mind, that just handling the raw post data can be insecure as hell. If you want the filtered data with the benefit of objects it is recommended using entities, input filters and all the other cool stuff zend framework comes with.
You have not added the fieldset to the form.
$form->add($fieldset1);
You forgot to prepare the form. It's in $form->prepare() that the names for the elements are changed to include the prefix for the fieldset.
If you use the "form" view helper, that will prepare the form for you. If you don't, you'll have to call "prepare" it yourself, for example in the view, just before you output the open tag:
$this->form->prepare();

zf2/zf3 register custom validator and injecting it into fieldset

I have a custom validator:
class CustomValidator extends RecordExists
{
public function isValid($value, array $context = null)
{
// some behaviour
return parent::isValid($value);
}
}
This validator has a factory:
class CustomValidatorFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$validator = new CustomValidator();
// preparations for CustomValidator
return $validator;
}
}
CustomValidator and its factory are registered in module.config.php under
'validators' => [
'factories' => [
CustomValidator::class => CustomValidatorFactory::class,
],
],
CustomValidator is attached to a fieldset's input in getInputFilterSpecification() as
'validators' => [
['name' => CustomValidator::class],
]
The fieldset is called via init() method of the form, and the form is called in the controller factory as $container->get('FormElementManager')->get('TheNeededForm').
The problem is that for some reason, CustomValidator gets instantiated not through the CustomValidatorFactory, but getInputFilterSpecification() of the fieldset just creates an instance of new CustomValidator().
How to make the custom validator instantiation through the factory?
PS: I already surfed the internet, and found a similar problem, but the solution given there didn't help: it suggested adding 'abstract_factories' => [FormAbstractServiceFactory::class] in module.config.php, under 'form_elements' directive.
I already answered this question here
https://stackoverflow.com/a/61287283/4685379
Here it is:
In ZF3/Laminas, if a validator is registered as an invokable, you can call the validator in the getInputFilterSpecification() of your form, and no problem. If a validator is instantiated using a factory, you get into trouble. If I understand correctly, even if your form is registered like this
'form_elements' => [
'factories' => [
SomeForm::class => SomeFormFactory::class,
]
]
and your validator:
'validators' => [
'factories' => [
SomeValidator::class => SomeValidatorFactory::class,
]
]
you won't be instantiating the validator via factory. The reason is that the form factory (the one you get like $form->getFormFactory()) has an input filter factory and in there sits default validator chain. And this validator chain has no ValidatorManager attached. And without the ValidatorManager, the default chain cannot map the validator name to the validator factory.
To solve all this headache, in your controller factory do this:
$form->('FormElementManager')->get(SomeForm::class);
$form->getFormFactory()->getInputFilterFactory()
->getDefaultValidatorChain()->setPluginManager($container->get('ValidatorManager'));
and your troubles are over.

Form custom elements with factories

We are used to work with ZF2, but for our last project, we decided to start with ZF3.
Now I am facing a problem in the form creation.
What I want to do is to create a custom select populated with values retrieved from database.
What I did in ZF2 was creating a class extending a select, with the ServiceLocatorAwareInterface, like:
class ManufacturerSelect extends Select implements ServiceLocatorAwareInterface {
public function init() {
$manufacturerTable = $this->getServiceLocator()->get('Car\Model\ManufacturerTable');
$valueOptions = [];
foreach ($manufacturerTable->fetchAll() as $manufacturer) {
$valueOptions[$manufacturer->getManufacturerId()] = $manufacturer->getName();
}
$this->setValueOptions($valueOptions);
}
public function getServiceLocator() {
return $this->serviceLocator;
}
public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
$this->serviceLocator = $serviceLocator;
}
}
Then, to use it in a form, it was enough to give the full name
$this->add(
array(
'name' => 'manufacturer_id',
'type' => 'Car\Form\Element\ManufacturerSelect'
)
);
Now this is not possible anymore, since the service locator was removed and the use of factories is necessary, but I'm struggling to find how to do the same thing.
Keeping in mind to use factories, I tried this configuration in module.config.php:
'form_elements' => [
'factories' => [
'Car\Form\Element\ManufacturerSelect' => function ($services) {
$manufacturerTable = $services->get('Car\Model\ManufacturerTable');
return new ManufacturerSelect($manufacturerTable);
},
'Car\Form\CarForm' => function ($services) {
$manufacturerTable = $services->get('Car\Model\ManufacturerTable');
return new CarForm($manufacturerTable, 'car-form');
}
]
]
Result: factory of CarForm is always called, but factory of ManufacturerSelect is not.
A simple solution would be to populate the select directly in the form class, but I would prefer to use the factory for the element and reuse it everywhere I want, like I was doing in ZF2.
Does anyone already encountered this problem and found a solution?
Do you add that element in "__construct" function? If so try "init"
EDIT:
First of all you don't need to create a custom select to fill in it via database. Just create a form with factory, fetch data from db in factory and pass to form. And use the data in form class as select's value options.
$this-add([
'type' => Element\Select:.class,
'name' => 'select-element'
'options' => [
'label' => 'The Select',
'empty_option' => 'Please choose one',
'value_options' => $this-dataFromDB
]
]);
If you create form as:
new MyForm();
Form Element Manager doesn't trigger custom elements' factories. But;
$container->get('FormElementManager')->get(MyForm::class);
triggers custom elements' factories. Here's a working example. It's working on ZF3.
Config:
return [
'controllers' => [
'factories' => [
MyController::class => MyControllerFactory::class
]
],
'form_elements' => [
'factories' => [
CustomElement::class => CustomElementFactory::class,
MyForm::class => MyFormFactory::class,
]
]
];
don't forget to add 'Zend\Form' to application config's 'modules'.
Element:
class CustomElement extends Text
{
}
Element Factory:
class CustomElementFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
echo 'element factory triggered';
return new CustomElement();
}
}
Fieldset/Form:
class MyForm extends Form
{
public function init()
{
$this
->add([
'type' => CustomElement::class,
'name' => 'name',
'options' => [
'label' => 'label',
],
])
;
}
}
Fieldset/Form Factory:
class MyFormFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
echo 'form factory triggered';
return new MyForm();
}
}
Controller's Factory:
class MyControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
echo 'controller factory triggered';
return new MyController(
$container->get('FormElementManager')->get(MyForm::class);
);
}
}

How can I access Database Adapter in ZF2 Field Set?

I have followed an example and would like to pass the Database adapter to a fieldset to create a drop down menu.
The code below is how i call the fieldset.
How can i access the database adapter in the BrandFieldset class?
$this->add(array(
'type' => 'Application\Form\BrandFieldset',
'name' => 'brand',
'options' => array(
'label' => 'Brand of the product',
),
));
Instantiating a fieldset is responsibility of the FormElementManager. When you try to access a form, form element or fieldset, the FormElementManager knows where to find and how to create it. This behaviour summerized in Default Services section of the framework.
Since the proper way of accessing form elements is retrieving them from FormElementManager, I would write a BrandFieldsetFactory to inject that DB adapter or further dependencies to fieldset on construction to achieve this.
A ZF3 friendly fieldset factory would look like:
<?php
namespace Application\Form\Factory;
use Application\Form\BrandFieldset;
use Interop\Container\ContainerInterface;
class BrandFieldsetFactory
{
/**
* #return BrandFieldset
*/
public function __invoke(ContainerInterface $fem, $name, array $options = null)
{
// FormElementManager is child of AbstractPluginManager
// which makes it a ContainerInterface instance
$adapter = $fem->getServiceLocator()->get('Your\Db\Adapter');
return new BrandFieldset($adapter);
}
}
At this point, BrandFieldset should extend the Zend\Form\Fieldset\Fieldset and it's constructor may look like following:
private $dbAdapter;
/**
* {#inheritdoc}
*/
public function __construct(My/Db/Adapter $db, $options = [])
{
$this->dbAdapter = $db;
return parent::__construct('brand-fieldset', $options);
}
Finally, in module.config.php file I'd have a configuration to tell FormElementManager about this factory:
<?php
use Application\Form\BrandFieldset;
use Application\Form\Factory\BrandFieldsetFactory;
return [
// other config
// Configuration for form element manager
'form_elements' => [
'factories' => [
BrandFieldset::class => BrandFieldsetFactory::class
],
],
];
HINT: The BrandFieldset::init() method will be called automatically by FormElementManager after construction. You can put any post-initialization logic into this method.
Based of these docs I was able to find a solution.
https://framework.zend.com/manual/2.1/en/modules/zend.form.advanced-use-of-forms.html
'form_elements' => array(
'invokables' => array(
'fieldset' => BrandFieldsetFactory::class
)
)
I needed to call the form using the service locator in the controller like below.
$sl = $this->getServiceLocator();
$form = $sl->get('FormElementManager')->get('Application\Form\CreateForm');
In addition I changed the __construct to init.

ZF2 injecting InputFilter into Fieldset not working automatically

I'm building a small application with ZF2 and Doctrine2. Setting it up in such a way as to have a lot of reusable code and technique. However, getting stumped by the fact that my InputFilter is not automatically injected into the Fieldset that it should get associated to.
I've confirmed that the Form that uses the Fieldset works (without the InputFilter). The InputFilter is also visible as present during debugging.
The question then, what am I doing wrong and how to fix having a separate InputFilter, coupled to a Fieldset in ZF2?
Sidenotes:
1 - I am aware that by using the InputFilterInterface I could have the InputFilter inside of the Fieldset class with the getInputFilterSpecification() function. However, as I'm trying to keep it DRY and reusable, it wouldn't do to have to copy it if I were to create an API that needs to use the Entity and InputFilter, but can only have the latter coupled with a Fieldset.
2 - A lot of Abstract classes are used, where used I'll indicate in the snippets what they have that's relevant
3 - The problem line is in CustomerFieldsetFactory.php
=========================================================================
Entity: Customer.php
/**
* Class Customer
* #package Customer\Entity
*
* #ORM\Entity
* #ORM\Table(name="customers")
*/
class Customer extends AbstractEntity //Contains $id
{
/**
* #var string
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
}
Form: CustomerForm.php
class CustomerForm extends AbstractForm
{
public function __construct($name = null, array $options)
{
parent::__construct($name, $options); // Adds CSRF
}
public function init()
{
$this->add([
'name' => 'customer',
'type' => CustomerFieldset::class,
'options' => [
'use_as_base_fieldset' => true,
],
]);
//Call parent initializer. Check in parent what it does.
parent::init(); //Adds submit button if not in form
}
}
Fieldset: CustomerFieldset.php
class CustomerFieldset extends AbstractFieldset //Contains EntityManager property and constructor requirement (as we're managing Doctrine Entities here)
{
public function init()
{
$this->add([ //For now id field is here, until InputFilter injection works
'name' => 'id',
'type' => Hidden::class,
'attributes' => [
'id' => 'entityId',
],
]);
$this->add([
'name' => 'name',
'type' => Text::class,
'options' => [
'label' => _('Name'),
],
]);
}
}
InputFilter: CustomerInputFilter.php
class CustomerInputFilter extends AbstractInputFilter
{
public function init()
{
parent::init();
$this->add([
'name' => 'name',
'required' => true,
'filters' => [
['name' => StringTrim::class],
['name' => StripTags::class],
],
'validators' => [
[
'name' => StringLength::class,
'options' => [
'min' => 3,
'max' => 255,
],
],
],
]);
}
}
Above the classes. Below the Factories
FormFactory: CustomerFormFactory.php
class CustomerFormFactory implements FactoryInterface, MutableCreationOptionsInterface
{
/**
* #var array
*/
protected $options;
/**
* #param array $options
*/
public function setCreationOptions(array $options)
{
//Arguments checking removed
$this->options = $options;
}
/**
* #param ServiceLocatorInterface|ControllerManager $serviceLocator
* #return CustomerForm
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$serviceManager = $serviceLocator->getServiceLocator();
$form = new CustomerForm($this->options['name'], $this->options['options']);
$form->setTranslator($serviceManager->get('translator'));
return $form;
}
}
FieldsetFactory: CustomerFieldsetFactory.php
class CustomerFieldsetFactory implements FactoryInterface, MutableCreationOptionsInterface
{
/**
* #var string
*/
protected $name;
public function setCreationOptions(array $options)
{
//Argument checking removed
$this->name = $options['name'];
}
public function createService(ServiceLocatorInterface $serviceLocator)
{
$serviceManager = $serviceLocator->getServiceLocator();
$fieldset = new CustomerFieldset($serviceManager->get('Doctrine\ORM\EntityManager'), $this->name);
$fieldset->setHydrator(new DoctrineObject($serviceManager->get('doctrine.entitymanager.orm_default'), false));
$fieldset->setObject(new Customer());
$fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class));
//RIGHT HERE! THE LINE ABOVE IS THE ONE THAT DOES NOT WORK!!!
return $fieldset;
}
}
InputFilterFactory: CustomerInputFilterFactory.php
class CustomerInputFilterFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$repository = $serviceLocator->getServiceLocator()
->get('Doctrine\ORM\EntityManager')
->getRepository(Customer::class);
return new CustomerInputFilter($repository);
}
}
Config: module.config.php
'controllers' => [
'factories' => [
CustomerController::class => CustomerControllerFactory::class,
],
],
'form_elements' => [
'factories' => [
CustomerForm::class => CustomerFormFactory::class,
CustomerFieldset::class => CustomerFieldsetFactory::class,
],
],
'input_filters' => [
'factories' => [
CustomerInputFilter::class => CustomerInputFilterFactory::class,
],
],
'service_manager' => [
'invokables' => [
CustomerControllerService::class => CustomerControllerService::class,
],
],
I am hoping one of you can help me out here.
EDIT: Update with actual error
The following line in the CustomerFieldset.php (above) triggers the error.
$fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class));
The error:
Fatal error: Call to undefined method Customer\Fieldset\CustomerFieldset::setInputFilter() in D:\htdocs\server-manager\module\Customer\src\Customer\Factory\CustomerFieldsetFactory.php on line 57
As seen in the above snippet, the InputFilter (and it's Factory) are known the the InputFilterManager.
The error states it does not know the getInputFilter() function on the Fieldset. Which is correct in a way, it doesn't exist. The question then is, how to have the function exist so that injecting the InputFilter will work, or how to bind this InputFilter to the Fieldset?
EDIT 2: Update based on Wilt's answer
Added use InputFilterAwareTrait to Abstract class AbstractInputFilter to create following (from answer):
use Zend\InputFilter\InputFilterAwareTrait;
abstract class AbstractFieldset extends Fieldset
{
use InputFilterAwareTrait;
// ... Other code
}
Turns out that I had another mistake in the (original) code above as well:
In file module.config.php the input_filters should've been input_filter_specs. This was (after using the Trait) a Invalid Factory registered error (titled ServiceNotCreatedException).
The following might be of use to someone, the Factory to create a Fieldset with Hydrator, Object and Inputfilter has the following createService() function:
public function createService(ServiceLocatorInterface $serviceLocator)
{
/** #var ServiceLocator $serviceManager */
$serviceManager = $serviceLocator->getServiceLocator();
/** #var CustomerRepository $customerRepository */
$customerRepository = $serviceManager->get('Doctrine\ORM\EntityManager')->getRepository(Customer::class);
$fieldset = new CustomerFieldset($serviceManager->get('Doctrine\ORM\EntityManager'), $this->name);
$fieldset->setHydrator(new DoctrineObject($serviceManager->get('doctrine.entitymanager.orm_default'), false));
$fieldset->setObject(new Customer());
$fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class, $customerRepository));
return $fieldset;
}
There is lots of information added to your question. I'd suggest you try to narrow down your question in the future. Read more on the guidelines for a good question here: How to create a Minimal, Complete, and Verifiable example.
Zend framework provides a InputFilterAwareTrait with both the setInputFilter and getInputFilter methods. You can easily implement/use this trait inside your CustomerFieldset class:
use Zend\InputFilter\InputFilterAwareTrait;
class CustomerFieldset extends AbstractFieldset
{
use InputFilterAwareTrait;
//...remaining code
}
In case you want the inputfilter in all classes that extend your abstract AbstractFieldset class you could also decide to add the trait there:
use Zend\InputFilter\InputFilterAwareTrait;
class AbstractFieldset
{
use InputFilterAwareTrait;
//...remaining code
}
See the following question: How to validate nested fieldsets. Fieldsets don't contain InputFilters but you should extend your base InputFilter of your form.
Create an InputFilter for each Fieldset and add them, with the same name as your fieldset, to your InputFilter of your form. As seen within the answer of the other question I linked.
If you don't want to do this you might consider working with InputSpecification.

Categories