diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 75b89f95e5..04f7dec53b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.2.0 ----- + * Added a `AbstractController::addLink()` method to add Link headers to the current response * Allowed configuring taggable cache pools via a new `framework.cache.pools.tags` option (bool|service-id) * Allowed configuring PDO-based cache pools via a new `cache.adapter.pdo` abstract service * Deprecated auto-injection of the container in AbstractController instances, register them as service subscribers instead diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php index 6202ff9eb9..94441a3ae2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php @@ -12,6 +12,8 @@ namespace Symfony\Bundle\FrameworkBundle\Controller; use Doctrine\Common\Persistence\ManagerRegistry; +use Fig\Link\GenericLinkProvider; +use Fig\Link\Link; use Psr\Container\ContainerInterface; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormBuilderInterface; @@ -19,6 +21,7 @@ use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -27,6 +30,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Csrf\CsrfToken; +use Symfony\Component\WebLink\EventListener\AddLinkHeaderListener; /** * Common features needed in controllers. @@ -398,4 +402,26 @@ trait ControllerTrait return $this->container->get('message_bus')->dispatch($message); } + + /** + * Adds a Link HTTP header to the current response. + * + * @see https://tools.ietf.org/html/rfc5988 + * + * @final + */ + protected function addLink(Request $request, Link $link) + { + if (!class_exists(AddLinkHeaderListener::class)) { + throw new \LogicException('You can not use the "addLink" method if the WebLink component is not available. Try running "composer require symfony/web-link".'); + } + + if (null === $linkProvider = $request->attributes->get('_links')) { + $request->attributes->set('_links', new GenericLinkProvider(array($link))); + + return; + } + + $request->attributes->set('_links', $linkProvider->withLink($link)); + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php index f30e024b0c..41d463f573 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Controller; +use Fig\Link\Link; use Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait; use Symfony\Bundle\FrameworkBundle\Tests\TestCase; use Symfony\Component\DependencyInjection\Container; @@ -528,6 +529,21 @@ abstract class ControllerTraitTest extends TestCase $this->assertEquals($doctrine, $controller->getDoctrine()); } + + public function testAddLink() + { + $request = new Request(); + $link1 = new Link('mercure', 'https://demo.mercure.rocks'); + $link2 = new Link('self', 'https://example.com/foo'); + + $controller = $this->createController(); + $controller->addLink($request, $link1); + $controller->addLink($request, $link2); + + $links = $request->attributes->get('_links')->getLinks(); + $this->assertContains($link1, $links); + $this->assertContains($link2, $links); + } } trait TestControllerTrait @@ -552,5 +568,6 @@ trait TestControllerTrait createForm as public; createFormBuilder as public; getDoctrine as public; + addLink as public; } }