Zend ServiceManager using setter injection
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
add a comment |
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
add a comment |
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
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
zend-framework zend-framework3
asked Nov 14 '18 at 11:20
robrob
1,31851526
1,31851526
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
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.
hm, there many unclear questions in the process to change my example. so in my case, theFieldSetFactory
isn't called, and theHydrator
isn't set. i have to implement getArrayCopy(). but i want to use theClassMethods
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.
andInstead, 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
add a comment |
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.
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
hm, there many unclear questions in the process to change my example. so in my case, theFieldSetFactory
isn't called, and theHydrator
isn't set. i have to implement getArrayCopy(). but i want to use theClassMethods
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.
andInstead, 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
add a comment |
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.
hm, there many unclear questions in the process to change my example. so in my case, theFieldSetFactory
isn't called, and theHydrator
isn't set. i have to implement getArrayCopy(). but i want to use theClassMethods
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.
andInstead, 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
add a comment |
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.
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.
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, theFieldSetFactory
isn't called, and theHydrator
isn't set. i have to implement getArrayCopy(). but i want to use theClassMethods
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.
andInstead, 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
add a comment |
hm, there many unclear questions in the process to change my example. so in my case, theFieldSetFactory
isn't called, and theHydrator
isn't set. i have to implement getArrayCopy(). but i want to use theClassMethods
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.
andInstead, 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
add a comment |
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.
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
add a comment |
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.
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
add a comment |
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.
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.
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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