Zend FrameWork 2 Get ServiceLocator In Form and populate a drop down list

余生颓废 提交于 2019-12-02 21:58:17

The other various answers here generally correct, for ZF < 2.1.

Once 2.1 is out, the framework has a pretty nice solution. This more or less formalizes DrBeza's solution, ie: using an initializer, and then moving any form-bootstrapping into an init() method that is called after all dependencies have been initialized.

I've been playing with the development branch, it it works quite well.

This is the method I used to get around that issue.

firstly, you want to make your form implement ServiceLocatorInterface as you have done.

You will then still need to manually inject the service locator, and as the whole form is generated inside the contrstuctor you will need to inject via the contructor too (no ideal to build it all in the constructor though)

Module.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;
            },
        ),
    );
}

Now inside your controller you get your form like this:

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

Now you will have access to the full service locator inside the form, to get hold of any other services etc such as:

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

In module.php I create two services. See how I feed the adapter to the form.

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

        ),
    );
}

In the form code I use that feed to whatever:

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

    }
}

We handle this in the model, by adding a method that accepts a form

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

As the form is passed by reference, we can do something like this in the controller where the form is built:

    $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',
        ),
    ));

Note: The example assumes the base form is build via annotations, but it doesn't matter how you create the initial form.

An alternative method to the other answers would be to create a ServiceManager Initializer.

An example of an existing Initializer is how the ServiceManager is injected if your instance implements ServiceLocatorAwareInterface.

The idea would be to create an interface that you check for in your Initialiser, this interface may look like:

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

An example of what your Initializer may look like:

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

        $instance->setServiceManager($serviceLocator);
        $instance->init();
    }
}

Anything that happens in init() would have access to the ServiceManager. Of course you would need to add your initializer to your SM configuration.

It is not perfect but it works fine for my needs and can also be applied to any Fieldsets pulled from the ServiceManager.

This is the way I used get around that issue.

firstly, In Module.php, create the service (just as you have done):

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

Then in the controller, I got a reference to the 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);

And viola, that work.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!