Reputation: 13
I know this topic was discussed 2 years ago. But I stuck on difficulty that I would like to solve.
I would like to create a zf3 form which contains more than two Select Element.
I would like to populate them with data coming from different repositories (options values of each Select item come from distinct repository).
First all, I tried to pass the service manager (from where I can access to my repositories) in the constructor of my form but I heard that this solution is not suitable at all.
So how can I include multiples repositories in my form to populate my Select Elements?
Upvotes: 1
Views: 609
Reputation: 1308
Select
module.config.php
)type
for your form elementsSelect
, like BrandSelect
namespace MyModule\Form\Element;
use Laminas\Form\Element\Select;
class BrandSelect extends Select {
protected $repository;
public function __construct($repository, $name = null, $options = []) {
parent::__construct($name, $options);
$this->repository = $repository;
}
/**
* Initialize the element
*
* @return void
*/
public function init() {
$valueOptions = [];
foreach ($this->repository->fetchBrands() as $brand) {
$valueOptions[$brand->getBrandId()] = $brand->getName();
}
asort($valueOptions);
$this->setValueOptions($valueOptions);
}
}
namespace MyModule\Form\Element;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Interop\Container\ContainerInterface;
use MyModule\Db\Repository;
class BrandSelectFactory implements FactoryInterface {
public function __invoke(ContainerInterface $container, $requestedName, $options = null): BrandSelect {
$repository = $container->get(Repository::class);
return new BrandSelect($repository);
}
}
module.config.php
)namespace MyModule;
return [
// ..
// Other configs
// ..
'form_elements' => [
'factories' => [
Form\Element\BrandSelect::class => Form\Element\BrandSelectFactory::class
]
]
];
type
for your form elements. init()
method, otherwise it will not work. I also added the InputFilterProviderInterface
.module.config.php
configuration, always under the form_elements
key (as did for the BrandSelect
):namespace MyModule\Form;
use Laminas\Form\Form;
use Laminas\InputFilter\InputFilterProviderInterface;
class BrandForm extends Form implements InputFilterProviderInterface {
public function __construct($name = null, $options = []) {
parent::__construct($name, $options);
}
// IT IS REALLY IMPORTANT TO ADD ELEMENTS IN INIT METHOD!
public function init() {
parent::init();
$this->add([
'name' => 'brand_id',
'type' => Element\BrandSelect::class,
'options' => [
'label' => 'Brands',
]
]);
}
public function getInputFilterSpecification() {
$inputFilter[] = [
'name' => 'brand_id',
'required' => true,
'filters' => [
['name' => 'Int']
]
];
return $inputFilter;
}
}
service manager
, but the FormElementManager
.BrandController
:<?php
namespace MyModule\Controller;
use Laminas\Form\FormElementManager;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;
class BrandController extends AbstractActionController {
private $formManager;
public function __construct(FormElementManager $formManager) {
$this->formManager = $formManager;
}
public function addBrandAction() {
$form = $this->formManager->get(\MyModule\Form\BrandForm::class);
// Do stuff
return new ViewModel([
'form' => $form
]);
}
}
namespace MyModule\Controller;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Interop\Container\ContainerInterface;
class BrandControllerFactory implements FactoryInterface {
public function __invoke(ContainerInterface $container, $requestedName, $options = null): BrandController {
$formManager = $container->get('FormElementManager');
return new BrandController($formManager);
}
}
which must be configured under controllers
key in module.config.php
:
namespace MyModule;
return [
// ..
// Other configs
// ..
'controllers' => [
'factories' => [
Controller\BrandController::class => Controller\BrandControllerFactory::class
],
],
'form_elements' => [
'factories' => [
Form\Element\BrandSelect::class => Form\Element\BrandSelectFactory::class
]
]
];
Upvotes: 2