【问题标题】:Zf3 populate select Element with data from DatabaseZf3 使用数据库中的数据填充选择元素
【发布时间】:2021-01-26 19:22:18
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: zend-framework3 laminas


    【解决方案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
            ]
        ]
    ];
    

    【讨论】:

    • 谢谢@Ermenegildo。我会试试看,很快就会通知你。
    猜你喜欢
    • 2018-09-11
    • 1970-01-01
    • 2015-10-28
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-07
    相关资源
    最近更新 更多