Skip to content

Commit 20cac53

Browse files
committed
update mercure documentation
1 parent 49cd53b commit 20cac53

File tree

1 file changed

+79
-60
lines changed

1 file changed

+79
-60
lines changed

mercure.rst

Lines changed: 79 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -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

466449
Instead 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.
573562
Testing
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

601620
Debugging

0 commit comments

Comments
 (0)