Zend ServiceManager using setter injection












0















in symfony i can use the setter injection for services via call option (https://symfony.com/doc/current/service_container/calls.html)



The example from the symfony documentation:



class MessageGenerator
{
private $logger;

public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}

// ...
}


service.yml



services:
AppServiceMessageGenerator:
# ...
calls:
- method: setLogger
arguments:
- '@logger'


I need this behaviour for my zend project. i want to inject a InputFilter into my FormFieldSet.



I didn't find anything about this in the zend documentation. Can i use something like this or exist a better solution for my problem in zend?










share|improve this question



























    0















    in symfony i can use the setter injection for services via call option (https://symfony.com/doc/current/service_container/calls.html)



    The example from the symfony documentation:



    class MessageGenerator
    {
    private $logger;

    public function setLogger(LoggerInterface $logger)
    {
    $this->logger = $logger;
    }

    // ...
    }


    service.yml



    services:
    AppServiceMessageGenerator:
    # ...
    calls:
    - method: setLogger
    arguments:
    - '@logger'


    I need this behaviour for my zend project. i want to inject a InputFilter into my FormFieldSet.



    I didn't find anything about this in the zend documentation. Can i use something like this or exist a better solution for my problem in zend?










    share|improve this question

























      0












      0








      0








      in symfony i can use the setter injection for services via call option (https://symfony.com/doc/current/service_container/calls.html)



      The example from the symfony documentation:



      class MessageGenerator
      {
      private $logger;

      public function setLogger(LoggerInterface $logger)
      {
      $this->logger = $logger;
      }

      // ...
      }


      service.yml



      services:
      AppServiceMessageGenerator:
      # ...
      calls:
      - method: setLogger
      arguments:
      - '@logger'


      I need this behaviour for my zend project. i want to inject a InputFilter into my FormFieldSet.



      I didn't find anything about this in the zend documentation. Can i use something like this or exist a better solution for my problem in zend?










      share|improve this question














      in symfony i can use the setter injection for services via call option (https://symfony.com/doc/current/service_container/calls.html)



      The example from the symfony documentation:



      class MessageGenerator
      {
      private $logger;

      public function setLogger(LoggerInterface $logger)
      {
      $this->logger = $logger;
      }

      // ...
      }


      service.yml



      services:
      AppServiceMessageGenerator:
      # ...
      calls:
      - method: setLogger
      arguments:
      - '@logger'


      I need this behaviour for my zend project. i want to inject a InputFilter into my FormFieldSet.



      I didn't find anything about this in the zend documentation. Can i use something like this or exist a better solution for my problem in zend?







      zend-framework zend-framework3






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 14 '18 at 11:20









      robrob

      1,31851526




      1,31851526
























          2 Answers
          2






          active

          oldest

          votes


















          2














          Based on this question and your previous question about Forms, Fieldsets and InputFilters, I'm thinking you want to achieve something similar to the following use case.



          Use case



          You have a




          • Location Entity

          • Address Entity

          • Location has a OneToOne to an Address (required, uni-directional)


          Requirements



          To manage the Location, you'll need:




          • LocationForm (-Factory)

          • LocationFormInputFilter (-Factory)

          • LocationFieldset (-Factory)

          • LocationFieldsetInputFilter (-Factory)

          • AddressFieldset (-Factory)

          • AddressFieldsetInputFilter (-Factory)


          Configuration



          To configure this in ZF3, you'll have to do add the following



          'form_elements' => [
          'factories' => [
          AddressFieldset::class => AddressFieldsetFactory::class,
          LocationForm::class => LocationFormFactory::class,
          LocationFieldset::class => LocationFieldsetFactory::class,
          ],
          ],
          'input_filters' => [
          'factories' => [
          AddressFieldsetInputFilter::class => AddressFieldsetInputFilterFactory::class,
          LocationFormInputFilter::class => LocationFormInputFilterFactory::class,
          LocationFieldsetInputFilter::class => LocationFieldsetInputFilterFactory::class,
          ],
          ],


          Forms & Fieldsets



          In the LocationForm, add your LocationFieldset and what else your Form needs, such as CSRF and submit button.



          class LocationForm extends AbstractForm
          {
          public function init()
          {
          $this->add([
          'name' => 'location',
          'type' => LocationFieldset::class,
          'options' => [
          'use_as_base_fieldset' => true,
          ],
          ]);

          //Call parent initializer. Adds CSRF & submit button
          parent::init();
          }
          }


          (Note: my AbstractForm does a bit more, I would suggest you have a look here, such as remove empty (child fieldsets/collections) Inputs so data is not attempted to be created in the DB)



          In the LocationFieldset, give add Inputs for the Location, such as a name, and the AddressFieldset:



          class LocationFieldset extends AbstractFieldset
          {
          public function init()
          {
          parent::init();

          $this->add([
          'name' => 'name',
          'required' => true,
          'type' => Text::class,
          'options' => [
          'label' => _('Name'),
          ],
          ]);

          $this->add([
          'type' => AddressFieldset::class,
          'name' => 'address',
          'required' => true,
          'options' => [
          'use_as_base_fieldset' => false,
          'label' => _('Address'),
          ],
          ]);
          }
          }


          In the AddressFieldset just add Inputs for the Address Entity. (Same as above, without the Fieldset type Input)



          InputFilters



          To validate the Form, you can keep it very simple:



          class LocationFormInputFilter extends AbstractFormInputFilter
          {
          /** @var LocationFieldsetInputFilter */
          protected $locationFieldsetInputFilter;

          public function __construct(LocationFieldsetInputFilter $filter)
          {
          $this->locationFieldsetInputFilter = $filter;

          parent::__construct();
          }

          public function init()
          {
          $this->add($this->locationFieldsetInputFilter, 'location');

          parent::init();
          }
          }


          (The AbstractFormInputFilter adds CSRF validator)



          Notice that we simply ->add() the LocationFieldsetInputFilter, but we give it a name (2nd parameter). This name is used later in the complete structure, so it's important to both keep it simple and keep it correct. Simplest is to give it a name that one on one matches the object of the Fieldset it's supposed to validate.



          Next, the LocationFieldsetInputFilter:



          class LocationFieldsetInputFilter extends AbstractFieldsetInputFilter
          {
          /**
          * @var AddressFieldsetInputFilter
          */
          protected $addressFieldsetInputFilter;

          public function __construct(AddressFieldsetInputFilter $addressFieldsetInputFilter)
          {
          $this->addressFieldsetInputFilter = $addressFieldsetInputFilter;

          parent::__construct();
          }

          public function init()
          {
          parent::init();

          $this->add($this->addressFieldsetInputFilter, 'address'); // Again, name is important

          $this->add(
          [
          'name' => 'name',
          'required' => true,
          'filters' => [
          ['name' => StringTrim::class],
          ['name' => StripTags::class],
          [
          'name' => ToNull::class,
          'options' => [
          'type' => ToNull::TYPE_STRING,
          ],
          ],
          ],
          'validators' => [
          [
          'name' => StringLength::class,
          'options' => [
          'min' => 3,
          'max' => 255,
          ],
          ],
          ],
          ]
          );
          }
          }


          Factories



          Now, you must bind them together, which is where your question about Setter injection comes from I think. This happens in the Factory.



          A *FormFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          $inputFilterPluginManager = $container->get('InputFilterManager');
          $inputFilter = $inputFilterPluginManager->get(LocationFormInputFilter::class);

          /** @var LocationForm $form */
          $form = new LocationForm();
          $form->setInputFilter($inputFilter); // The setter injection you're after

          return $form;
          }


          A *FieldsetFactory would do the following (do the same for Location- and AddressFieldsets):



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          /** @var LocationFieldset $fieldset */
          // name matters! Match the object to keep it simple. Name is used from Form to match the InputFilter (with same name!)
          $fieldset = new LocationFieldset('location');
          // Zend Reflection Hydrator, could easily be something else, such as DoctrineObject hydrator.
          $fieldset->setHydrator(new Reflection());
          $fieldset->setObject(new Location());

          return $fieldset;
          }


          A *FormInputFilterFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          $inputFilterPluginManager = $container->get('InputFilterManager');

          /** @var LocationFieldsetInputFilter $locationFieldsetInputFilter */
          $locationFieldsetInputFilter = $inputFilterPluginManager->get(LocationFieldsetInputFilter::class);

          // Create Form InputFilter
          $locationFormInputFilter = new LocationFormInputFilter(
          $locationFieldsetInputFilter
          );

          return $locationFormInputFilter;
          }


          A *FieldsetInputFilterFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          /** @var AddressFieldsetInputFilter $addressFieldsetInputFilter */
          $addressFieldsetInputFilter = $this->getInputFilterManager()->get(AddressFieldsetInputFilter::class);
          $addressFieldsetInputFilter->setRequired(true);

          return new LocationFieldsetInputFilter(
          $addressFieldsetInputFilter
          );
          }


          Note:




          • Setting an InputFilter as (not) required is something I've added here

          • If your InputFilter (such as AddressFieldsetInputFilter) does not have a child InputFilter, you can can skip getting the child and straight away return the new InputFilter.




          I think I covered it all for a complete picture. If you have any questions about this, please comment.






          share|improve this answer
























          • hm, there many unclear questions in the process to change my example. so in my case, the FieldSetFactory isn't called, and the Hydrator isn't set. i have to implement getArrayCopy(). but i want to use the ClassMethods Hydrator. but i like your way to solve it

            – rob
            Nov 15 '18 at 10:24











          • The FieldsetFactory not being called is a common cause of doing $form->setFieldset(new Fieldset()) instead of $form->setFieldset($container->get(Fieldset::class)). Using the appropriate ServiceManager causes the Fieldset to be supplied using the Factory registered in the config instead of a straight up "new class()". Make sure your config is present and make sure you're using the right ServiceManager. (For Form & Fieldsets it's $container->get(Fieldset::class), for InputFilters it's $container->get('InputFilterManager')->get(InputFilter::class).

            – rkeet
            Nov 15 '18 at 10:53











          • ok, think i have to play something more with zend. its slightly different from symfony handling. but for this special case the answer from tasmaniski will be more fit to my question

            – rob
            Nov 15 '18 at 12:49











          • While initializers (tasmaniski's answer) do what you want them, please do read the docs and note: While convenient, initializer usage is also problematic. They are provided primarily for backwards compatibility, but we highly discourage their usage. and Instead, we encourage you to inject all necessary dependencies via the constructor, using factories. If some dependencies use setter or interface injection, use delegator factories. Of course, if it's the one time, by all means. But if not, slippery slope ;) If it's a new project or one being upgraded, I would advise factories instead.

            – rkeet
            Nov 15 '18 at 15:51











          • Ok, thats a reason to step over the initializer. So in Symfony there's something easier to use DI. But i want to learn to use zend too. Big thanks for your usefull help. i marked your post as answer, cause of the hint from the docs :-)

            – rob
            Nov 15 '18 at 18:13



















          1














          What you need are Initializers from Zend Service Manager.



          The initializer can be a class that is called whenever a service has been created.
          In that class, you need to check the type of service that is created, and if it's appropriate type than inject whatever you want.



          To register one Initializer add in config under service_manager key:



          'service_manager' => [
          'initializers' => [
          MyInitializer::class
          ],
          ]


          and then just create that class



          class MyInitializer implements InitializerInterface
          {
          public function __invoke(ContainerInterface $container, $instance)
          {
          // you need to check should you inject or not
          if ($instance instanceof MessageGenerator) {
          $instance->setLogger($container->get('logger'));
          }
          }
          }


          You need to have registred MessageGenerator in zend-servicemanager also. In this way, when you try to retrive MessageGenerator from SM, after creation MyInitializer is called.






          share|improve this answer
























          • Beware: overuse of initializers may cause unnecessary overhead since every service retrieved from service locator would pass through registered initializers. While having a few application wide initializers are fine, they should be avoided as much as possible.

            – edigu
            Nov 20 '18 at 22:18











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53299020%2fzend-servicemanager-using-setter-injection%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          2 Answers
          2






          active

          oldest

          votes








          2 Answers
          2






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          2














          Based on this question and your previous question about Forms, Fieldsets and InputFilters, I'm thinking you want to achieve something similar to the following use case.



          Use case



          You have a




          • Location Entity

          • Address Entity

          • Location has a OneToOne to an Address (required, uni-directional)


          Requirements



          To manage the Location, you'll need:




          • LocationForm (-Factory)

          • LocationFormInputFilter (-Factory)

          • LocationFieldset (-Factory)

          • LocationFieldsetInputFilter (-Factory)

          • AddressFieldset (-Factory)

          • AddressFieldsetInputFilter (-Factory)


          Configuration



          To configure this in ZF3, you'll have to do add the following



          'form_elements' => [
          'factories' => [
          AddressFieldset::class => AddressFieldsetFactory::class,
          LocationForm::class => LocationFormFactory::class,
          LocationFieldset::class => LocationFieldsetFactory::class,
          ],
          ],
          'input_filters' => [
          'factories' => [
          AddressFieldsetInputFilter::class => AddressFieldsetInputFilterFactory::class,
          LocationFormInputFilter::class => LocationFormInputFilterFactory::class,
          LocationFieldsetInputFilter::class => LocationFieldsetInputFilterFactory::class,
          ],
          ],


          Forms & Fieldsets



          In the LocationForm, add your LocationFieldset and what else your Form needs, such as CSRF and submit button.



          class LocationForm extends AbstractForm
          {
          public function init()
          {
          $this->add([
          'name' => 'location',
          'type' => LocationFieldset::class,
          'options' => [
          'use_as_base_fieldset' => true,
          ],
          ]);

          //Call parent initializer. Adds CSRF & submit button
          parent::init();
          }
          }


          (Note: my AbstractForm does a bit more, I would suggest you have a look here, such as remove empty (child fieldsets/collections) Inputs so data is not attempted to be created in the DB)



          In the LocationFieldset, give add Inputs for the Location, such as a name, and the AddressFieldset:



          class LocationFieldset extends AbstractFieldset
          {
          public function init()
          {
          parent::init();

          $this->add([
          'name' => 'name',
          'required' => true,
          'type' => Text::class,
          'options' => [
          'label' => _('Name'),
          ],
          ]);

          $this->add([
          'type' => AddressFieldset::class,
          'name' => 'address',
          'required' => true,
          'options' => [
          'use_as_base_fieldset' => false,
          'label' => _('Address'),
          ],
          ]);
          }
          }


          In the AddressFieldset just add Inputs for the Address Entity. (Same as above, without the Fieldset type Input)



          InputFilters



          To validate the Form, you can keep it very simple:



          class LocationFormInputFilter extends AbstractFormInputFilter
          {
          /** @var LocationFieldsetInputFilter */
          protected $locationFieldsetInputFilter;

          public function __construct(LocationFieldsetInputFilter $filter)
          {
          $this->locationFieldsetInputFilter = $filter;

          parent::__construct();
          }

          public function init()
          {
          $this->add($this->locationFieldsetInputFilter, 'location');

          parent::init();
          }
          }


          (The AbstractFormInputFilter adds CSRF validator)



          Notice that we simply ->add() the LocationFieldsetInputFilter, but we give it a name (2nd parameter). This name is used later in the complete structure, so it's important to both keep it simple and keep it correct. Simplest is to give it a name that one on one matches the object of the Fieldset it's supposed to validate.



          Next, the LocationFieldsetInputFilter:



          class LocationFieldsetInputFilter extends AbstractFieldsetInputFilter
          {
          /**
          * @var AddressFieldsetInputFilter
          */
          protected $addressFieldsetInputFilter;

          public function __construct(AddressFieldsetInputFilter $addressFieldsetInputFilter)
          {
          $this->addressFieldsetInputFilter = $addressFieldsetInputFilter;

          parent::__construct();
          }

          public function init()
          {
          parent::init();

          $this->add($this->addressFieldsetInputFilter, 'address'); // Again, name is important

          $this->add(
          [
          'name' => 'name',
          'required' => true,
          'filters' => [
          ['name' => StringTrim::class],
          ['name' => StripTags::class],
          [
          'name' => ToNull::class,
          'options' => [
          'type' => ToNull::TYPE_STRING,
          ],
          ],
          ],
          'validators' => [
          [
          'name' => StringLength::class,
          'options' => [
          'min' => 3,
          'max' => 255,
          ],
          ],
          ],
          ]
          );
          }
          }


          Factories



          Now, you must bind them together, which is where your question about Setter injection comes from I think. This happens in the Factory.



          A *FormFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          $inputFilterPluginManager = $container->get('InputFilterManager');
          $inputFilter = $inputFilterPluginManager->get(LocationFormInputFilter::class);

          /** @var LocationForm $form */
          $form = new LocationForm();
          $form->setInputFilter($inputFilter); // The setter injection you're after

          return $form;
          }


          A *FieldsetFactory would do the following (do the same for Location- and AddressFieldsets):



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          /** @var LocationFieldset $fieldset */
          // name matters! Match the object to keep it simple. Name is used from Form to match the InputFilter (with same name!)
          $fieldset = new LocationFieldset('location');
          // Zend Reflection Hydrator, could easily be something else, such as DoctrineObject hydrator.
          $fieldset->setHydrator(new Reflection());
          $fieldset->setObject(new Location());

          return $fieldset;
          }


          A *FormInputFilterFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          $inputFilterPluginManager = $container->get('InputFilterManager');

          /** @var LocationFieldsetInputFilter $locationFieldsetInputFilter */
          $locationFieldsetInputFilter = $inputFilterPluginManager->get(LocationFieldsetInputFilter::class);

          // Create Form InputFilter
          $locationFormInputFilter = new LocationFormInputFilter(
          $locationFieldsetInputFilter
          );

          return $locationFormInputFilter;
          }


          A *FieldsetInputFilterFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          /** @var AddressFieldsetInputFilter $addressFieldsetInputFilter */
          $addressFieldsetInputFilter = $this->getInputFilterManager()->get(AddressFieldsetInputFilter::class);
          $addressFieldsetInputFilter->setRequired(true);

          return new LocationFieldsetInputFilter(
          $addressFieldsetInputFilter
          );
          }


          Note:




          • Setting an InputFilter as (not) required is something I've added here

          • If your InputFilter (such as AddressFieldsetInputFilter) does not have a child InputFilter, you can can skip getting the child and straight away return the new InputFilter.




          I think I covered it all for a complete picture. If you have any questions about this, please comment.






          share|improve this answer
























          • hm, there many unclear questions in the process to change my example. so in my case, the FieldSetFactory isn't called, and the Hydrator isn't set. i have to implement getArrayCopy(). but i want to use the ClassMethods Hydrator. but i like your way to solve it

            – rob
            Nov 15 '18 at 10:24











          • The FieldsetFactory not being called is a common cause of doing $form->setFieldset(new Fieldset()) instead of $form->setFieldset($container->get(Fieldset::class)). Using the appropriate ServiceManager causes the Fieldset to be supplied using the Factory registered in the config instead of a straight up "new class()". Make sure your config is present and make sure you're using the right ServiceManager. (For Form & Fieldsets it's $container->get(Fieldset::class), for InputFilters it's $container->get('InputFilterManager')->get(InputFilter::class).

            – rkeet
            Nov 15 '18 at 10:53











          • ok, think i have to play something more with zend. its slightly different from symfony handling. but for this special case the answer from tasmaniski will be more fit to my question

            – rob
            Nov 15 '18 at 12:49











          • While initializers (tasmaniski's answer) do what you want them, please do read the docs and note: While convenient, initializer usage is also problematic. They are provided primarily for backwards compatibility, but we highly discourage their usage. and Instead, we encourage you to inject all necessary dependencies via the constructor, using factories. If some dependencies use setter or interface injection, use delegator factories. Of course, if it's the one time, by all means. But if not, slippery slope ;) If it's a new project or one being upgraded, I would advise factories instead.

            – rkeet
            Nov 15 '18 at 15:51











          • Ok, thats a reason to step over the initializer. So in Symfony there's something easier to use DI. But i want to learn to use zend too. Big thanks for your usefull help. i marked your post as answer, cause of the hint from the docs :-)

            – rob
            Nov 15 '18 at 18:13
















          2














          Based on this question and your previous question about Forms, Fieldsets and InputFilters, I'm thinking you want to achieve something similar to the following use case.



          Use case



          You have a




          • Location Entity

          • Address Entity

          • Location has a OneToOne to an Address (required, uni-directional)


          Requirements



          To manage the Location, you'll need:




          • LocationForm (-Factory)

          • LocationFormInputFilter (-Factory)

          • LocationFieldset (-Factory)

          • LocationFieldsetInputFilter (-Factory)

          • AddressFieldset (-Factory)

          • AddressFieldsetInputFilter (-Factory)


          Configuration



          To configure this in ZF3, you'll have to do add the following



          'form_elements' => [
          'factories' => [
          AddressFieldset::class => AddressFieldsetFactory::class,
          LocationForm::class => LocationFormFactory::class,
          LocationFieldset::class => LocationFieldsetFactory::class,
          ],
          ],
          'input_filters' => [
          'factories' => [
          AddressFieldsetInputFilter::class => AddressFieldsetInputFilterFactory::class,
          LocationFormInputFilter::class => LocationFormInputFilterFactory::class,
          LocationFieldsetInputFilter::class => LocationFieldsetInputFilterFactory::class,
          ],
          ],


          Forms & Fieldsets



          In the LocationForm, add your LocationFieldset and what else your Form needs, such as CSRF and submit button.



          class LocationForm extends AbstractForm
          {
          public function init()
          {
          $this->add([
          'name' => 'location',
          'type' => LocationFieldset::class,
          'options' => [
          'use_as_base_fieldset' => true,
          ],
          ]);

          //Call parent initializer. Adds CSRF & submit button
          parent::init();
          }
          }


          (Note: my AbstractForm does a bit more, I would suggest you have a look here, such as remove empty (child fieldsets/collections) Inputs so data is not attempted to be created in the DB)



          In the LocationFieldset, give add Inputs for the Location, such as a name, and the AddressFieldset:



          class LocationFieldset extends AbstractFieldset
          {
          public function init()
          {
          parent::init();

          $this->add([
          'name' => 'name',
          'required' => true,
          'type' => Text::class,
          'options' => [
          'label' => _('Name'),
          ],
          ]);

          $this->add([
          'type' => AddressFieldset::class,
          'name' => 'address',
          'required' => true,
          'options' => [
          'use_as_base_fieldset' => false,
          'label' => _('Address'),
          ],
          ]);
          }
          }


          In the AddressFieldset just add Inputs for the Address Entity. (Same as above, without the Fieldset type Input)



          InputFilters



          To validate the Form, you can keep it very simple:



          class LocationFormInputFilter extends AbstractFormInputFilter
          {
          /** @var LocationFieldsetInputFilter */
          protected $locationFieldsetInputFilter;

          public function __construct(LocationFieldsetInputFilter $filter)
          {
          $this->locationFieldsetInputFilter = $filter;

          parent::__construct();
          }

          public function init()
          {
          $this->add($this->locationFieldsetInputFilter, 'location');

          parent::init();
          }
          }


          (The AbstractFormInputFilter adds CSRF validator)



          Notice that we simply ->add() the LocationFieldsetInputFilter, but we give it a name (2nd parameter). This name is used later in the complete structure, so it's important to both keep it simple and keep it correct. Simplest is to give it a name that one on one matches the object of the Fieldset it's supposed to validate.



          Next, the LocationFieldsetInputFilter:



          class LocationFieldsetInputFilter extends AbstractFieldsetInputFilter
          {
          /**
          * @var AddressFieldsetInputFilter
          */
          protected $addressFieldsetInputFilter;

          public function __construct(AddressFieldsetInputFilter $addressFieldsetInputFilter)
          {
          $this->addressFieldsetInputFilter = $addressFieldsetInputFilter;

          parent::__construct();
          }

          public function init()
          {
          parent::init();

          $this->add($this->addressFieldsetInputFilter, 'address'); // Again, name is important

          $this->add(
          [
          'name' => 'name',
          'required' => true,
          'filters' => [
          ['name' => StringTrim::class],
          ['name' => StripTags::class],
          [
          'name' => ToNull::class,
          'options' => [
          'type' => ToNull::TYPE_STRING,
          ],
          ],
          ],
          'validators' => [
          [
          'name' => StringLength::class,
          'options' => [
          'min' => 3,
          'max' => 255,
          ],
          ],
          ],
          ]
          );
          }
          }


          Factories



          Now, you must bind them together, which is where your question about Setter injection comes from I think. This happens in the Factory.



          A *FormFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          $inputFilterPluginManager = $container->get('InputFilterManager');
          $inputFilter = $inputFilterPluginManager->get(LocationFormInputFilter::class);

          /** @var LocationForm $form */
          $form = new LocationForm();
          $form->setInputFilter($inputFilter); // The setter injection you're after

          return $form;
          }


          A *FieldsetFactory would do the following (do the same for Location- and AddressFieldsets):



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          /** @var LocationFieldset $fieldset */
          // name matters! Match the object to keep it simple. Name is used from Form to match the InputFilter (with same name!)
          $fieldset = new LocationFieldset('location');
          // Zend Reflection Hydrator, could easily be something else, such as DoctrineObject hydrator.
          $fieldset->setHydrator(new Reflection());
          $fieldset->setObject(new Location());

          return $fieldset;
          }


          A *FormInputFilterFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          $inputFilterPluginManager = $container->get('InputFilterManager');

          /** @var LocationFieldsetInputFilter $locationFieldsetInputFilter */
          $locationFieldsetInputFilter = $inputFilterPluginManager->get(LocationFieldsetInputFilter::class);

          // Create Form InputFilter
          $locationFormInputFilter = new LocationFormInputFilter(
          $locationFieldsetInputFilter
          );

          return $locationFormInputFilter;
          }


          A *FieldsetInputFilterFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          /** @var AddressFieldsetInputFilter $addressFieldsetInputFilter */
          $addressFieldsetInputFilter = $this->getInputFilterManager()->get(AddressFieldsetInputFilter::class);
          $addressFieldsetInputFilter->setRequired(true);

          return new LocationFieldsetInputFilter(
          $addressFieldsetInputFilter
          );
          }


          Note:




          • Setting an InputFilter as (not) required is something I've added here

          • If your InputFilter (such as AddressFieldsetInputFilter) does not have a child InputFilter, you can can skip getting the child and straight away return the new InputFilter.




          I think I covered it all for a complete picture. If you have any questions about this, please comment.






          share|improve this answer
























          • hm, there many unclear questions in the process to change my example. so in my case, the FieldSetFactory isn't called, and the Hydrator isn't set. i have to implement getArrayCopy(). but i want to use the ClassMethods Hydrator. but i like your way to solve it

            – rob
            Nov 15 '18 at 10:24











          • The FieldsetFactory not being called is a common cause of doing $form->setFieldset(new Fieldset()) instead of $form->setFieldset($container->get(Fieldset::class)). Using the appropriate ServiceManager causes the Fieldset to be supplied using the Factory registered in the config instead of a straight up "new class()". Make sure your config is present and make sure you're using the right ServiceManager. (For Form & Fieldsets it's $container->get(Fieldset::class), for InputFilters it's $container->get('InputFilterManager')->get(InputFilter::class).

            – rkeet
            Nov 15 '18 at 10:53











          • ok, think i have to play something more with zend. its slightly different from symfony handling. but for this special case the answer from tasmaniski will be more fit to my question

            – rob
            Nov 15 '18 at 12:49











          • While initializers (tasmaniski's answer) do what you want them, please do read the docs and note: While convenient, initializer usage is also problematic. They are provided primarily for backwards compatibility, but we highly discourage their usage. and Instead, we encourage you to inject all necessary dependencies via the constructor, using factories. If some dependencies use setter or interface injection, use delegator factories. Of course, if it's the one time, by all means. But if not, slippery slope ;) If it's a new project or one being upgraded, I would advise factories instead.

            – rkeet
            Nov 15 '18 at 15:51











          • Ok, thats a reason to step over the initializer. So in Symfony there's something easier to use DI. But i want to learn to use zend too. Big thanks for your usefull help. i marked your post as answer, cause of the hint from the docs :-)

            – rob
            Nov 15 '18 at 18:13














          2












          2








          2







          Based on this question and your previous question about Forms, Fieldsets and InputFilters, I'm thinking you want to achieve something similar to the following use case.



          Use case



          You have a




          • Location Entity

          • Address Entity

          • Location has a OneToOne to an Address (required, uni-directional)


          Requirements



          To manage the Location, you'll need:




          • LocationForm (-Factory)

          • LocationFormInputFilter (-Factory)

          • LocationFieldset (-Factory)

          • LocationFieldsetInputFilter (-Factory)

          • AddressFieldset (-Factory)

          • AddressFieldsetInputFilter (-Factory)


          Configuration



          To configure this in ZF3, you'll have to do add the following



          'form_elements' => [
          'factories' => [
          AddressFieldset::class => AddressFieldsetFactory::class,
          LocationForm::class => LocationFormFactory::class,
          LocationFieldset::class => LocationFieldsetFactory::class,
          ],
          ],
          'input_filters' => [
          'factories' => [
          AddressFieldsetInputFilter::class => AddressFieldsetInputFilterFactory::class,
          LocationFormInputFilter::class => LocationFormInputFilterFactory::class,
          LocationFieldsetInputFilter::class => LocationFieldsetInputFilterFactory::class,
          ],
          ],


          Forms & Fieldsets



          In the LocationForm, add your LocationFieldset and what else your Form needs, such as CSRF and submit button.



          class LocationForm extends AbstractForm
          {
          public function init()
          {
          $this->add([
          'name' => 'location',
          'type' => LocationFieldset::class,
          'options' => [
          'use_as_base_fieldset' => true,
          ],
          ]);

          //Call parent initializer. Adds CSRF & submit button
          parent::init();
          }
          }


          (Note: my AbstractForm does a bit more, I would suggest you have a look here, such as remove empty (child fieldsets/collections) Inputs so data is not attempted to be created in the DB)



          In the LocationFieldset, give add Inputs for the Location, such as a name, and the AddressFieldset:



          class LocationFieldset extends AbstractFieldset
          {
          public function init()
          {
          parent::init();

          $this->add([
          'name' => 'name',
          'required' => true,
          'type' => Text::class,
          'options' => [
          'label' => _('Name'),
          ],
          ]);

          $this->add([
          'type' => AddressFieldset::class,
          'name' => 'address',
          'required' => true,
          'options' => [
          'use_as_base_fieldset' => false,
          'label' => _('Address'),
          ],
          ]);
          }
          }


          In the AddressFieldset just add Inputs for the Address Entity. (Same as above, without the Fieldset type Input)



          InputFilters



          To validate the Form, you can keep it very simple:



          class LocationFormInputFilter extends AbstractFormInputFilter
          {
          /** @var LocationFieldsetInputFilter */
          protected $locationFieldsetInputFilter;

          public function __construct(LocationFieldsetInputFilter $filter)
          {
          $this->locationFieldsetInputFilter = $filter;

          parent::__construct();
          }

          public function init()
          {
          $this->add($this->locationFieldsetInputFilter, 'location');

          parent::init();
          }
          }


          (The AbstractFormInputFilter adds CSRF validator)



          Notice that we simply ->add() the LocationFieldsetInputFilter, but we give it a name (2nd parameter). This name is used later in the complete structure, so it's important to both keep it simple and keep it correct. Simplest is to give it a name that one on one matches the object of the Fieldset it's supposed to validate.



          Next, the LocationFieldsetInputFilter:



          class LocationFieldsetInputFilter extends AbstractFieldsetInputFilter
          {
          /**
          * @var AddressFieldsetInputFilter
          */
          protected $addressFieldsetInputFilter;

          public function __construct(AddressFieldsetInputFilter $addressFieldsetInputFilter)
          {
          $this->addressFieldsetInputFilter = $addressFieldsetInputFilter;

          parent::__construct();
          }

          public function init()
          {
          parent::init();

          $this->add($this->addressFieldsetInputFilter, 'address'); // Again, name is important

          $this->add(
          [
          'name' => 'name',
          'required' => true,
          'filters' => [
          ['name' => StringTrim::class],
          ['name' => StripTags::class],
          [
          'name' => ToNull::class,
          'options' => [
          'type' => ToNull::TYPE_STRING,
          ],
          ],
          ],
          'validators' => [
          [
          'name' => StringLength::class,
          'options' => [
          'min' => 3,
          'max' => 255,
          ],
          ],
          ],
          ]
          );
          }
          }


          Factories



          Now, you must bind them together, which is where your question about Setter injection comes from I think. This happens in the Factory.



          A *FormFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          $inputFilterPluginManager = $container->get('InputFilterManager');
          $inputFilter = $inputFilterPluginManager->get(LocationFormInputFilter::class);

          /** @var LocationForm $form */
          $form = new LocationForm();
          $form->setInputFilter($inputFilter); // The setter injection you're after

          return $form;
          }


          A *FieldsetFactory would do the following (do the same for Location- and AddressFieldsets):



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          /** @var LocationFieldset $fieldset */
          // name matters! Match the object to keep it simple. Name is used from Form to match the InputFilter (with same name!)
          $fieldset = new LocationFieldset('location');
          // Zend Reflection Hydrator, could easily be something else, such as DoctrineObject hydrator.
          $fieldset->setHydrator(new Reflection());
          $fieldset->setObject(new Location());

          return $fieldset;
          }


          A *FormInputFilterFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          $inputFilterPluginManager = $container->get('InputFilterManager');

          /** @var LocationFieldsetInputFilter $locationFieldsetInputFilter */
          $locationFieldsetInputFilter = $inputFilterPluginManager->get(LocationFieldsetInputFilter::class);

          // Create Form InputFilter
          $locationFormInputFilter = new LocationFormInputFilter(
          $locationFieldsetInputFilter
          );

          return $locationFormInputFilter;
          }


          A *FieldsetInputFilterFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          /** @var AddressFieldsetInputFilter $addressFieldsetInputFilter */
          $addressFieldsetInputFilter = $this->getInputFilterManager()->get(AddressFieldsetInputFilter::class);
          $addressFieldsetInputFilter->setRequired(true);

          return new LocationFieldsetInputFilter(
          $addressFieldsetInputFilter
          );
          }


          Note:




          • Setting an InputFilter as (not) required is something I've added here

          • If your InputFilter (such as AddressFieldsetInputFilter) does not have a child InputFilter, you can can skip getting the child and straight away return the new InputFilter.




          I think I covered it all for a complete picture. If you have any questions about this, please comment.






          share|improve this answer













          Based on this question and your previous question about Forms, Fieldsets and InputFilters, I'm thinking you want to achieve something similar to the following use case.



          Use case



          You have a




          • Location Entity

          • Address Entity

          • Location has a OneToOne to an Address (required, uni-directional)


          Requirements



          To manage the Location, you'll need:




          • LocationForm (-Factory)

          • LocationFormInputFilter (-Factory)

          • LocationFieldset (-Factory)

          • LocationFieldsetInputFilter (-Factory)

          • AddressFieldset (-Factory)

          • AddressFieldsetInputFilter (-Factory)


          Configuration



          To configure this in ZF3, you'll have to do add the following



          'form_elements' => [
          'factories' => [
          AddressFieldset::class => AddressFieldsetFactory::class,
          LocationForm::class => LocationFormFactory::class,
          LocationFieldset::class => LocationFieldsetFactory::class,
          ],
          ],
          'input_filters' => [
          'factories' => [
          AddressFieldsetInputFilter::class => AddressFieldsetInputFilterFactory::class,
          LocationFormInputFilter::class => LocationFormInputFilterFactory::class,
          LocationFieldsetInputFilter::class => LocationFieldsetInputFilterFactory::class,
          ],
          ],


          Forms & Fieldsets



          In the LocationForm, add your LocationFieldset and what else your Form needs, such as CSRF and submit button.



          class LocationForm extends AbstractForm
          {
          public function init()
          {
          $this->add([
          'name' => 'location',
          'type' => LocationFieldset::class,
          'options' => [
          'use_as_base_fieldset' => true,
          ],
          ]);

          //Call parent initializer. Adds CSRF & submit button
          parent::init();
          }
          }


          (Note: my AbstractForm does a bit more, I would suggest you have a look here, such as remove empty (child fieldsets/collections) Inputs so data is not attempted to be created in the DB)



          In the LocationFieldset, give add Inputs for the Location, such as a name, and the AddressFieldset:



          class LocationFieldset extends AbstractFieldset
          {
          public function init()
          {
          parent::init();

          $this->add([
          'name' => 'name',
          'required' => true,
          'type' => Text::class,
          'options' => [
          'label' => _('Name'),
          ],
          ]);

          $this->add([
          'type' => AddressFieldset::class,
          'name' => 'address',
          'required' => true,
          'options' => [
          'use_as_base_fieldset' => false,
          'label' => _('Address'),
          ],
          ]);
          }
          }


          In the AddressFieldset just add Inputs for the Address Entity. (Same as above, without the Fieldset type Input)



          InputFilters



          To validate the Form, you can keep it very simple:



          class LocationFormInputFilter extends AbstractFormInputFilter
          {
          /** @var LocationFieldsetInputFilter */
          protected $locationFieldsetInputFilter;

          public function __construct(LocationFieldsetInputFilter $filter)
          {
          $this->locationFieldsetInputFilter = $filter;

          parent::__construct();
          }

          public function init()
          {
          $this->add($this->locationFieldsetInputFilter, 'location');

          parent::init();
          }
          }


          (The AbstractFormInputFilter adds CSRF validator)



          Notice that we simply ->add() the LocationFieldsetInputFilter, but we give it a name (2nd parameter). This name is used later in the complete structure, so it's important to both keep it simple and keep it correct. Simplest is to give it a name that one on one matches the object of the Fieldset it's supposed to validate.



          Next, the LocationFieldsetInputFilter:



          class LocationFieldsetInputFilter extends AbstractFieldsetInputFilter
          {
          /**
          * @var AddressFieldsetInputFilter
          */
          protected $addressFieldsetInputFilter;

          public function __construct(AddressFieldsetInputFilter $addressFieldsetInputFilter)
          {
          $this->addressFieldsetInputFilter = $addressFieldsetInputFilter;

          parent::__construct();
          }

          public function init()
          {
          parent::init();

          $this->add($this->addressFieldsetInputFilter, 'address'); // Again, name is important

          $this->add(
          [
          'name' => 'name',
          'required' => true,
          'filters' => [
          ['name' => StringTrim::class],
          ['name' => StripTags::class],
          [
          'name' => ToNull::class,
          'options' => [
          'type' => ToNull::TYPE_STRING,
          ],
          ],
          ],
          'validators' => [
          [
          'name' => StringLength::class,
          'options' => [
          'min' => 3,
          'max' => 255,
          ],
          ],
          ],
          ]
          );
          }
          }


          Factories



          Now, you must bind them together, which is where your question about Setter injection comes from I think. This happens in the Factory.



          A *FormFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          $inputFilterPluginManager = $container->get('InputFilterManager');
          $inputFilter = $inputFilterPluginManager->get(LocationFormInputFilter::class);

          /** @var LocationForm $form */
          $form = new LocationForm();
          $form->setInputFilter($inputFilter); // The setter injection you're after

          return $form;
          }


          A *FieldsetFactory would do the following (do the same for Location- and AddressFieldsets):



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          /** @var LocationFieldset $fieldset */
          // name matters! Match the object to keep it simple. Name is used from Form to match the InputFilter (with same name!)
          $fieldset = new LocationFieldset('location');
          // Zend Reflection Hydrator, could easily be something else, such as DoctrineObject hydrator.
          $fieldset->setHydrator(new Reflection());
          $fieldset->setObject(new Location());

          return $fieldset;
          }


          A *FormInputFilterFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          $inputFilterPluginManager = $container->get('InputFilterManager');

          /** @var LocationFieldsetInputFilter $locationFieldsetInputFilter */
          $locationFieldsetInputFilter = $inputFilterPluginManager->get(LocationFieldsetInputFilter::class);

          // Create Form InputFilter
          $locationFormInputFilter = new LocationFormInputFilter(
          $locationFieldsetInputFilter
          );

          return $locationFormInputFilter;
          }


          A *FieldsetInputFilterFactory would do the following:



          public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
          {
          /** @var AddressFieldsetInputFilter $addressFieldsetInputFilter */
          $addressFieldsetInputFilter = $this->getInputFilterManager()->get(AddressFieldsetInputFilter::class);
          $addressFieldsetInputFilter->setRequired(true);

          return new LocationFieldsetInputFilter(
          $addressFieldsetInputFilter
          );
          }


          Note:




          • Setting an InputFilter as (not) required is something I've added here

          • If your InputFilter (such as AddressFieldsetInputFilter) does not have a child InputFilter, you can can skip getting the child and straight away return the new InputFilter.




          I think I covered it all for a complete picture. If you have any questions about this, please comment.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 15 '18 at 8:55









          rkeetrkeet

          1,89621735




          1,89621735













          • hm, there many unclear questions in the process to change my example. so in my case, the FieldSetFactory isn't called, and the Hydrator isn't set. i have to implement getArrayCopy(). but i want to use the ClassMethods Hydrator. but i like your way to solve it

            – rob
            Nov 15 '18 at 10:24











          • The FieldsetFactory not being called is a common cause of doing $form->setFieldset(new Fieldset()) instead of $form->setFieldset($container->get(Fieldset::class)). Using the appropriate ServiceManager causes the Fieldset to be supplied using the Factory registered in the config instead of a straight up "new class()". Make sure your config is present and make sure you're using the right ServiceManager. (For Form & Fieldsets it's $container->get(Fieldset::class), for InputFilters it's $container->get('InputFilterManager')->get(InputFilter::class).

            – rkeet
            Nov 15 '18 at 10:53











          • ok, think i have to play something more with zend. its slightly different from symfony handling. but for this special case the answer from tasmaniski will be more fit to my question

            – rob
            Nov 15 '18 at 12:49











          • While initializers (tasmaniski's answer) do what you want them, please do read the docs and note: While convenient, initializer usage is also problematic. They are provided primarily for backwards compatibility, but we highly discourage their usage. and Instead, we encourage you to inject all necessary dependencies via the constructor, using factories. If some dependencies use setter or interface injection, use delegator factories. Of course, if it's the one time, by all means. But if not, slippery slope ;) If it's a new project or one being upgraded, I would advise factories instead.

            – rkeet
            Nov 15 '18 at 15:51











          • Ok, thats a reason to step over the initializer. So in Symfony there's something easier to use DI. But i want to learn to use zend too. Big thanks for your usefull help. i marked your post as answer, cause of the hint from the docs :-)

            – rob
            Nov 15 '18 at 18:13



















          • hm, there many unclear questions in the process to change my example. so in my case, the FieldSetFactory isn't called, and the Hydrator isn't set. i have to implement getArrayCopy(). but i want to use the ClassMethods Hydrator. but i like your way to solve it

            – rob
            Nov 15 '18 at 10:24











          • The FieldsetFactory not being called is a common cause of doing $form->setFieldset(new Fieldset()) instead of $form->setFieldset($container->get(Fieldset::class)). Using the appropriate ServiceManager causes the Fieldset to be supplied using the Factory registered in the config instead of a straight up "new class()". Make sure your config is present and make sure you're using the right ServiceManager. (For Form & Fieldsets it's $container->get(Fieldset::class), for InputFilters it's $container->get('InputFilterManager')->get(InputFilter::class).

            – rkeet
            Nov 15 '18 at 10:53











          • ok, think i have to play something more with zend. its slightly different from symfony handling. but for this special case the answer from tasmaniski will be more fit to my question

            – rob
            Nov 15 '18 at 12:49











          • While initializers (tasmaniski's answer) do what you want them, please do read the docs and note: While convenient, initializer usage is also problematic. They are provided primarily for backwards compatibility, but we highly discourage their usage. and Instead, we encourage you to inject all necessary dependencies via the constructor, using factories. If some dependencies use setter or interface injection, use delegator factories. Of course, if it's the one time, by all means. But if not, slippery slope ;) If it's a new project or one being upgraded, I would advise factories instead.

            – rkeet
            Nov 15 '18 at 15:51











          • Ok, thats a reason to step over the initializer. So in Symfony there's something easier to use DI. But i want to learn to use zend too. Big thanks for your usefull help. i marked your post as answer, cause of the hint from the docs :-)

            – rob
            Nov 15 '18 at 18:13

















          hm, there many unclear questions in the process to change my example. so in my case, the FieldSetFactory isn't called, and the Hydrator isn't set. i have to implement getArrayCopy(). but i want to use the ClassMethods Hydrator. but i like your way to solve it

          – rob
          Nov 15 '18 at 10:24





          hm, there many unclear questions in the process to change my example. so in my case, the FieldSetFactory isn't called, and the Hydrator isn't set. i have to implement getArrayCopy(). but i want to use the ClassMethods Hydrator. but i like your way to solve it

          – rob
          Nov 15 '18 at 10:24













          The FieldsetFactory not being called is a common cause of doing $form->setFieldset(new Fieldset()) instead of $form->setFieldset($container->get(Fieldset::class)). Using the appropriate ServiceManager causes the Fieldset to be supplied using the Factory registered in the config instead of a straight up "new class()". Make sure your config is present and make sure you're using the right ServiceManager. (For Form & Fieldsets it's $container->get(Fieldset::class), for InputFilters it's $container->get('InputFilterManager')->get(InputFilter::class).

          – rkeet
          Nov 15 '18 at 10:53





          The FieldsetFactory not being called is a common cause of doing $form->setFieldset(new Fieldset()) instead of $form->setFieldset($container->get(Fieldset::class)). Using the appropriate ServiceManager causes the Fieldset to be supplied using the Factory registered in the config instead of a straight up "new class()". Make sure your config is present and make sure you're using the right ServiceManager. (For Form & Fieldsets it's $container->get(Fieldset::class), for InputFilters it's $container->get('InputFilterManager')->get(InputFilter::class).

          – rkeet
          Nov 15 '18 at 10:53













          ok, think i have to play something more with zend. its slightly different from symfony handling. but for this special case the answer from tasmaniski will be more fit to my question

          – rob
          Nov 15 '18 at 12:49





          ok, think i have to play something more with zend. its slightly different from symfony handling. but for this special case the answer from tasmaniski will be more fit to my question

          – rob
          Nov 15 '18 at 12:49













          While initializers (tasmaniski's answer) do what you want them, please do read the docs and note: While convenient, initializer usage is also problematic. They are provided primarily for backwards compatibility, but we highly discourage their usage. and Instead, we encourage you to inject all necessary dependencies via the constructor, using factories. If some dependencies use setter or interface injection, use delegator factories. Of course, if it's the one time, by all means. But if not, slippery slope ;) If it's a new project or one being upgraded, I would advise factories instead.

          – rkeet
          Nov 15 '18 at 15:51





          While initializers (tasmaniski's answer) do what you want them, please do read the docs and note: While convenient, initializer usage is also problematic. They are provided primarily for backwards compatibility, but we highly discourage their usage. and Instead, we encourage you to inject all necessary dependencies via the constructor, using factories. If some dependencies use setter or interface injection, use delegator factories. Of course, if it's the one time, by all means. But if not, slippery slope ;) If it's a new project or one being upgraded, I would advise factories instead.

          – rkeet
          Nov 15 '18 at 15:51













          Ok, thats a reason to step over the initializer. So in Symfony there's something easier to use DI. But i want to learn to use zend too. Big thanks for your usefull help. i marked your post as answer, cause of the hint from the docs :-)

          – rob
          Nov 15 '18 at 18:13





          Ok, thats a reason to step over the initializer. So in Symfony there's something easier to use DI. But i want to learn to use zend too. Big thanks for your usefull help. i marked your post as answer, cause of the hint from the docs :-)

          – rob
          Nov 15 '18 at 18:13













          1














          What you need are Initializers from Zend Service Manager.



          The initializer can be a class that is called whenever a service has been created.
          In that class, you need to check the type of service that is created, and if it's appropriate type than inject whatever you want.



          To register one Initializer add in config under service_manager key:



          'service_manager' => [
          'initializers' => [
          MyInitializer::class
          ],
          ]


          and then just create that class



          class MyInitializer implements InitializerInterface
          {
          public function __invoke(ContainerInterface $container, $instance)
          {
          // you need to check should you inject or not
          if ($instance instanceof MessageGenerator) {
          $instance->setLogger($container->get('logger'));
          }
          }
          }


          You need to have registred MessageGenerator in zend-servicemanager also. In this way, when you try to retrive MessageGenerator from SM, after creation MyInitializer is called.






          share|improve this answer
























          • Beware: overuse of initializers may cause unnecessary overhead since every service retrieved from service locator would pass through registered initializers. While having a few application wide initializers are fine, they should be avoided as much as possible.

            – edigu
            Nov 20 '18 at 22:18
















          1














          What you need are Initializers from Zend Service Manager.



          The initializer can be a class that is called whenever a service has been created.
          In that class, you need to check the type of service that is created, and if it's appropriate type than inject whatever you want.



          To register one Initializer add in config under service_manager key:



          'service_manager' => [
          'initializers' => [
          MyInitializer::class
          ],
          ]


          and then just create that class



          class MyInitializer implements InitializerInterface
          {
          public function __invoke(ContainerInterface $container, $instance)
          {
          // you need to check should you inject or not
          if ($instance instanceof MessageGenerator) {
          $instance->setLogger($container->get('logger'));
          }
          }
          }


          You need to have registred MessageGenerator in zend-servicemanager also. In this way, when you try to retrive MessageGenerator from SM, after creation MyInitializer is called.






          share|improve this answer
























          • Beware: overuse of initializers may cause unnecessary overhead since every service retrieved from service locator would pass through registered initializers. While having a few application wide initializers are fine, they should be avoided as much as possible.

            – edigu
            Nov 20 '18 at 22:18














          1












          1








          1







          What you need are Initializers from Zend Service Manager.



          The initializer can be a class that is called whenever a service has been created.
          In that class, you need to check the type of service that is created, and if it's appropriate type than inject whatever you want.



          To register one Initializer add in config under service_manager key:



          'service_manager' => [
          'initializers' => [
          MyInitializer::class
          ],
          ]


          and then just create that class



          class MyInitializer implements InitializerInterface
          {
          public function __invoke(ContainerInterface $container, $instance)
          {
          // you need to check should you inject or not
          if ($instance instanceof MessageGenerator) {
          $instance->setLogger($container->get('logger'));
          }
          }
          }


          You need to have registred MessageGenerator in zend-servicemanager also. In this way, when you try to retrive MessageGenerator from SM, after creation MyInitializer is called.






          share|improve this answer













          What you need are Initializers from Zend Service Manager.



          The initializer can be a class that is called whenever a service has been created.
          In that class, you need to check the type of service that is created, and if it's appropriate type than inject whatever you want.



          To register one Initializer add in config under service_manager key:



          'service_manager' => [
          'initializers' => [
          MyInitializer::class
          ],
          ]


          and then just create that class



          class MyInitializer implements InitializerInterface
          {
          public function __invoke(ContainerInterface $container, $instance)
          {
          // you need to check should you inject or not
          if ($instance instanceof MessageGenerator) {
          $instance->setLogger($container->get('logger'));
          }
          }
          }


          You need to have registred MessageGenerator in zend-servicemanager also. In this way, when you try to retrive MessageGenerator from SM, after creation MyInitializer is called.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 15 '18 at 12:24









          tasmaniskitasmaniski

          3,87322258




          3,87322258













          • Beware: overuse of initializers may cause unnecessary overhead since every service retrieved from service locator would pass through registered initializers. While having a few application wide initializers are fine, they should be avoided as much as possible.

            – edigu
            Nov 20 '18 at 22:18



















          • Beware: overuse of initializers may cause unnecessary overhead since every service retrieved from service locator would pass through registered initializers. While having a few application wide initializers are fine, they should be avoided as much as possible.

            – edigu
            Nov 20 '18 at 22:18

















          Beware: overuse of initializers may cause unnecessary overhead since every service retrieved from service locator would pass through registered initializers. While having a few application wide initializers are fine, they should be avoided as much as possible.

          – edigu
          Nov 20 '18 at 22:18





          Beware: overuse of initializers may cause unnecessary overhead since every service retrieved from service locator would pass through registered initializers. While having a few application wide initializers are fine, they should be avoided as much as possible.

          – edigu
          Nov 20 '18 at 22:18


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53299020%2fzend-servicemanager-using-setter-injection%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Xamarin.iOS Cant Deploy on Iphone

          Glorious Revolution

          Dulmage-Mendelsohn matrix decomposition in Python