Skip to content

Commit 933208d

Browse files
committed
feature #57408 [FrameworkBundle] Simpler Kernel setup with MicroKernelTrait (yceruto)
This PR was merged into the 7.2 branch. Discussion ---------- [FrameworkBundle] Simpler Kernel setup with `MicroKernelTrait` | Q | A | ------------- | --- | Branch? | 7.2 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | - | License | MIT Minor improvements to create minimalistic Symfony apps with zero config (initially) + invokable controller using the Kernel class only: ```php // index.php <?php require_once __DIR__.'/vendor/autoload_runtime.php'; // ... class StripeWebhookEventSubscriber extends Kernel { use MicroKernelTrait; #[Route('/', methods: 'GET')] public function __invoke(Request $request, NotifierInterface $notifier): Response { // ... return new Response('OK'); } } return static function (array $context) { $kernel = new StripeWebhookEventSubscriber($context['APP_ENV'], (bool) $context['APP_DEBUG']); return \PHP_SAPI === 'cli' ? new Application($kernel) : $kernel; }; ``` > [!NOTE] > Ideal for one-file apps or workers. **What exactly does this PR improve?** * It makes the `config/` directory optional. Then you can add extension configs by redefining the `configureContainer()` method or by importing external files in `config/packages/*` as usual. * It adds support for service arguments when an invokable controller is defined within the same kernel class (as shown in the example) * Fall back to `yield new FrameworkBundle()` in `registerBundles()` method in case the `$this->getBundlesPath()` file does not exist. What do you think? Commits ------- 8176573134 Simpler kernel setup with MicroKernelTrait
2 parents 3b777e2 + da2a036 commit 933208d

File tree

5 files changed

+51
-18
lines changed

5 files changed

+51
-18
lines changed

CHANGELOG.md

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

77
* Add support for setting `headers` with `Symfony\Bundle\FrameworkBundle\Controller\TemplateController`
88
* Derivate `kernel.secret` from the decryption secret when its env var is not defined
9+
* Make the `config/` directory optional in `MicroKernelTrait`, add support for service arguments in the
10+
invokable Kernel class, and register `FrameworkBundle` by default when the `bundles.php` file is missing
911

1012
7.1
1113
---

Kernel/MicroKernelTrait.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\Kernel;
1313

14+
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1415
use Symfony\Component\Config\Loader\LoaderInterface;
1516
use Symfony\Component\DependencyInjection\ContainerBuilder;
1617
use Symfony\Component\DependencyInjection\Loader\Configurator\AbstractConfigurator;
@@ -48,7 +49,7 @@ trait MicroKernelTrait
4849
*/
4950
private function configureContainer(ContainerConfigurator $container, LoaderInterface $loader, ContainerBuilder $builder): void
5051
{
51-
$configDir = $this->getConfigDir();
52+
$configDir = preg_replace('{/config$}', '/{config}', $this->getConfigDir());
5253

5354
$container->import($configDir.'/{packages}/*.{php,yaml}');
5455
$container->import($configDir.'/{packages}/'.$this->environment.'/*.{php,yaml}');
@@ -73,7 +74,7 @@ private function configureContainer(ContainerConfigurator $container, LoaderInte
7374
*/
7475
private function configureRoutes(RoutingConfigurator $routes): void
7576
{
76-
$configDir = $this->getConfigDir();
77+
$configDir = preg_replace('{/config$}', '/{config}', $this->getConfigDir());
7778

7879
$routes->import($configDir.'/{routes}/'.$this->environment.'/*.{php,yaml}');
7980
$routes->import($configDir.'/{routes}/*.{php,yaml}');
@@ -84,7 +85,7 @@ private function configureRoutes(RoutingConfigurator $routes): void
8485
$routes->import($configDir.'/{routes}.php');
8586
}
8687

87-
if (false !== ($fileName = (new \ReflectionObject($this))->getFileName())) {
88+
if ($fileName = (new \ReflectionObject($this))->getFileName()) {
8889
$routes->import($fileName, 'attribute');
8990
}
9091
}
@@ -130,7 +131,13 @@ public function getLogDir(): string
130131

131132
public function registerBundles(): iterable
132133
{
133-
$contents = require $this->getBundlesPath();
134+
if (!is_file($bundlesPath = $this->getBundlesPath())) {
135+
yield new FrameworkBundle();
136+
137+
return;
138+
}
139+
140+
$contents = require $bundlesPath;
134141
foreach ($contents as $class => $envs) {
135142
if ($envs[$this->environment] ?? $envs['all'] ?? false) {
136143
yield new $class();
@@ -216,6 +223,8 @@ public function loadRoutes(LoaderInterface $loader): RouteCollection
216223
$route->setDefault('_controller', ['kernel', $controller[1]]);
217224
} elseif ($controller instanceof \Closure && $this === ($r = new \ReflectionFunction($controller))->getClosureThis() && !$r->isAnonymous()) {
218225
$route->setDefault('_controller', ['kernel', $r->name]);
226+
} elseif ($this::class === $controller && method_exists($this, '__invoke')) {
227+
$route->setDefault('_controller', 'kernel');
219228
}
220229
}
221230

Tests/Kernel/ConcreteMicroKernel.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Tests\Kernel;
1313

1414
use Psr\Log\NullLogger;
15-
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1615
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
1716
use Symfony\Component\Config\Loader\LoaderInterface;
1817
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -46,13 +45,6 @@ public function dangerousAction()
4645
throw new Danger();
4746
}
4847

49-
public function registerBundles(): iterable
50-
{
51-
return [
52-
new FrameworkBundle(),
53-
];
54-
}
55-
5648
public function getCacheDir(): string
5749
{
5850
return $this->cacheDir = sys_get_temp_dir().'/sf_micro_kernel';

Tests/Kernel/MicroKernelTraitTest.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Psr\Log\NullLogger;
16-
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1716
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
1817
use Symfony\Component\DependencyInjection\ContainerBuilder;
1918
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
@@ -140,6 +139,17 @@ protected function configureRoutes(RoutingConfigurator $routes): void
140139

141140
$this->assertSame('Hello World!', $response->getContent());
142141
}
142+
143+
public function testSimpleKernel()
144+
{
145+
$kernel = $this->kernel = new SimpleKernel('simple_kernel');
146+
$kernel->boot();
147+
148+
$request = Request::create('/');
149+
$response = $kernel->handle($request, HttpKernelInterface::MAIN_REQUEST, false);
150+
151+
$this->assertSame('Hello World!', $response->getContent());
152+
}
143153
}
144154

145155
abstract class MinimalKernel extends Kernel
@@ -155,11 +165,6 @@ public function __construct(string $cacheDir)
155165
$this->cacheDir = sys_get_temp_dir().'/'.$cacheDir;
156166
}
157167

158-
public function registerBundles(): iterable
159-
{
160-
yield new FrameworkBundle();
161-
}
162-
163168
public function getCacheDir(): string
164169
{
165170
return $this->cacheDir;

Tests/Kernel/SimpleKernel.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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 Symfony\Component\HttpFoundation\Response;
15+
use Symfony\Component\Routing\Attribute\Route;
16+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
17+
18+
final class SimpleKernel extends MinimalKernel
19+
{
20+
#[Route('/')]
21+
public function __invoke(UrlGeneratorInterface $urlGenerator): Response
22+
{
23+
return new Response('Hello World!');
24+
}
25+
}

0 commit comments

Comments
 (0)