mirror of
https://github.com/symfony/symfony-docs.git
synced 2026-03-24 00:32:14 +01:00
300 lines
10 KiB
ReStructuredText
300 lines
10 KiB
ReStructuredText
.. index::
|
|
single: DependencyInjection; Factories
|
|
|
|
Using a Factory to Create Services
|
|
==================================
|
|
|
|
Symfony's Service Container provides multiple features to control the creation
|
|
of objects, allowing you to specify arguments passed to the constructor as well
|
|
as calling methods and setting parameters.
|
|
|
|
However, sometimes you need to apply the `factory design pattern`_ to delegate
|
|
the object creation to some special object called "the factory". In those cases,
|
|
the service container can call a method on your factory to create the object
|
|
rather than directly instantiating the class.
|
|
|
|
Static Factories
|
|
----------------
|
|
|
|
Suppose you have a factory that configures and returns a new ``NewsletterManager``
|
|
object by calling the static ``createNewsletterManager()`` method::
|
|
|
|
class NewsletterManagerStaticFactory
|
|
{
|
|
public static function createNewsletterManager()
|
|
{
|
|
$newsletterManager = new NewsletterManager();
|
|
|
|
// ...
|
|
|
|
return $newsletterManager;
|
|
}
|
|
}
|
|
|
|
To make the ``NewsletterManager`` object available as a service, use the
|
|
``factory`` option to define which method of which class must be called to
|
|
create its object:
|
|
|
|
.. configuration-block::
|
|
|
|
.. code-block:: yaml
|
|
|
|
# config/services.yaml
|
|
services:
|
|
# ...
|
|
|
|
App\Email\NewsletterManager:
|
|
# the first argument is the class and the second argument is the static method
|
|
factory: ['App\Email\NewsletterManagerStaticFactory', 'createNewsletterManager']
|
|
|
|
.. code-block:: xml
|
|
|
|
<!-- config/services.xml -->
|
|
<?xml version="1.0" encoding="UTF-8" ?>
|
|
<container xmlns="http://symfony.com/schema/dic/services"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://symfony.com/schema/dic/services
|
|
https://symfony.com/schema/dic/services/services-1.0.xsd">
|
|
|
|
<services>
|
|
<service id="App\Email\NewsletterManager">
|
|
<!-- the first argument is the class and the second argument is the static method -->
|
|
<factory class="App\Email\NewsletterManagerStaticFactory" method="createNewsletterManager"/>
|
|
|
|
<!-- if the factory class is the same as the service class, you can omit
|
|
the 'class' attribute and define just the 'method' attribute:
|
|
|
|
<factory method="createNewsletterManager"/>
|
|
-->
|
|
</service>
|
|
</services>
|
|
</container>
|
|
|
|
.. code-block:: php
|
|
|
|
// config/services.php
|
|
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
|
|
|
use App\Email\NewsletterManager;
|
|
use App\Email\NewsletterManagerStaticFactory;
|
|
|
|
return function(ContainerConfigurator $configurator) {
|
|
$services = $configurator->services();
|
|
|
|
$services->set(NewsletterManager::class)
|
|
// the first argument is the class and the second argument is the static method
|
|
->factory([NewsletterManagerStaticFactory::class, 'createNewsletterManager']);
|
|
};
|
|
|
|
|
|
.. note::
|
|
|
|
When using a factory to create services, the value chosen for class
|
|
has no effect on the resulting service. The actual class name
|
|
only depends on the object that is returned by the factory. However,
|
|
the configured class name may be used by compiler passes and therefore
|
|
should be set to a sensible value.
|
|
|
|
Non-Static Factories
|
|
--------------------
|
|
|
|
If your factory is using a regular method instead of a static one to configure
|
|
and create the service, instantiate the factory itself as a service too.
|
|
Configuration of the service container then looks like this:
|
|
|
|
.. configuration-block::
|
|
|
|
.. code-block:: yaml
|
|
|
|
# config/services.yaml
|
|
services:
|
|
# ...
|
|
|
|
# first, create a service for the factory
|
|
App\Email\NewsletterManagerFactory: ~
|
|
|
|
# second, use the factory service as the first argument of the 'factory'
|
|
# option and the factory method as the second argument
|
|
App\Email\NewsletterManager:
|
|
factory: ['@App\Email\NewsletterManagerFactory', 'createNewsletterManager']
|
|
|
|
.. code-block:: xml
|
|
|
|
<!-- config/services.xml -->
|
|
<?xml version="1.0" encoding="UTF-8" ?>
|
|
<container xmlns="http://symfony.com/schema/dic/services"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://symfony.com/schema/dic/services
|
|
https://symfony.com/schema/dic/services/services-1.0.xsd">
|
|
|
|
<services>
|
|
<!-- first, create a service for the factory -->
|
|
<service id="App\Email\NewsletterManagerFactory"/>
|
|
|
|
<!-- second, use the factory service as the first argument of the 'factory'
|
|
option and the factory method as the second argument -->
|
|
<service id="App\Email\NewsletterManager">
|
|
<factory service="App\Email\NewsletterManagerFactory"
|
|
method="createNewsletterManager"
|
|
/>
|
|
</service>
|
|
</services>
|
|
</container>
|
|
|
|
.. code-block:: php
|
|
|
|
// config/services.php
|
|
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
|
|
|
use App\Email\NewsletterManager;
|
|
use App\Email\NewsletterManagerFactory;
|
|
|
|
return function(ContainerConfigurator $configurator) {
|
|
$services = $configurator->services();
|
|
|
|
// first, create a service for the factory
|
|
$services->set(NewsletterManagerFactory::class);
|
|
|
|
// second, use the factory service as the first argument of the 'factory'
|
|
// method and the factory method as the second argument
|
|
$services->set(NewsletterManager::class)
|
|
->factory([ref(NewsletterManagerFactory::class), 'createNewsletterManager']);
|
|
};
|
|
|
|
.. _factories-invokable:
|
|
|
|
Invokable Factories
|
|
-------------------
|
|
|
|
Suppose you now change your factory method to ``__invoke()`` so that your
|
|
factory service can be used as a callback::
|
|
|
|
class InvokableNewsletterManagerFactory
|
|
{
|
|
public function __invoke()
|
|
{
|
|
$newsletterManager = new NewsletterManager();
|
|
|
|
// ...
|
|
|
|
return $newsletterManager;
|
|
}
|
|
}
|
|
|
|
.. versionadded:: 4.3
|
|
|
|
Invokable factories for services were introduced in Symfony 4.3.
|
|
|
|
Services can be created and configured via invokable factories by omitting the
|
|
method name:
|
|
|
|
.. configuration-block::
|
|
|
|
.. code-block:: yaml
|
|
|
|
# config/services.yaml
|
|
services:
|
|
# ...
|
|
|
|
App\Email\NewsletterManager:
|
|
class: App\Email\NewsletterManager
|
|
factory: '@App\Email\NewsletterManagerFactory'
|
|
|
|
.. code-block:: xml
|
|
|
|
<!-- config/services.xml -->
|
|
<?xml version="1.0" encoding="UTF-8" ?>
|
|
<container xmlns="http://symfony.com/schema/dic/services"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://symfony.com/schema/dic/services
|
|
https://symfony.com/schema/dic/services/services-1.0.xsd">
|
|
|
|
<services>
|
|
<!-- ... -->
|
|
|
|
<service id="App\Email\NewsletterManager"
|
|
class="App\Email\NewsletterManager">
|
|
<factory service="App\Email\NewsletterManagerFactory"/>
|
|
</service>
|
|
</services>
|
|
</container>
|
|
|
|
.. code-block:: php
|
|
|
|
// config/services.php
|
|
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
|
|
|
use App\Email\NewsletterManager;
|
|
use App\Email\NewsletterManagerFactory;
|
|
|
|
return function(ContainerConfigurator $configurator) {
|
|
$services = $configurator->services();
|
|
|
|
$services->set(NewsletterManager::class)
|
|
->factory(ref(NewsletterManagerFactory::class));
|
|
};
|
|
|
|
.. _factories-passing-arguments-factory-method:
|
|
|
|
Passing Arguments to the Factory Method
|
|
---------------------------------------
|
|
|
|
.. tip::
|
|
|
|
Arguments to your factory method are :ref:`autowired <services-autowire>` if
|
|
that's enabled for your service.
|
|
|
|
If you need to pass arguments to the factory method you can use the ``arguments``
|
|
option. For example, suppose the ``createNewsletterManager()`` method in the
|
|
previous examples takes the ``templating`` service as an argument:
|
|
|
|
.. configuration-block::
|
|
|
|
.. code-block:: yaml
|
|
|
|
# config/services.yaml
|
|
services:
|
|
# ...
|
|
|
|
App\Email\NewsletterManager:
|
|
factory: ['@App\Email\NewsletterManagerFactory', createNewsletterManager]
|
|
arguments: ['@templating']
|
|
|
|
.. code-block:: xml
|
|
|
|
<!-- config/services.xml -->
|
|
<?xml version="1.0" encoding="UTF-8" ?>
|
|
<container xmlns="http://symfony.com/schema/dic/services"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://symfony.com/schema/dic/services
|
|
https://symfony.com/schema/dic/services/services-1.0.xsd">
|
|
|
|
<services>
|
|
<!-- ... -->
|
|
|
|
<service id="App\Email\NewsletterManager">
|
|
<factory service="App\Email\NewsletterManagerFactory" method="createNewsletterManager"/>
|
|
<argument type="service" id="templating"/>
|
|
</service>
|
|
</services>
|
|
</container>
|
|
|
|
.. code-block:: php
|
|
|
|
// config/services.php
|
|
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
|
|
|
use App\Email\NewsletterManager;
|
|
use App\Email\NewsletterManagerFactory;
|
|
|
|
return function(ContainerConfigurator $configurator) {
|
|
$services = $configurator->services();
|
|
|
|
$services->set(NewsletterManager::class)
|
|
->factory([ref(NewsletterManagerFactory::class), 'createNewsletterManager'])
|
|
->args([ref('templating')])
|
|
;
|
|
};
|
|
|
|
.. _`factory design pattern`: https://en.wikipedia.org/wiki/Factory_(object-oriented_programming)
|