【问题标题】:Form custom elements with factories用工厂形成自定义元素
【发布时间】:2017-11-03 15:20:18
【问题描述】:

我们习惯于使用 ZF2,但对于我们的上一个项目,我们决定从 ZF3 开始。
现在我在创建表单时遇到了问题。

我想做的是创建一个自定义选择,其中填充了从数据库中检索到的值。

我在 ZF2 中所做的是创建一个扩展选择的类,使用 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 的工厂不是。

一个简单的解决方案是直接在表单类中填充选择,但我更愿意为元素使用工厂并在任何我想要的地方重用它,就像我在 ZF2 中所做的那样。

是否有人已经遇到过这个问题并找到了解决方案?

【问题讨论】:

  • 您遇到什么错误?请不要使用闭包,因为工厂使用 zendframework.github.io/zend-servicemanager/migration/… -> 闭包不可缓存,也不像工厂类那样可重用
  • 实际上,我没有收到错误,工厂根本没有被调用。我 100% 确定这一点,因为我什至在里面放了一个骰子,但没有成功。关于闭包,我在这里只使用它们来表示,通常我使用类。
  • 如何将Car\Form\Element\ManufacturerSelect 添加到表单中?还在使用$this->add(['type' => class])
  • 是的,完全一样
  • 你能确认$this->add被调用了吗

标签: php zend-framework3


【解决方案1】:

您是否在“__construct”函数中添加该元素?如果是这样,请尝试“init”

编辑:

首先,您不需要创建自定义选择来通过数据库填充它。只需使用工厂创建一个表单,从工厂的数据库中获取数据并传递给表单。并将表单类中的数据作为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();

Form Element Manager 不会触发自定义元素的工厂。但是;

$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,
        ]
    ]
];

不要忘记将“Zend\Form”添加到应用程序配置的“模块”中。

元素:

class CustomElement extends Text
{
}

元素工厂:

class CustomElementFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        echo 'element factory triggered';
        return new CustomElement();
    }
}

字段集/表单:

class MyForm extends Form
{
    public function init()
    {
        $this
            ->add([
                'type'    => CustomElement::class,
                'name'    => 'name',
                'options' => [
                    'label' => 'label',
                ],
            ])
        ;
    }
}

字段集/表单工厂:

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);
            );
        }
}

【讨论】:

  • 等等你怎么叫表格?您必须通过 FormElementManager 调用表单才能使工厂正常工作。 new MyForm() 在那里不起作用。
  • 因为ZF2是强制使用的,所以我也在ZF3中使用。但是,仍然没有调用元素工厂(但表单工厂是)
  • 好吧.. 代码块在 cmets 中不起作用,所以我编辑了答案。
  • 忘记发布答案了。顺便说一句,我只是忘了把东西放在 init 部分......
猜你喜欢
  • 1970-01-01
  • 2016-04-22
  • 2014-07-23
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多