Skip to content

Commit 4c04c38

Browse files
committed
add framework integration and controller decoration support
1 parent 18db3b3 commit 4c04c38

File tree

7 files changed

+86
-0
lines changed

7 files changed

+86
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ CHANGELOG
1212
* Deprecate making `cache.app` adapter taggable, use the `cache.app.taggable` adapter instead
1313
* Enable `json_decode_detailed_errors` in the default serializer context in debug mode by default when `seld/jsonlint` is installed
1414
* Register `Symfony\Component\Serializer\NameConverter\SnakeCaseToCamelCaseNameConverter` as a service named `serializer.name_converter.snake_case_to_camel_case` if available
15+
* Add Decorator component integration and controller decoration support
1516

1617
7.1
1718
---

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
use Symfony\Component\Console\DataCollector\CommandDataCollector;
5353
use Symfony\Component\Console\Debug\CliRequest;
5454
use Symfony\Component\Console\Messenger\RunCommandMessageHandler;
55+
use Symfony\Component\Decorator\DecoratorInterface;
5556
use Symfony\Component\DependencyInjection\Alias;
5657
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
5758
use Symfony\Component\DependencyInjection\ChildDefinition;
@@ -224,6 +225,10 @@ public function load(array $configs, ContainerBuilder $container): void
224225
$loader->load('fragment_renderer.php');
225226
$loader->load('error_renderer.php');
226227

228+
if (ContainerBuilder::willBeAvailable('symfony/decorator', DecoratorInterface::class, ['symfony/framework-bundle'])) {
229+
$loader->load('decorator.php');
230+
}
231+
227232
if (!ContainerBuilder::willBeAvailable('symfony/clock', ClockInterface::class, ['symfony/framework-bundle'])) {
228233
$container->removeDefinition('clock');
229234
$container->removeAlias(ClockInterface::class);
@@ -658,6 +663,8 @@ public function load(array $configs, ContainerBuilder $container): void
658663
->addTag('mime.mime_type_guesser');
659664
$container->registerForAutoconfiguration(LoggerAwareInterface::class)
660665
->addMethodCall('setLogger', [new Reference('logger')]);
666+
$container->registerForAutoconfiguration(DecoratorInterface::class)
667+
->addTag('decorator');
661668

662669
$container->registerAttributeForAutoconfiguration(AsEventListener::class, static function (ChildDefinition $definition, AsEventListener $attribute, \ReflectionClass|\ReflectionMethod $reflector) {
663670
$tagAttributes = get_object_vars($attribute);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\EventListener;
13+
14+
use Symfony\Component\Decorator\DecoratorInterface;
15+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
16+
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
17+
use Symfony\Component\HttpKernel\KernelEvents;
18+
19+
/**
20+
* @author Yonel Ceruto <open@yceruto.dev>
21+
*/
22+
final readonly class DecorateControllerListener implements EventSubscriberInterface
23+
{
24+
public function __construct(
25+
private DecoratorInterface $decorator,
26+
) {
27+
}
28+
29+
public function decorate(ControllerArgumentsEvent $event): void
30+
{
31+
$event->setController($this->decorator->decorate($event->getController()(...)));
32+
}
33+
34+
public static function getSubscribedEvents(): array
35+
{
36+
return [
37+
KernelEvents::CONTROLLER_ARGUMENTS => ['decorate', -1024],
38+
];
39+
}
40+
}

src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use Symfony\Component\Config\Resource\ClassExistenceResource;
3434
use Symfony\Component\Console\ConsoleEvents;
3535
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
36+
use Symfony\Component\Decorator\DependencyInjection\DecoratorsPass;
3637
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
3738
use Symfony\Component\DependencyInjection\Compiler\RegisterReverseContainerPass;
3839
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -173,6 +174,7 @@ public function build(ContainerBuilder $container): void
173174
// must be registered after MonologBundle's LoggerChannelPass
174175
$container->addCompilerPass(new ErrorLoggerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
175176
$container->addCompilerPass(new VirtualRequestStackPass());
177+
$this->addCompilerPassIfExists($container, DecoratorsPass::class);
176178

177179
if ($container->getParameter('kernel.debug')) {
178180
$container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 2);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
13+
14+
use Symfony\Bundle\FrameworkBundle\EventListener\DecorateControllerListener;
15+
use Symfony\Component\Decorator\DecoratorChain;
16+
use Symfony\Component\Decorator\DecoratorInterface;
17+
18+
return static function (ContainerConfigurator $container) {
19+
$container->services()
20+
->set('decorator.chain', DecoratorChain::class)
21+
->args([
22+
abstract_arg('decorators locator, set in DecoratorsPass')
23+
])
24+
25+
->set('decorator.listener.controller', DecorateControllerListener::class)
26+
->args([
27+
service('decorator.chain')
28+
])
29+
->tag('kernel.event_subscriber')
30+
31+
->alias(DecoratorInterface::class, 'decorator.chain')
32+
;
33+
};

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"symfony/console": "^6.4|^7.0",
4343
"symfony/clock": "^6.4|^7.0",
4444
"symfony/css-selector": "^6.4|^7.0",
45+
"symfony/decorator": "^7.2",
4546
"symfony/dom-crawler": "^6.4|^7.0",
4647
"symfony/dotenv": "^6.4|^7.0",
4748
"symfony/polyfill-intl-icu": "~1.0",

src/Symfony/Component/Decorator/DecoratorChain.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
/**
1919
* @author Yonel Ceruto <open@yceruto.dev>
20+
*
21+
* @experimental
2022
*/
2123
readonly class DecoratorChain implements DecoratorInterface
2224
{

0 commit comments

Comments
 (0)