Skip to content

Commit 67208cf

Browse files
bug #62535 [HttpKernel] Don't reset services between fragments redering when using in HttpCache (nicolas-grekas)
This PR was merged into the 7.4 branch. Discussion ---------- [HttpKernel] Don't reset services between fragments redering when using in HttpCache | Q | A | ------------- | --- | Branch? | 7.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix #62451 | License | MIT Commits ------- 9e8413f [HttpKernel] Don't reset services between fragments redering when using in HttpCache
2 parents 8d9bb32 + 9e8413f commit 67208cf

File tree

2 files changed

+84
-2
lines changed

2 files changed

+84
-2
lines changed

src/Symfony/Component/HttpKernel/Kernel.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
6767
private ?string $warmupDir = null;
6868
private int $requestStackSize = 0;
6969
private bool $resetServices = false;
70+
private bool $handlingHttpCache = false;
7071

7172
/**
7273
* @var array<string, bool>
@@ -98,6 +99,7 @@ public function __clone()
9899
$this->container = null;
99100
$this->requestStackSize = 0;
100101
$this->resetServices = false;
102+
$this->handlingHttpCache = false;
101103
}
102104

103105
public function boot(): void
@@ -170,13 +172,22 @@ public function handle(Request $request, int $type = HttpKernelInterface::MAIN_R
170172
$container = $this->container ?? $this->preBoot();
171173

172174
if ($container->has('http_cache')) {
173-
return $container->get('http_cache')->handle($request, $type, $catch);
175+
$this->handlingHttpCache = true;
176+
177+
try {
178+
return $container->get('http_cache')->handle($request, $type, $catch);
179+
} finally {
180+
$this->handlingHttpCache = false;
181+
$this->resetServices = true;
182+
}
174183
}
175184
}
176185

177186
$this->boot();
178187
++$this->requestStackSize;
179-
$this->resetServices = true;
188+
if (!$this->handlingHttpCache) {
189+
$this->resetServices = true;
190+
}
180191

181192
try {
182193
return $this->getHttpKernel()->handle($request, $type, $catch);

src/Symfony/Component/HttpKernel/Tests/KernelTest.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
1818
use Symfony\Component\DependencyInjection\ContainerBuilder;
1919
use Symfony\Component\DependencyInjection\ContainerInterface;
20+
use Symfony\Component\DependencyInjection\Reference;
2021
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
2122
use Symfony\Component\Filesystem\Exception\IOException;
2223
use Symfony\Component\Filesystem\Filesystem;
@@ -30,6 +31,7 @@
3031
use Symfony\Component\HttpKernel\HttpKernel;
3132
use Symfony\Component\HttpKernel\HttpKernelInterface;
3233
use Symfony\Component\HttpKernel\Kernel;
34+
use Symfony\Component\HttpKernel\KernelInterface;
3335
use Symfony\Component\HttpKernel\Tests\Fixtures\KernelWithoutBundles;
3436
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
3537

@@ -492,6 +494,39 @@ public function testServicesResetter()
492494
$this->assertEquals(1, ResettableService::$counter);
493495
}
494496

497+
public function testServicesAreNotResetBetweenHttpCacheFragments()
498+
{
499+
ResettableService::$counter = 0;
500+
$fragmentKernel = new FragmentHandlingKernel();
501+
502+
$kernel = new CustomProjectDirKernel(function (ContainerBuilder $container) {
503+
$container->addCompilerPass(new ResettableServicePass());
504+
$container->register('kernel', CustomProjectDirKernel::class)
505+
->setSynthetic(true)
506+
->setPublic(true);
507+
$container->register('one', ResettableService::class)
508+
->setPublic(true)
509+
->addTag('kernel.reset', ['method' => 'reset']);
510+
$container->register('services_resetter', ServicesResetter::class)->setPublic(true);
511+
$container->register('http_cache', FragmentRenderingHttpCache::class)
512+
->setPublic(true)
513+
->addArgument(new Reference('kernel'));
514+
}, $fragmentKernel, 'http_cache_fragments');
515+
516+
$kernel->handle(new Request());
517+
518+
$this->assertSame([
519+
['/first-fragment', HttpKernelInterface::MAIN_REQUEST],
520+
['/second-fragment', HttpKernelInterface::MAIN_REQUEST],
521+
], $fragmentKernel->handledPaths);
522+
$this->assertSame([0, 0], $fragmentKernel->resetCounters);
523+
$this->assertSame(0, ResettableService::$counter);
524+
525+
$kernel->boot();
526+
527+
$this->assertSame(1, ResettableService::$counter);
528+
}
529+
495530
#[Group('time-sensitive')]
496531
public function testKernelStartTimeIsResetWhileBootingAlreadyBootedKernel()
497532
{
@@ -731,3 +766,39 @@ public function doLoadClassCache(): void
731766
{
732767
}
733768
}
769+
770+
class FragmentHandlingKernel implements HttpKernelInterface
771+
{
772+
public array $handledPaths = [];
773+
public array $resetCounters = [];
774+
775+
public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response
776+
{
777+
$this->handledPaths[] = [$request->getPathInfo(), $type];
778+
$this->resetCounters[] = ResettableService::$counter;
779+
780+
return new Response($request->getPathInfo());
781+
}
782+
}
783+
784+
class FragmentRenderingHttpCache implements HttpKernelInterface
785+
{
786+
public function __construct(
787+
private KernelInterface $kernel,
788+
private string $trackedServiceId = 'one',
789+
) {
790+
}
791+
792+
public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response
793+
{
794+
$this->kernel->boot();
795+
$this->kernel->getContainer()->get($this->trackedServiceId);
796+
797+
$responses = [];
798+
foreach (['/first-fragment', '/second-fragment'] as $path) {
799+
$responses[] = $this->kernel->handle(Request::create($path), self::MAIN_REQUEST, $catch);
800+
}
801+
802+
return new Response(implode('', array_map(static fn (Response $response) => $response->getContent(), $responses)));
803+
}
804+
}

0 commit comments

Comments
 (0)