1

我知道这个话题是在 2 年前讨论过的。但我坚持我想解决的困难。

我想创建一个包含两个以上选择元素的 zf3 表单。

我想用来自不同存储库的数据填充它们(每个 Select 项目的选项值来自不同的存储库)。

首先,我尝试在表单的构造函数中传递服务管理器(我可以从那里访问我的存储库),但我听说这个解决方案根本不合适。

那么如何在我的表单中包含多个存储库来填充我的选择元素?

4

1 回答 1

2

简短的回答:

  1. 创建一个扩展类Select
  2. 为此类创建工厂
  3. 在您的模块配置中添加此自定义元素 ( module.config.php)
  4. 使用此类作为type您的表单元素
  5. 通过表单管理器检索表单
  6. 例如,对于控制器,调整控制器的工厂

详细解答:

  1. 创建一个扩展 的类Select,例如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);
    }

}
  1. 为此类创建工厂
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);
    }

}
  1. 在您的模块配置中添加此自定义元素 ( module.config.php)
namespace MyModule;

return [
    // ..
    // Other configs
    // ..
    'form_elements' => [
        'factories' => [
            Form\Element\BrandSelect::class => Form\Element\BrandSelectFactory::class
        ]
    ]
];
  1. 将此类type用于您的表单元素。
    init()方法中添加所有元素非常重要,否则将无法正常工作。我还添加了InputFilterProviderInterface.
    在这种情况下,表单不需要任何其他元素它的构造函数。如果需要,您必须为表单创建一个工厂并传递您需要的所有参数。必须在module.config.php配置中添加表单工厂,始终在form_elements键下(就像 对 一样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;
    }

}
  1. 通过表单管理器检索
    表单必须使用正确的管理器检索表单,该管理器不是. service manager,而是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
        ]);
    }

}
  1. 最后,您必须调整控制器的工厂:
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);
    }

}

必须在controllerskey 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
        ]
    ]
];
于 2021-01-27T13:00:56.410 回答