Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions reference/attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ Dependency Injection
* :ref:`Autoconfigure <lazy-services_configuration>`
* :ref:`AutoconfigureTag <di-instanceof>`
* :ref:`Autowire <autowire-attribute>`
* :ref:`AutowireCallable <container_closure-as-argument>`
* :doc:`AutowireDecorated </service_container/service_decoration>`
* :doc:`AutowireServiceClosure </service_container/service_closures>`
* :ref:`Exclude <service-psr4-loader>`
* :ref:`TaggedIterator <tags_reference-tagged-services>`
* :ref:`TaggedLocator <service-subscribers-locators_defining-service-locator>`
Expand Down
47 changes: 47 additions & 0 deletions service_container.rst
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,8 @@ For a full list of *all* possible services in the container, run:

$ php bin/console debug:container

.. _container_closure-as-argument:

Injecting a Closure as an Argument
----------------------------------

Expand Down Expand Up @@ -796,6 +798,51 @@ Our configuration looks like this:

The ``closure`` argument type was introduced in Symfony 6.1.

It is also possible to convert a callable into an injected closure
thanks to the
:class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireCallable`
attribute. Let's say our ``MessageHashGenerator`` class now has a ``generate()``
method::

// src/Hash/MessageHashGenerator.php
namespace App\Hash;

class MessageHashGenerator
{
public function generate(): string
{
// Compute and return a message hash
}
}

We can inject the ``generate()`` method of the ``MessageHashGenerator``
like this::

// src/Service/MessageGenerator.php
namespace App\Service;

use App\Hash\MessageHashGenerator;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Attribute\AutowireCallable;

class MessageGenerator
{
public function __construct(
private readonly LoggerInterface $logger,
#[AutowireCallable(service: MessageHashGenerator::class, method: 'generate')]
private readonly \Closure $generateMessageHash
) {
// ...
}

// ...
}

.. versionadded:: 6.3

The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireCallable`
attribute was introduced in Symfony 6.3.

.. _services-binding:

Binding Arguments by Name or Type
Expand Down
38 changes: 38 additions & 0 deletions service_container/service_closures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,44 @@ argument of type ``service_closure``:
Another way to inject services lazily is via a
:doc:`service locator </service_container/service_subscribers_locators>`.

Thanks to the
:class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireServiceClosure`
attribute, defining a service wrapped in a closure can directly be done
in the service class, without further configuration::

// src/Service/MyService.php
namespace App\Service;

use Symfony\Component\DependencyInjection\Attribute\AutowireServiceClosure;
use Symfony\Component\Mailer\MailerInterface;

class MyService
{
public function __construct(
#[AutowireServiceClosure('mailer')]
private readonly \Closure $mailer
) {
$this->mailer = $mailer;
}

public function doSomething(): void
{
// ...

$this->getMailer()->send($email);
}

private function getMailer(): MailerInterface
{
return ($this->mailer)();
}
}

.. versionadded:: 6.3

The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireServiceClosure`
attribute was introduced in Symfony 6.3.

Using a Service Closure in a Compiler Pass
------------------------------------------

Expand Down