Skip to content

Commit f2492af

Browse files
committed
feature #40575 [FrameworkBundle][HttpKernel][TwigBridge] Add an helper to generate fragments URL (dunglas)
This PR was squashed before being merged into the 5.3-dev branch. Discussion ---------- [FrameworkBundle][HttpKernel][TwigBridge] Add an helper to generate fragments URL | Q | A | ------------- | --- | Branch? | 5.x | Bug fix? | no | New feature? | yes <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tickets | Fix n/a | License | MIT | Doc PR | todo This PR adds a new helper to generate raw fragment URL. Fragments will be useful to generate lazy frames with Symfony UX Turbo (symfony/ux#64). This will also be convenient when using hinclude, ESI etc in case you want full control over the generated HTML. This is also more in sync with the new best practices we apply in the form component (generate the HTML by yourself instead of using Twig helpers hiding the HTML elements). Example: ```html <turbo-frame id="set_aside_tray" src="{{ fragment_uri(controller('Symfony\Bundle\FrameworkBundle\Controller', {template: "foo.html.twig"})) }}"> <img src="/icons/spinner.gif"> </turbo-frame> ``` Commits ------- 5d29d76612 [FrameworkBundle][HttpKernel][TwigBridge] Add an helper to generate fragments URL
2 parents 5e664fd + 18ef0a2 commit f2492af

File tree

4 files changed

+49
-1
lines changed

4 files changed

+49
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* Add a new `markAsPublic` method on `NotificationEmail` to change the `importance` context option to null after creation
8+
* Add a new `fragment_uri()` helper to generate the URI of a fragment
89

910
5.3.0
1011
-----

Extension/HttpKernelExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public function getFunctions(): array
3030
return [
3131
new TwigFunction('render', [HttpKernelRuntime::class, 'renderFragment'], ['is_safe' => ['html']]),
3232
new TwigFunction('render_*', [HttpKernelRuntime::class, 'renderFragmentStrategy'], ['is_safe' => ['html']]),
33+
new TwigFunction('fragment_uri', [HttpKernelRuntime::class, 'generateFragmentUri']),
3334
new TwigFunction('controller', static::class.'::controller'),
3435
];
3536
}

Extension/HttpKernelRuntime.php

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

1414
use Symfony\Component\HttpKernel\Controller\ControllerReference;
1515
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
16+
use Symfony\Component\HttpKernel\Fragment\FragmentUriGeneratorInterface;
1617

1718
/**
1819
* Provides integration with the HttpKernel component.
@@ -22,10 +23,12 @@
2223
final class HttpKernelRuntime
2324
{
2425
private $handler;
26+
private $fragmentUriGenerator;
2527

26-
public function __construct(FragmentHandler $handler)
28+
public function __construct(FragmentHandler $handler, FragmentUriGeneratorInterface $fragmentUriGenerator = null)
2729
{
2830
$this->handler = $handler;
31+
$this->fragmentUriGenerator = $fragmentUriGenerator;
2932
}
3033

3134
/**
@@ -54,4 +57,13 @@ public function renderFragmentStrategy(string $strategy, $uri, array $options =
5457
{
5558
return $this->handler->render($uri, $strategy, $options);
5659
}
60+
61+
public function generateFragmentUri(ControllerReference $controller, bool $absolute = false, bool $strict = true, bool $sign = true): string
62+
{
63+
if (null === $this->fragmentUriGenerator) {
64+
throw new \LogicException(sprintf('An instance of "%s" must be provided to use "%s()".', FragmentUriGeneratorInterface::class, __METHOD__));
65+
}
66+
67+
return $this->fragmentUriGenerator->generate($controller, null, $absolute, $strict, $sign);
68+
}
5769
}

Tests/Extension/HttpKernelExtensionTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Bridge\Twig\Extension\HttpKernelExtension;
1616
use Symfony\Bridge\Twig\Extension\HttpKernelRuntime;
17+
use Symfony\Bundle\FrameworkBundle\Controller\TemplateController;
1718
use Symfony\Component\HttpFoundation\Request;
1819
use Symfony\Component\HttpFoundation\RequestStack;
1920
use Symfony\Component\HttpFoundation\Response;
2021
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
2122
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
23+
use Symfony\Component\HttpKernel\Fragment\FragmentUriGenerator;
24+
use Symfony\Component\HttpKernel\UriSigner;
2225
use Twig\Environment;
2326
use Twig\Loader\ArrayLoader;
2427
use Twig\RuntimeLoader\RuntimeLoaderInterface;
@@ -53,6 +56,37 @@ public function testUnknownFragmentRenderer()
5356
$renderer->render('/foo');
5457
}
5558

59+
public function testGenerateFragmentUri()
60+
{
61+
if (!class_exists(FragmentUriGenerator::class)) {
62+
$this->markTestSkipped('HttpKernel 5.3+ is required');
63+
}
64+
65+
$requestStack = new RequestStack();
66+
$requestStack->push(Request::create('/'));
67+
68+
$fragmentHandler = new FragmentHandler($requestStack);
69+
$fragmentUriGenerator = new FragmentUriGenerator('/_fragment', new UriSigner('s3cr3t'), $requestStack);
70+
71+
$kernelRuntime = new HttpKernelRuntime($fragmentHandler, $fragmentUriGenerator);
72+
73+
$loader = new ArrayLoader([
74+
'index' => sprintf(<<<TWIG
75+
{{ fragment_uri(controller("%s::templateAction", {template: "foo.html.twig"})) }}
76+
TWIG
77+
, TemplateController::class), ]);
78+
$twig = new Environment($loader, ['debug' => true, 'cache' => false]);
79+
$twig->addExtension(new HttpKernelExtension());
80+
81+
$loader = $this->createMock(RuntimeLoaderInterface::class);
82+
$loader->expects($this->any())->method('load')->willReturnMap([
83+
[HttpKernelRuntime::class, $kernelRuntime],
84+
]);
85+
$twig->addRuntimeLoader($loader);
86+
87+
$this->assertSame('/_fragment?_hash=PP8%2FeEbn1pr27I9wmag%2FM6jYGVwUZ0l2h0vhh2OJ6CI%3D&amp;_path=template%3Dfoo.html.twig%26_format%3Dhtml%26_locale%3Den%26_controller%3DSymfonyBundleFrameworkBundleControllerTemplateController%253A%253AtemplateAction', $twig->render('index'));
88+
}
89+
5690
protected function getFragmentHandler($return)
5791
{
5892
$strategy = $this->createMock(FragmentRendererInterface::class);

0 commit comments

Comments
 (0)