ZF2: Equivalent of getServiceLocator in Zend Form

2019-04-14 16:20发布

问题:

assumption: Event\Service\EventService is my personal object that works with Event\Entity\Event entities

This code works in an ActionController:

$eventService = $this->getServiceLocator()->get('Event\Service\EventService');

How can I get $eventService in a Zend\Form\Form in the same way?

回答1:

You have two options if you have a dependency like this. In your case, a Form depends on a Service. The first option is to inject dependencies:

class Form
{
  protected $service;
  public function setService(Service $service)
  {
    $this->service = $service;
  }
}

$form = new Form;
$form->setService($service);

In this case, the $form is unaware of the location of $service and generally accepted as a good idea. To make sure you don't need to set up all the dependencies yourself each time you need a Form, you can use the service manager to create a factory.

One way (there are more) to create a factory is to add a getServiceConfiguration() method to your module class and use a closure to instantiate a Form object. This is an example to inject a Service into a Form:

public function getServiceConfiguration()
{
    return array(
        'factories' => array(
            'Event\Form\Event' => function ($sm) {
                $service = $sm->get('Event\Service\EventService');
                $form    = new Form;
                $form->setService($service);

                return $form;
            }
        )
    );
}

Then you simply get the Form from your service manager. For example, in your controller:

$form = $this->getServiceLocator()->get('Event\Form\Event');

A second option is to pull dependencies. Though it is not recommended for classes like forms, you can inject a service manager so the form can pull dependencies itself:

class Form
{
    protected $sm;

    public function setServiceManager(ServiceManager $sm)
    {
        $this->sm = $sm;
    }

    /**
     * This returns the Service you depend on
     *
     * @return Service
     */
    public function getService ()
    {
        return $this->sm->get('Event\Service\EventService');
    }
}

However, this second option couples your code with unnecessary couplings and it makes it very hard to test your code. So please use dependency injection instead of pulling dependencies yourself. There are only a handful of cases where you might want to pull dependencies yourself :)



回答2:

You can just configure the form with all the options in the module.php. In the following code I:

  • Name the service as my_form
  • Associate the new object \MyModule\Form\MyForm with this service
  • Inject the service 'something1' to the _construct()
  • Inject the service 'something2' to the setSomething()

Code:

public function getServiceConfiguration()
{
    return array(
        'factories' => array(
            'my_form' => function ($sm) {
                $model = new \MyModule\Form\MyForm($sm->get('something1'));
                $obj = $sm->get('something2');
                $model->setSomething($obj);
                return $model;
            },
         ),
    );
}

And then in the controller the following line will populate your object with all needed dependencies

$form = $this->getServiceLocator()->get('my_form');



回答3:

Use the form element manager to get the form in your controller:

  $form = $this->getServiceLocator()->get('FormElementManager')->get('Path\To\Your\Form', $args);

Then in your form will become this

<?php
    namespace Your\Namespace;
    use Zend\Form\Form;
    use Zend\ServiceManager\ServiceLocatorAwareInterface;
    use Zend\ServiceManager\ ServiceLocatorAwareTrait;

    class MyForm extends Form implements ServiceLocatorAwareInterface {
    use ServiceLocatorAwareTrait;

    public function __construct($class_name, $args)
    {
         /// you cannot get the service locator in construct.
    }
    public function init()
    {
        $this->getServiceLocator()->get('Path\To\Your\Service');
    }
}