【问题标题】:Zend FrameWork 2 Get ServiceLocator In Form and populate a drop down listZend FrameWork 2 Get ServiceLocator In Form 并填充下拉列表
【发布时间】:2012-09-17 12:29:17
【问题描述】:

我需要从表单中获取适配器,但仍然无法。

在我的控制器中,我可以使用以下方法恢复适配器:

// module/Users/src/Users/Controller/UsersController.php
public function getUsersTable ()
{
    if (! $this->usersTable) {
        $sm = $this->getServiceLocator();
        $this->usersTable = $sm->get('Users\Model\UsersTable');
    }
    return $this->usersTable;
}

在我的模块中我这样做了:

// module/Users/Module.php  
public function getServiceConfig()
{
    return array(
            'factories' => array(
                    'Users\Model\UsersTable' =>  function($sm) {
                        $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                        $uTable     = new UsersTable($dbAdapter);
                        return $uTable;
                    },
                    //I need to get this to the list of groups
                    'Users\Model\GroupsTable' =>  function($sm) {
                        $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                        $gTable     = new GroupsTable($dbAdapter);
                        return $gTable;
                    },
            ),
    );
}

谁能给我一个例子,如何将适配器从组表单中获取到表格?

我已将这个示例应用于我的表单用户: http://framework.zend.com/manual/2.0/en/modules/zend.form.collections.html

从这里编辑...

也许我提出这个问题时表达了自己的错误。

我真正需要做的是用我的表组中的信息填充一个选择(下拉)。

所以我需要通过 ServiceLocatorAwareInterface (see this link) 实现我的 userForm 类中的服务,因为默认情况下,Zend Framework MVC 注册了一个初始化器,它将注入到 ServiceManager 实例中 ServiceLocatorAwareInterface 实现任何类。

从表组中检索值并填充选择后。

问题是在我尝试过的所有方法中,getServiceLocator() 返回:

Call to a member function get() on a non-object in
D:\WEBSERVER\htdocs\Zend2Control\module\Users\src\Users\Form\UsersForm.php
on line 46

我只是想在我的用户窗体中执行此操作...

namespace Users\Form;

use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Form\Element;
use Zend\Form\Form;

class UsersForm extends Form implements ServiceLocatorAwareInterface
{

    protected $serviceLocator;

    public function getServiceLocator ()
    {
        return $this->serviceLocator;
    }

    public function setServiceLocator (ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
    }

    public function __construct ($name = null)
    {
        parent::__construct('users');

        $this->setAttribute('method', 'post');        

        $sm = $this->getServiceLocator();

        $groups = $sm->get('Users\Model\GroupsTable')->fetchAll(); // line 46       

        $select = new Element\Select('groups');

        $options = array();

        foreach ($groups as $group) {

            $options[$group->id] = $group->name;
        }

        $select->setValueOptions($options);

        $this->add($select);

        // and more elements here...

【问题讨论】:

  • 嗨,您找到解决方案了吗?

标签: zend-framework2


【解决方案1】:

这里的其他各种答案通常是正确的,对于 ZF

一旦 2.1 发布,框架就有一个漂亮的nice solution。这或多或少形式化了 DrBeza 的解决方案,即:使用初始化程序,然后将任何表单引导移动到 init() 方法中,该方法在所有依赖项都已初始化后调用。

我一直在玩开发分支,它工作得很好。

【讨论】:

    【解决方案2】:

    这是我用来解决这个问题的方法。

    首先,你想让你的表单实现 ServiceLocatorInterface 。

    然后您仍然需要手动注入服务定位器,并且由于整个表单是在构造函数中生成的,因此您也需要通过构造函数进行注入(尽管在构造函数中构建它并不理想)

    模块.php

    /**
     * Get the service Config
     * 
     * @return array 
     */
    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                /**
                 * Inject ServiceLocator into our Form
                 */
                'MyModule\Form\MyForm' =>  function($sm) {
                    $form = new \MyModule\Form\MyFormForm('formname', $sm);
                    //$form->setServiceLocator($sm);
    
                    // Alternativly you can inject the adapter/gateway directly
                    // just add a setter on your form object...
                    //$form->setAdapter($sm->get('Users\Model\GroupsTable')); 
    
                    return $form;
                },
            ),
        );
    }
    

    现在在您的控制器中,您的表单如下所示:

    // Service locator now injected
    $form = $this->getServiceLocator()->get('MyModule\Form\MyForm');
    

    现在您将可以访问表单内的完整服务定位器,以获取任何其他服务等,例如:

    $groups = $this->getServiceLocator()->get('Users\Model\GroupsTable')->fetchAll();
    

    【讨论】:

    • 我最喜欢这个答案,但我发现将服务定位器保存在表单中真的很费内存,所以我宁愿将它保存在构造函数中,而不是将其保存在表单中,从配置中使用我需要的任何东西,而不是保存它。
    • 我在你身边,真的很烦人……很高兴看到 Zend 把它修好了。
    • 在对象中仅包含一个引用并不是“大量内存”。
    • 在构造函数中传递它没有什么不同,它只是对您正在添加的对象的引用,而不是副本。
    • 不错的解决方案,但是在表单中注入服务定位器真的是一个很好的解决方案吗?
    【解决方案3】:

    在 module.php 中,我创建了两个服务。看看我如何将适配器提供给表单。

    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'db_adapter' =>  function($sm) {
                    $config = $sm->get('Configuration');
                    $dbAdapter = new \Zend\Db\Adapter\Adapter($config['db']);
                    return $dbAdapter;
                },
    
                'my_amazing_form' => function ($sm) {
                    return new \dir\Form\SomeForm($sm->get('db_adapter'));
                },
    
            ),
        );
    }
    

    在表单代码中,我将该提要用于任何内容:

    namespace ....\Form;
    
    use Zend\Form\Factory as FormFactory;
    use Zend\Form\Form;
    
    class SomeForm extends Form
    {
    
        public function __construct($adapter, $name = null)
        {
            parent::__construct($name);
            $factory = new FormFactory();
    
            if (null === $name) {
                $this->setName('whatever');
            }
    
        }
    }
    

    【讨论】:

    • 我编辑了我的问题。相信现在理解的更清楚了。感谢您的回复。
    • 要填充选择选项,只需将模型(或任何其他类/适配器/其他)传递给我的回答中提到的表单。然后你就可以和它互动了。
    【解决方案4】:

    我们在模型中处理这个问题,通过添加一个接受表单的方法

    public function buildFormSelectOptions($form, $context = null)
    {
        /** 
         * Do this this for each form element that needs options added
         */
        $model = $this->getServiceManager()->get('modelProject');
    
        if (empty($context)){
            $optionRecords = $model->findAll();
        } else {
            /**
             * other logic for $optionRecords
             */
        }
    
        $options = array('value'=>'', 'label'=>'Choose a Project');
        foreach ($optionRecords as $option) {
            $options[] = array('value'=>$option->getId(), 'label'=>$option->getName());
        }
    
        $form->get('project')->setAttribute('options', $options);
    }
    

    由于表单是通过引用传递的,我们可以在构建表单的控制器中做这样的事情:

        $builder = new AnnotationBuilder();
        $form = $builder->createForm($myEntity);
        $myModel->buildFormSelectOptions($form, $myEntity);
    
        $form->add(array(
            'name' => 'submitbutton',
            'attributes' => array(
                'type'  => 'submit',
                'value' => 'Submit',
                'id' => 'submitbutton',
            ),
        ));
    
        $form->add(array(
            'name' => 'cancel',
            'attributes' => array(
                'type'  => 'submit',
                'value' => 'Cancel',
                'id' => 'cancel',
            ),
        ));
    

    注意:该示例假定基本表单是通过注释构建的,但您如何创建初始表单并不重要。

    【讨论】:

      【解决方案5】:

      其他答案的另一种方法是创建一个 ServiceManager Initializer。

      现有 Initializer 的一个示例是如果您的实例实现 ServiceLocatorAwareInterface 时如何注入 ServiceManager。

      我们的想法是创建一个您在 Initialiser 中检查的接口,该接口可能如下所示:

      interface FormServiceAwareInterface
      {
          public function init();
          public function setServiceManager(ServiceManager $serviceManager);
      }
      

      您的初始化程序可能看起来的示例:

      class FormInitializer implements InitializerInterface
      {
          public function initialize($instance, ServiceLocatorInterface $serviceLocator)
          {
              if (!$instance instanceof FormServiceAwareInterface)
              {
                  return;
              }
      
              $instance->setServiceManager($serviceLocator);
              $instance->init();
          }
      }
      

      init() 中发生的任何事情都可以访问ServiceManager。当然,您需要将初始化程序添加到您的 SM 配置中。

      它并不完美,但它可以很好地满足我的需求,也可以应用于从 ServiceManager 中提取的任何字段集。

      【讨论】:

        【解决方案6】:

        这是我用来解决这个问题的方法。

        首先,在 Module.php 中,创建服务(就像您所做的那样):

        // module/Users/Module.php  
        public function getServiceConfig()
        {
            return array(
                    'factories' => array(
                            'Users\Model\UsersTable' =>  function($sm) {
                                $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                                $uTable     = new UsersTable($dbAdapter);
                                return $uTable;
                            },
                            //I need to get this to the list of groups
                            'Users\Model\GroupsTable' =>  function($sm) {
                                $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                                $gTable     = new GroupsTable($dbAdapter);
                                return $gTable;
                            },
                    ),
            );
        }
        

        然后在控制器中,我得到了对 Service 的引用:

        $users = $this->getServiceLocator()->get('Test\Model\TestGroupTable')->fetchAll();
                $options = array();
                foreach ($users as $user)
                   $options[$user->id] = $user->name;
                //get the form element
                $form->get('user_id')->setValueOptions($options);
        

        还有中提琴,很管用。

        【讨论】:

          猜你喜欢
          • 2011-04-22
          • 2021-08-23
          • 1970-01-01
          • 2012-09-26
          • 2012-12-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多