feature #28875 [FWBundle] Add a new method AbstractController::addLink() (dunglas)

This PR was squashed before being merged into the 4.2-dev branch (closes #28875).

Discussion
----------

[FWBundle] Add a new method AbstractController::addLink()

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      |no
| New feature?  | yes <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | n/a   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | todo

This provides a convenient method to add `Link` headers to the current `Response` directly from the `Request` object.
It improves the developer experience and the discoverability of [the WebLink component](https://github.com/symfony/symfony-docs/pull/10309).

Usage:

```php
namespace App\Controller;

use Fig\Link\Link;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class MyAction extends AbstractController
{
    public function __invoke(Request $request): Response
    {
        $this->addLink($request, new Link('mercure', 'https://demo.mercure.rocks'));

        return $this->json(['foo' => 'bar']);
    }
}
```

Commits
-------

4d20c39f70 [FWBundle] Add a new method AbstractController::addLink()
This commit is contained in:
Fabien Potencier 2018-10-24 05:28:52 +02:00
commit b452c015cc
3 changed files with 44 additions and 0 deletions

View File

@ -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

View File

@ -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));
}
}

View File

@ -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;
}
}