使用工厂形成自定义元素
Form custom elements with factories
我们习惯于使用 ZF2,但对于我们的上一个项目,我们决定从 ZF3 开始。
现在我在创建表单时遇到了问题。
我想要做的是创建一个自定义 select 填充从数据库中检索的值。
我在 ZF2 中所做的是创建一个 class 扩展 select,使用 ServiceLocatorAwareInterface
,例如:
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;
}
}
然后,在表格中使用它,给出全名就足够了
$this->add(
array(
'name' => 'manufacturer_id',
'type' => 'Car\Form\Element\ManufacturerSelect'
)
);
现在这不再可能了,因为服务定位器已被删除并且必须使用工厂,但我正在努力寻找如何做同样的事情。
牢记使用工厂,我在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');
}
]
]
结果:CarForm 的工厂总是被调用,但 ManufacturerSelect 的工厂不被调用。
一个简单的解决方案是直接以 class 的形式填充 select,但我更愿意为元素使用工厂并在我想要的任何地方重用它,就像我做的那样在 ZF2.
是否有人遇到过这个问题并找到了解决方案?
您是否在“__construct”函数中添加了该元素?如果是这样,请尝试 "init"
编辑:
首先,您无需创建自定义 select 即可通过数据库进行填写。只需使用工厂创建一个表单,从工厂中的数据库中获取数据并传递给表单。并使用表格 class 中的数据作为 select 的值选项。
$this-add([
'type' => Element\Select:.class,
'name' => 'select-element'
'options' => [
'label' => 'The Select',
'empty_option' => 'Please choose one',
'value_options' => $this-dataFromDB
]
]);
如果您将表单创建为:
new MyForm();
表单元素管理器不触发自定义元素的工厂。但是;
$container->get('FormElementManager')->get(MyForm::class);
触发自定义元素的工厂。这是一个工作示例。它在 ZF3 上工作。
配置:
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'.
元素:
class CustomElement extends Text
{
}
元素工厂:
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工厂:
class MyFormFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
echo 'form factory triggered';
return new MyForm();
}
}
控制器工厂:
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);
);
}
}
我们习惯于使用 ZF2,但对于我们的上一个项目,我们决定从 ZF3 开始。
现在我在创建表单时遇到了问题。
我想要做的是创建一个自定义 select 填充从数据库中检索的值。
我在 ZF2 中所做的是创建一个 class 扩展 select,使用 ServiceLocatorAwareInterface
,例如:
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;
}
}
然后,在表格中使用它,给出全名就足够了
$this->add(
array(
'name' => 'manufacturer_id',
'type' => 'Car\Form\Element\ManufacturerSelect'
)
);
现在这不再可能了,因为服务定位器已被删除并且必须使用工厂,但我正在努力寻找如何做同样的事情。
牢记使用工厂,我在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');
}
]
]
结果:CarForm 的工厂总是被调用,但 ManufacturerSelect 的工厂不被调用。
一个简单的解决方案是直接以 class 的形式填充 select,但我更愿意为元素使用工厂并在我想要的任何地方重用它,就像我做的那样在 ZF2.
是否有人遇到过这个问题并找到了解决方案?
您是否在“__construct”函数中添加了该元素?如果是这样,请尝试 "init"
编辑:
首先,您无需创建自定义 select 即可通过数据库进行填写。只需使用工厂创建一个表单,从工厂中的数据库中获取数据并传递给表单。并使用表格 class 中的数据作为 select 的值选项。
$this-add([
'type' => Element\Select:.class,
'name' => 'select-element'
'options' => [
'label' => 'The Select',
'empty_option' => 'Please choose one',
'value_options' => $this-dataFromDB
]
]);
如果您将表单创建为:
new MyForm();
表单元素管理器不触发自定义元素的工厂。但是;
$container->get('FormElementManager')->get(MyForm::class);
触发自定义元素的工厂。这是一个工作示例。它在 ZF3 上工作。
配置:
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'.
元素:
class CustomElement extends Text
{
}
元素工厂:
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工厂:
class MyFormFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
echo 'form factory triggered';
return new MyForm();
}
}
控制器工厂:
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);
);
}
}