Zf3 用数据库中的数据填充选择元素

时间:2021-01-26 19:22:18

标签: zend-framework3 laminas

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

我想创建一个 zf3 表单,其中包含两个以上的 Select 元素。

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

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

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

1 个答案:

答案 0 :(得分:1)

简答:

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

}

必须在 controllers 中的 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
        ]
    ]
];
相关问题