Skip to content

Commit cc9f9f2

Browse files
[FrameworkBundle] Allow using the kernel as a registry of controllers and service factories
1 parent fb2c385 commit cc9f9f2

File tree

9 files changed

+164
-8
lines changed

9 files changed

+164
-8
lines changed

src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
use Symfony\Component\Config\Loader\LoaderInterface;
1515
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\DependencyInjection\Definition;
17+
use Symfony\Component\DependencyInjection\Loader\Configurator\AbstractConfigurator;
1618
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
19+
use Symfony\Component\DependencyInjection\Reference;
1720
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1821
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
1922
use Symfony\Component\Routing\RouteCollection;
@@ -93,6 +96,7 @@ public function registerContainerConfiguration(LoaderInterface $loader)
9396

9497
if (!$container->hasDefinition('kernel')) {
9598
$container->register('kernel', static::class)
99+
->addTag('controller.service_arguments')
96100
->setSynthetic(true)
97101
->setPublic(true)
98102
;
@@ -109,6 +113,7 @@ public function registerContainerConfiguration(LoaderInterface $loader)
109113
$container->fileExists($this->getProjectDir().'/config/bundles.php');
110114
$container->setParameter('container.dumper.inline_class_loader', \PHP_VERSION_ID < 70400 || !ini_get('opcache.preload'));
111115
$container->setParameter('container.dumper.inline_factories', true);
116+
$container->setParameter('kernel.secret', '%env(APP_SECRET)%');
112117

113118
try {
114119
$this->configureContainer($container, $loader);
@@ -122,16 +127,33 @@ public function registerContainerConfiguration(LoaderInterface $loader)
122127
}
123128
}
124129

130+
$defaultDefinition = (new Definition())->setAutowired(true)->setAutoconfigured(true);
125131
$kernelLoader = $loader->getResolver()->resolve($file);
126132
$kernelLoader->setCurrentDir(\dirname($file));
127133
$instanceof = &\Closure::bind(function &() { return $this->instanceof; }, $kernelLoader, $kernelLoader)();
128134

135+
$valuePreProcessor = AbstractConfigurator::$valuePreProcessor;
136+
AbstractConfigurator::$valuePreProcessor = function ($value) use ($kernelDefinition) {
137+
if ($this === $value) {
138+
return new Reference('kernel');
139+
}
140+
141+
if (\is_array($value) && [0, 1] === array_keys($value) && $value[0] instanceof Reference && 'kernel' === (string) $value[0] && method_exists($this, $value[1])) {
142+
$kernelDefinition->addTag('controller.service_arguments', ['exclude_method' => $value[1]]);
143+
}
144+
145+
return $value;
146+
};
147+
129148
try {
130-
$this->configureContainer(new ContainerConfigurator($container, $kernelLoader, $instanceof, $file, $file), $loader);
149+
$this->configureContainer(new ContainerConfigurator($container, $kernelLoader, $instanceof, $file, $file, $defaultDefinition), $loader);
131150
} finally {
132151
$instanceof = [];
133152
$kernelLoader->registerAliasesForSinglyImplementedInterfaces();
153+
AbstractConfigurator::$valuePreProcessor = $valuePreProcessor;
134154
}
155+
156+
$container->setAlias(static::class, 'kernel');
135157
});
136158
}
137159

@@ -148,6 +170,14 @@ public function loadRoutes(LoaderInterface $loader)
148170
try {
149171
$this->configureRoutes(new RoutingConfigurator($collection, $kernelLoader, $file, $file));
150172

173+
foreach ($collection as $route) {
174+
$controller = $route->getDefault('_controller');
175+
176+
if (\is_array($controller) && [0, 1] === array_keys($controller) && $this === $controller[0]) {
177+
$route->setDefault('_controller', ['kernel', $controller[1]]);
178+
}
179+
}
180+
151181
return $collection;
152182
} catch (\TypeError $e) {
153183
if (0 !== strpos($e->getMessage(), sprintf('Argument 1 passed to %s::configureRoutes() must be an instance of %s,', static::class, RouteCollectionBuilder::class))) {

src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
1818
use Symfony\Component\HttpFoundation\Request;
1919

20+
require_once __DIR__.'/flex-style/src/FlexStyleMicroKernel.php';
21+
2022
class MicroKernelTraitTest extends TestCase
2123
{
2224
public function test()
@@ -56,4 +58,15 @@ public function testRoutingRouteLoaderTagIsAdded()
5658
$kernel->registerContainerConfiguration(new ClosureLoader($container));
5759
$this->assertTrue($container->getDefinition('kernel')->hasTag('routing.route_loader'));
5860
}
61+
62+
public function testFlexStyle()
63+
{
64+
$kernel = new FlexStyleMicroKernel('test', false);
65+
$kernel->boot();
66+
67+
$request = Request::create('/');
68+
$response = $kernel->handle($request);
69+
70+
$this->assertEquals('Have a great day!', $response->getContent());
71+
}
5972
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
4+
5+
return [
6+
FrameworkBundle::class => ['all' => true],
7+
];
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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\Tests\Kernel;
13+
14+
use Psr\Log\LoggerInterface;
15+
use Psr\Log\NullLogger;
16+
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
17+
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
18+
use Symfony\Component\Filesystem\Filesystem;
19+
use Symfony\Component\HttpFoundation\Response;
20+
use Symfony\Component\HttpKernel\Kernel;
21+
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
22+
23+
class FlexStyleMicroKernel extends Kernel
24+
{
25+
use MicroKernelTrait;
26+
27+
private $cacheDir;
28+
29+
public function halloweenAction(\stdClass $o)
30+
{
31+
return new Response($o->halloween);
32+
}
33+
34+
public function createHalloween(LoggerInterface $logger, string $halloween)
35+
{
36+
$o = new \stdClass();
37+
$o->logger = $logger;
38+
$o->halloween = $halloween;
39+
40+
return $o;
41+
}
42+
43+
public function getCacheDir(): string
44+
{
45+
return $this->cacheDir = sys_get_temp_dir().'/sf_flex_kernel';
46+
}
47+
48+
public function getLogDir(): string
49+
{
50+
return $this->cacheDir;
51+
}
52+
53+
public function __sleep(): array
54+
{
55+
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
56+
}
57+
58+
public function __wakeup()
59+
{
60+
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
61+
}
62+
63+
public function __destruct()
64+
{
65+
$fs = new Filesystem();
66+
$fs->remove($this->cacheDir);
67+
}
68+
69+
protected function configureRoutes(RoutingConfigurator $routes): void
70+
{
71+
$routes->add('halloween', '/')->controller([$this, 'halloweenAction']);
72+
}
73+
74+
protected function configureContainer(ContainerConfigurator $c)
75+
{
76+
$c->parameters()
77+
->set('halloween', 'Have a great day!');
78+
79+
$c->services()
80+
->set('logger', NullLogger::class)
81+
->set('stdClass', 'stdClass')
82+
->factory([$this, 'createHalloween'])
83+
->arg('$halloween', '%halloween%');
84+
}
85+
}

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"ext-xml": "*",
2121
"symfony/cache": "^4.4|^5.0",
2222
"symfony/config": "^5.0",
23-
"symfony/dependency-injection": "^5.0.1",
23+
"symfony/dependency-injection": "^5.1",
2424
"symfony/error-handler": "^4.4.1|^5.0.1",
2525
"symfony/http-foundation": "^4.4|^5.0",
2626
"symfony/http-kernel": "^5.0",

src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractConfigurator.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ abstract class AbstractConfigurator
2222
{
2323
const FACTORY = 'unknown';
2424

25+
/**
26+
* @var callable(mixed $value, bool $allowService)|null
27+
*/
28+
public static $valuePreProcessor;
29+
2530
/** @internal */
2631
protected $definition;
2732

@@ -49,7 +54,11 @@ public static function processValue($value, $allowServices = false)
4954
$value[$k] = static::processValue($v, $allowServices);
5055
}
5156

52-
return $value;
57+
return self::$valuePreProcessor ? (self::$valuePreProcessor)($value, $allowServices) : $value;
58+
}
59+
60+
if (self::$valuePreProcessor) {
61+
$value = (self::$valuePreProcessor)($value, $allowServices);
5362
}
5463

5564
if ($value instanceof ReferenceConfigurator) {

src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,16 @@ class ContainerConfigurator extends AbstractConfigurator
3434
private $path;
3535
private $file;
3636
private $anonymousCount = 0;
37+
private $defaultDefinition;
3738

38-
public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, string $path, string $file)
39+
public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, string $path, string $file, Definition $defaultDefinition = null)
3940
{
4041
$this->container = $container;
4142
$this->loader = $loader;
4243
$this->instanceof = &$instanceof;
4344
$this->path = $path;
4445
$this->file = $file;
46+
$this->defaultDefinition = $defaultDefinition;
4547
}
4648

4749
final public function extension(string $namespace, array $config)
@@ -73,7 +75,7 @@ final public function parameters(): ParametersConfigurator
7375

7476
final public function services(): ServicesConfigurator
7577
{
76-
return new ServicesConfigurator($this->container, $this->loader, $this->instanceof, $this->path, $this->anonymousCount);
78+
return new ServicesConfigurator($this->container, $this->loader, $this->instanceof, $this->path, $this->anonymousCount, $this->defaultDefinition);
7779
}
7880
}
7981

src/Symfony/Component/DependencyInjection/Loader/Configurator/ServicesConfigurator.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,19 @@ class ServicesConfigurator extends AbstractConfigurator
3232
private $path;
3333
private $anonymousHash;
3434
private $anonymousCount;
35+
private $defaultDefinition;
3536

36-
public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, string $path = null, int &$anonymousCount = 0)
37+
public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, string $path = null, int &$anonymousCount = 0, Definition $defaultDefinition = null)
3738
{
38-
$this->defaults = new Definition();
39+
$defaultDefinition = $defaultDefinition ?? new Definition();
40+
$this->defaults = clone $defaultDefinition;
3941
$this->container = $container;
4042
$this->loader = $loader;
4143
$this->instanceof = &$instanceof;
4244
$this->path = $path;
4345
$this->anonymousHash = ContainerBuilder::hash($path ?: mt_rand());
4446
$this->anonymousCount = &$anonymousCount;
47+
$this->defaultDefinition = $defaultDefinition;
4548
$instanceof = [];
4649
}
4750

@@ -50,7 +53,7 @@ public function __construct(ContainerBuilder $container, PhpFileLoader $loader,
5053
*/
5154
final public function defaults(): DefaultsConfigurator
5255
{
53-
return new DefaultsConfigurator($this, $this->defaults = new Definition(), $this->path);
56+
return new DefaultsConfigurator($this, $this->defaults = clone $this->defaultDefinition, $this->path);
5457
}
5558

5659
/**

src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ public function process(ContainerBuilder $container)
8585
}
8686
}
8787

88+
foreach ($tags as $i => $attributes) {
89+
if (isset($attributes['exclude_method'])) {
90+
unset($methods[strtolower($attributes['exclude_method'])]);
91+
unset($tags[$i]);
92+
}
93+
}
94+
8895
// validate and collect explicit per-actions and per-arguments service references
8996
foreach ($tags as $attributes) {
9097
if (!isset($attributes['action']) && !isset($attributes['argument']) && !isset($attributes['id'])) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy