Skip to content
Open
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
10 changes: 10 additions & 0 deletions components/http_kernel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,16 @@ Another typical use-case for this event is to retrieve the attributes from
the controller using the :method:`Symfony\\Component\\HttpKernel\\Event\\ControllerEvent::getAttributes`
method. See the Symfony section below for some examples.

Controller attributes are stored in the ``_controller_attributes`` request
attribute. This decouples them from the controller source code, allowing
listeners to override attributes at runtime (e.g. to change caching behavior
for specific requests without modifying the controller).

.. versionadded:: 8.1

Storing controller attributes in the ``_controller_attributes`` request
attribute was introduced in Symfony 8.1.

Listeners to this event can also change the controller callable completely
by calling :method:`ControllerEvent::setController <Symfony\\Component\\HttpKernel\\Event\\ControllerEvent::setController>`
on the event object that's passed to listeners on this event.
Expand Down
16 changes: 11 additions & 5 deletions logging/monolog_console.rst
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,17 @@ The Monolog console handler is enabled by default:

.. note::

The handler name (``console``) and the excluded channel (``!console``) are
independent concepts. The handler name is an arbitrary identifier for this
handler configuration, while ``!console`` excludes log messages from the
``console`` :doc:`logging channel </logging/channels_handlers>`, which is
used internally by the console component itself.
In this configuration, ``console`` is an arbitrary handler name and can be
any string. The ``type: console`` option selects the
:class:`Symfony\\Bridge\\Monolog\\Handler\\ConsoleHandler`, which writes log
messages to the command output.

The ``channels`` option uses the ``!`` prefix to exclude specific
:doc:`channels </logging/channels_handlers>`. The ``console`` channel is
excluded to reduce noise. This is the channel where Symfony logs command
lifecycle events (e.g. *Command "{command}" exited with code "{code}"*).
Excluding this channel does **not** affect any log messages you write yourself
inside your commands, which use different channels and will still appear normally.

Now, log messages will be shown on the console based on the log levels and verbosity.
By default (normal verbosity level), warnings and higher will be shown. But in
Expand Down
52 changes: 52 additions & 0 deletions reference/events.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,34 @@ even to change the controller entirely::
$event->setController($myCustomController);
}

You can also use ``getAttributes()`` to retrieve PHP attributes declared on the
controller:

.. code-block:: php-attributes

use Symfony\Component\HttpKernel\Event\ControllerEvent;

public function onKernelController(ControllerEvent $event): void
{
// get all attributes, grouped by class name
$allAttributes = $event->getAttributes();

// get all attributes as a flat list (not grouped)
$flatAttributes = $event->getAttributes('*');

// get attributes of a specific class
$cacheAttributes = $event->getAttributes(Cache::class);
}

Controller attributes are stored in the ``_controller_attributes`` request
attribute, which means they can be overridden at runtime to change the behavior
of attribute-based listeners without modifying the controller source code.

.. versionadded:: 8.1

Storing controller attributes in the ``_controller_attributes`` request
attribute was introduced in Symfony 8.1.

.. seealso::

Read more on the :ref:`kernel.controller event <component-http-kernel-kernel-controller>`.
Expand Down Expand Up @@ -164,6 +192,30 @@ before sending it back (e.g. add/modify HTTP headers, add cookies, etc.)::
// ... modify the response object
}

You can use ``getControllerAttributes()`` to retrieve PHP attributes declared
on the controller that handled the request:

.. code-block:: php-attributes

use Symfony\Component\HttpKernel\Event\ResponseEvent;

public function onKernelResponse(ResponseEvent $event): void
{
// get all controller attributes, grouped by class name
$allAttributes = $event->getControllerAttributes();

// get all controller attributes as a flat list (not grouped)
$flatAttributes = $event->getControllerAttributes('*');

// get attributes of a specific class
$cacheAttributes = $event->getControllerAttributes(Cache::class);
}

.. versionadded:: 8.1

The ``ResponseEvent::getControllerAttributes()`` method was introduced in
Symfony 8.1.

.. seealso::

Read more on the :ref:`kernel.response event <component-http-kernel-kernel-response>`.
Expand Down
13 changes: 0 additions & 13 deletions service_container.rst
Original file line number Diff line number Diff line change
Expand Up @@ -271,19 +271,6 @@ You can limit service registration to specific environments as follows:
services:
App\Service\AnotherClass: ~

.. code-block:: xml

<!-- config/services.xml -->
<services>
<service id="App\Service\SomeClass"/>

<when env="dev">
<services>
<service id="App\Service\AnotherClass"/>
</services>
</when>
</services>

.. code-block:: php

// config/services.php
Expand Down
28 changes: 16 additions & 12 deletions testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -314,27 +314,31 @@ concrete one::
No further configuration is required, as the test service container is a special one
that allows you to interact with private services and aliases.

Mocking non-shared services
Mocking Non-Shared Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Non-shared services can be mocked in tests when using the test service container.
:doc:`Non-shared services </service_container/shared>` are instantiated every time
they are retrieved from the container. For this reason, in tests you must mock
them using a ``Closure`` that acts as a factory, rather than a concrete instance::

Because non-shared services are instantiated every time they are retrieved,
they must be replaced by a *factory* instead of a concrete instance. For this
reason, non-shared services must be mocked using a ``Closure``::

static::bootKernel();
self::bootKernel();
$container = static::getContainer();

$services = [new \stdClass(), new \stdClass()];
$container->set(Mailer::class, function (): Mailer {
$mailer = $this->createMock(Mailer::class);
$mailer->method('send')->willReturn(true);

$container->set('non_shared_service', static function () use (&$services) {
return array_pop($services);
return $mailer;
});

The closure acts as a factory and is called each time the service is requested.
$newsletterGenerator = $container->get(NewsletterGenerator::class);

In this example, each time the container resolves ``Mailer``, the closure is
called and a new mock instance is returned

.. versionadded:: 8.1

Replacing a non-shared service with a non-callable value will throw an exception.
Support for mocking non-shared services was introduced in Symfony 8.1.

.. _testing-databases:

Expand Down
Loading