Tuesday, 5 November 2013

A solution to dependency injection into multiple nested ZF2 fieldset classes

After a couple of days spent trying to get the ZF2 Element Manager to let me inject services into my nested fieldsets, I found a solution which seems to work with minimal changes to the Element Manager example or fieldset classes.

Note: My project was slightly different, but, I'll describe my solution in the context of ZF2's own Form Collections documentation. I have also posted this solution in the comments of the ZF website.

In the Element Manager factory
  • As I was using factories for the injection which was providing the fieldsets for use, I didn't use the invokables array at all.
  • I changed this:
    $fieldset = new AlbumFieldset($albumTable);
    to this:
    $fieldset = new AlbumFieldset();
    $fieldset->albumTable = $albumTable;
  • Make sure all additional fieldsets are setup as factories in the same way (with appropriate class name changes).

In all fieldsets classes that were being injected

  • I changed the __constructor() method to init().
  • I added a public variable of:
    public $albumTable;
  • To show population of the service in the example, change the categories text element to a select element and populate its options. (fetchPairs is an additional method inside the albumTable class that returns a key/value pairs array):
    'name' => 'name',
    'type' => 'Select',
    'options' => array(
    'label' => 'Name of the category',
    'empty_option' => 'Select category…',
    'value_options' => $this->albumTable->fetchPairs(),

Though this solution isn't perhaps the best (it can be changed to a publicly set service method with type hinting), it does inject rather than pull which I believe is better for decoupling etc plus also requires less code.

Note to ZF2 devs
While learning ZF2, I've become quite accustom to the way in which the Service Manager works but the Element Manager seems to differ somewhat in its own approach which caused confusion.

A couple of these differences:
  1. Having to use the init method to sidestep the problem of object construction setup and subsequent further injection.
  2. Having to pull the starting form instance from the Element Manager when there is no reference for it. This seems at odds with the way the Service Manager works.
In addition to those, the approach in the Element Manager example for injection does not work with the existing ZF2 documentation for form collections. You can't use the constructor to inject the service in all fieldsets, and trying to use the init() method in the same way results in an incompatible declaration error.

No comments:

Post a Comment