@@ -159,20 +159,19 @@ service, including controllers::
159159 namespace App\Controller;
160160
161161 use Symfony\Component\HttpFoundation\Response;
162- use Symfony\Component\Mercure\PublisherInterface ;
162+ use Symfony\Component\Mercure\HubInterface ;
163163 use Symfony\Component\Mercure\Update;
164164
165165 class PublishController
166166 {
167- public function __invoke(PublisherInterface $publisher ): Response
167+ public function __invoke(HubInterface $hub ): Response
168168 {
169169 $update = new Update(
170170 'http://example.com/books/1',
171171 json_encode(['status' => 'OutOfStock'])
172172 );
173173
174- // The Publisher service is an invokable object
175- $publisher($update);
174+ $hub->publish($update);
176175
177176 return new Response('published!');
178177 }
@@ -297,17 +296,14 @@ by using the ``AbstractController::addLink`` helper method::
297296 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
298297 use Symfony\Component\HttpFoundation\JsonResponse;
299298 use Symfony\Component\HttpFoundation\Request;
300- use Symfony\Component\WebLink\Link ;
299+ use Symfony\Component\Mercure\Discovery ;
301300
302301 class DiscoverController extends AbstractController
303302 {
304- public function __invoke(Request $request): JsonResponse
303+ public function __invoke(Request $request, Discovery $discovery ): JsonResponse
305304 {
306- // This parameter is automatically created by the MercureBundle
307- $hubUrl = $this->getParameter('mercure.default_hub');
308-
309305 // Link: <http://localhost:3000/.well-known/mercure>; rel="mercure"
310- $this ->addLink($request, new Link('mercure', $hubUrl) );
306+ $discovery ->addLink($request);
311307
312308 return $this->json([
313309 '@id' => '/books/1',
@@ -346,13 +342,13 @@ of the ``Update`` constructor to ``true``::
346342 // src/Controller/Publish.php
347343 namespace App\Controller;
348344
345+ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
349346 use Symfony\Component\HttpFoundation\Response;
350- use Symfony\Component\Mercure\PublisherInterface;
351347 use Symfony\Component\Mercure\Update;
352348
353- class PublishController
349+ class PublishController extends AbstractController
354350 {
355- public function __invoke(PublisherInterface $publisher ): Response
351+ public function __invoke(HubInterface $hub ): Response
356352 {
357353 $update = new Update(
358354 'http://example.com/books/1',
@@ -362,7 +358,7 @@ of the ``Update`` constructor to ``true``::
362358
363359 // Publisher's JWT must contain this topic, a URI template it matches or * in mercure.publish or you'll get a 401
364360 // Subscriber's JWT must contain this topic, a URI template it matches or * in mercure.subscribe to receive the update
365- $publisher ($update);
361+ $hub->publish ($update);
366362
367363 return new Response('private update published!');
368364 }
@@ -417,39 +413,26 @@ And here is the controller::
417413 // src/Controller/DiscoverController.php
418414 namespace App\Controller;
419415
420- use Lcobucci\JWT\Configuration;
421- use Lcobucci\JWT\Signer\Hmac\Sha256;
422- use Lcobucci\JWT\Signer\Key;
423416 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
424- use Symfony\Component\HttpFoundation\Cookie;
425417 use Symfony\Component\HttpFoundation\Request;
426418 use Symfony\Component\HttpFoundation\Response;
427- use Symfony\Component\WebLink\Link;
419+ use Symfony\Component\Mercure\Authorization;
420+ use Symfony\Component\Mercure\Discovery;
428421
429422 class DiscoverController extends AbstractController
430423 {
431- public function __invoke(Request $request): Response
424+ public function __invoke(Request $request, Discovery $discovery, Authorization $authorization ): Response
432425 {
433- $hubUrl = $this->getParameter('mercure.default_hub');
434- $this->addLink($request, new Link('mercure', $hubUrl));
435-
436- $key = Key\InMemory::plainText('mercure_secret_key'); // don't forget to set this parameter! Test value: !ChangeMe!
437- $configuration = Configuration::forSymmetricSigner(new Sha256(), $key);
438-
439- $token = $configuration->builder()
440- ->withClaim('mercure', ['subscribe' => ["http://example.com/books/1"]]) // can also be a URI template, or *
441- ->getToken($configuration->signer(), $configuration->signingKey())
442- ->toString();
443-
444- $response = $this->json(['@id' => '/demo/books/1', 'availability' => 'https://schema.org/InStock']);
445- $cookie = Cookie::create('mercureAuthorization')
446- ->withValue($token)
447- ->withPath('/.well-known/mercure')
448- ->withSecure(true)
449- ->withHttpOnly(true)
450- ->withSameSite('strict')
451- ;
452- $response->headers->setCookie($cookie);
426+ $discovery->addLink($request);
427+
428+ $response = new JsonResponse([
429+ '@id' => '/demo/books/1',
430+ 'availability' => 'https://schema.org/InStock'
431+ ]);
432+
433+ $response->headers->setCookie(
434+ $authorization->createCookie($request, ["http://example.com/books/1"])
435+ );
453436
454437 return $response;
455438 }
@@ -464,15 +447,17 @@ Programmatically Generating The JWT Used to Publish
464447---------------------------------------------------
465448
466449Instead of directly storing a JWT in the configuration,
467- you can create a service that will return the token used by
468- the ``Publisher `` object::
450+ you can create a token provider that will return the token used by
451+ the ``HubInterface `` object::
469452
470- // src/Mercure/MyJwtProvider .php
453+ // src/Mercure/MyTokenProvider .php
471454 namespace App\Mercure;
472455
473- final class MyJwtProvider
456+ use Symfony\Component\Mercure\JWT\TokenProviderInterface;
457+
458+ final class MyTokenProvider implements TokenProviderInterface
474459 {
475- public function __invoke (): string
460+ public function getToken (): string
476461 {
477462 return 'the-JWT';
478463 }
@@ -489,7 +474,8 @@ Then, reference this service in the bundle configuration:
489474 hubs :
490475 default :
491476 url : https://mercure-hub.example.com/.well-known/mercure
492- jwt_provider : App\Mercure\MyJwtProvider
477+ jwt :
478+ provider : App\Mercure\MyTokenProvider
493479
494480 .. code-block :: xml
495481
@@ -499,8 +485,9 @@ Then, reference this service in the bundle configuration:
499485 <hub
500486 name =" default"
501487 url =" https://mercure-hub.example.com/.well-known/mercure"
502- jwt-provider =" App\Mercure\MyJwtProvider"
503- />
488+ >
489+ <jwt provider =" App\Mercure\MyTokenProvider" />
490+ </hub >
504491 </config >
505492
506493 .. code-block :: php
@@ -512,7 +499,9 @@ Then, reference this service in the bundle configuration:
512499 'hubs' => [
513500 'default' => [
514501 'url' => 'https://mercure-hub.example.com/.well-known/mercure',
515- 'jwt_provider' => MyJwtProvider::class,
502+ 'jwt' => [
503+ 'provider' => MyJwtProvider::class,
504+ ]
516505 ],
517506 ],
518507 ]);
@@ -573,29 +562,59 @@ its Mercure support.
573562Testing
574563--------
575564
576- During functional testing there is no need to send updates to Mercure. They will
577- be handled by a stub publisher::
565+ During unit testing there is not need to send updates to Mercure.
578566
579- // tests/Functional/Fixtures/PublisherStub.php
580- namespace App\Tests\Functional\Fixtures;
567+ You can instead make use of the `MockHub `::
581568
582- use Symfony\Component\Mercure\PublisherInterface;
569+ // tests/Functional/.php
570+ namespace App\Tests\Unit\Controller;
571+
572+ use App\Controller\MessageController;
573+ use Symfony\Component\Mercure\JWT\StaticTokenProvider;
574+ use Symfony\Component\Mercure\MockHub;
575+ use Symfony\Component\Mercure\HubInterface;
583576 use Symfony\Component\Mercure\Update;
584577
585- class PublisherStub implements PublisherInterface
578+ class MessageControllerTest extends TestCase
586579 {
587580 public function __invoke(Update $update): string
588581 {
589- return '';
582+ $hub = new MockHub('default', 'https://internal/.well-known/mercure', new StaticTokenProvider('foo'), function(Update $update): string {
583+ // $this->assertTrue($update->isPrivate());
584+
585+ return 'id';
586+ });
587+
588+ $controller = new MessageController($hub);
589+
590+ ...
591+ }
592+ }
593+
594+ During functional testing you can instead decorate the Hub::
595+
596+ // tests/Functional/Fixtures/HubStub.php
597+ namespace App\Tests\Functional\Fixtures;
598+
599+ use Symfony\Component\Mercure\HubInterface;
600+ use Symfony\Component\Mercure\Update;
601+
602+ class HubStub implements HubInterface
603+ {
604+ public function publish(Update $update): string
605+ {
606+ return 'id';
590607 }
608+
609+ // implement rest of HubInterface methods here
591610 }
592611
593- PublisherStub decorates the default publisher service so no updates are actually
594- sent. Here is the PublisherStub implementation::
612+ HubStub decorates the default hub service so no updates are actually
613+ sent. Here is the HubStub implementation::
595614
596615 # config/services_test.yaml
597- App\Tests\Functional\Fixtures\PublisherStub :
598- decorates: mercure.hub.default.publisher
616+ App\Tests\Functional\Fixtures\HubStub :
617+ decorates: mercure.hub.default
599618
600619
601620Debugging
0 commit comments