Short answer:
- Create a class that extends the
Select
- Create a factory for such class
- Add this custom element in your module configuration (
module.config.php
)
- Use this class as
type
for your form elements
- Retrieve the form through the form manager
- Example, for controllers, adapt the controller's factory
Detailed answer:
- Create a class that extends the
Select
, like BrandSelect
namespace MyModuleFormElement;
use LaminasFormElementSelect;
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);
}
}
- Create a factory for such class
namespace MyModuleFormElement;
use LaminasServiceManagerFactoryFactoryInterface;
use InteropContainerContainerInterface;
use MyModuleDbRepository;
class BrandSelectFactory implements FactoryInterface {
public function __invoke(ContainerInterface $container, $requestedName, $options = null): BrandSelect {
$repository = $container->get(Repository::class);
return new BrandSelect($repository);
}
}
- Add this custom element in your module configuration (
module.config.php
)
namespace MyModule;
return [
// ..
// Other configs
// ..
'form_elements' => [
'factories' => [
FormElementBrandSelect::class => FormElementBrandSelectFactory::class
]
]
];
- Use this class as
type
for your form elements.
It is really important to add all elements in the init()
method, otherwise it will not work. I also added the InputFilterProviderInterface
.
In this case, form doens't require any other element its constructor. If needed, you must create a factory for the form and pass all params you need. The form factory must be added in module.config.php
configuration, always under the form_elements
key (as did for the BrandSelect
):
namespace MyModuleForm;
use LaminasFormForm;
use LaminasInputFilterInputFilterProviderInterface;
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' => ElementBrandSelect::class,
'options' => [
'label' => 'Brands',
]
]);
}
public function getInputFilterSpecification() {
$inputFilter[] = [
'name' => 'brand_id',
'required' => true,
'filters' => [
['name' => 'Int']
]
];
return $inputFilter;
}
}
- Retrieve the form through the form manager
Form must be retrieved using correct manager, which isn't the service manager
, but the FormElementManager
.
For example, if you need the form inside BrandController
:
<?php
namespace MyModuleController;
use LaminasFormFormElementManager;
use LaminasMvcControllerAbstractActionController;
use LaminasViewModelViewModel;
class BrandController extends AbstractActionController {
private $formManager;
public function __construct(FormElementManager $formManager) {
$this->formManager = $formManager;
}
public function addBrandAction() {
$form = $this->formManager->get(MyModuleFormBrandForm::class);
// Do stuff
return new ViewModel([
'form' => $form
]);
}
}
- Finally, you'll have to adapt the controller's factory:
namespace MyModuleController;
use LaminasServiceManagerFactoryFactoryInterface;
use InteropContainerContainerInterface;
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' => [
ControllerBrandController::class => ControllerBrandControllerFactory::class
],
],
'form_elements' => [
'factories' => [
FormElementBrandSelect::class => FormElementBrandSelectFactory::class
]
]
];
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…