minor #40671 [Notifier] Mercure bridge: bump mercure dependency to 0.5 (azjezz, mtarld)

This PR was merged into the 5.3-dev branch.

Discussion
----------

[Notifier] Mercure bridge: bump mercure dependency to 0.5

| Q             | A
| ------------- | ---
| Branch?       | 5.x
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| License       | MIT
| Doc PR        | https://github.com/symfony/symfony-docs/pull/15179

Bump Mercure bridge's `symfony/mercure` dependency to 0.5 to deal with hubs instead of publishers.

---
To be able to use `HandlerRegistry::all` method, this PR needs https://github.com/symfony/mercure/pull/50 to be merged and released.

Commits
-------

498f96f1a8 Drop support of mercure:^0.4
d3306fdc92 add support for symfony/mercure:^0.5
This commit is contained in:
Robin Chalas 2021-04-06 12:24:06 +02:00
commit de143497ff
8 changed files with 108 additions and 152 deletions

View File

@ -142,7 +142,7 @@
"psr/http-client": "^1.0",
"psr/simple-cache": "^1.0",
"egulias/email-validator": "^2.1.10|^3.1",
"symfony/mercure-bundle": "^0.2",
"symfony/mercure-bundle": "^0.3",
"symfony/phpunit-bridge": "^5.2",
"symfony/security-acl": "~2.8|~3.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",

View File

@ -26,6 +26,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Bundle\FrameworkBundle\Routing\AnnotatedRouteControllerLoader;
use Symfony\Bundle\FrameworkBundle\Routing\RouteLoaderInterface;
use Symfony\Bundle\FullStack;
use Symfony\Bundle\MercureBundle\MercureBundle;
use Symfony\Component\Asset\PackageInterface;
use Symfony\Component\BrowserKit\AbstractBrowser;
use Symfony\Component\Cache\Adapter\AdapterInterface;
@ -44,8 +45,6 @@ use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@ -95,6 +94,7 @@ use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkTransportFactory;
use Symfony\Component\Mailer\Bridge\Sendgrid\Transport\SendgridTransportFactory;
use Symfony\Component\Mailer\Bridge\Sendinblue\Transport\SendinblueTransportFactory;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mercure\HubRegistry;
use Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\AmazonSqsTransportFactory;
use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpTransportFactory;
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\BeanstalkdTransportFactory;
@ -2408,7 +2408,7 @@ class FrameworkExtension extends Extension
if (ContainerBuilder::willBeAvailable('symfony/mercure-notifier', MercureTransportFactory::class, $parentPackages) && ContainerBuilder::willBeAvailable('symfony/mercure-bundle', MercureBundle::class, $parentPackages)) {
$container->getDefinition($classToServices[MercureTransportFactory::class])
->replaceArgument('$publisherLocator', new ServiceLocatorArgument(new TaggedIteratorArgument('mercure.publisher', null, null, true)));
->replaceArgument('$registry', new Reference(HubRegistry::class));
} elseif (ContainerBuilder::willBeAvailable('symfony/mercure-notifier', MercureTransportFactory::class, $parentPackages)) {
$container->removeDefinition($classToServices[MercureTransportFactory::class]);
}

View File

@ -11,20 +11,18 @@
namespace Symfony\Component\Notifier\Bridge\Mercure;
use Symfony\Component\Mercure\PublisherInterface;
use Symfony\Component\Mercure\Exception\InvalidArgumentException;
use Symfony\Component\Mercure\Exception\RuntimeException as MercureRuntimeException;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Notifier\Exception\InvalidArgumentException;
use Symfony\Component\Notifier\Exception\LogicException;
use Symfony\Component\Notifier\Exception\RuntimeException;
use Symfony\Component\Notifier\Exception\TransportException;
use Symfony\Component\Notifier\Exception\UnsupportedMessageTypeException;
use Symfony\Component\Notifier\Message\ChatMessage;
use Symfony\Component\Notifier\Message\MessageInterface;
use Symfony\Component\Notifier\Message\SentMessage;
use Symfony\Component\Notifier\Transport\AbstractTransport;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
/**
@ -32,21 +30,21 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
*/
final class MercureTransport extends AbstractTransport
{
private $publisher;
private $publisherId;
private $hub;
private $hubId;
private $topics;
/**
* @param string|string[]|null $topics
*/
public function __construct(PublisherInterface $publisher, string $publisherId, $topics = null, ?HttpClientInterface $client = null, ?EventDispatcherInterface $dispatcher = null)
public function __construct(HubInterface $hub, string $hubId, $topics = null, ?HttpClientInterface $client = null, ?EventDispatcherInterface $dispatcher = null)
{
if (null !== $topics && !\is_array($topics) && !\is_string($topics)) {
throw new \TypeError(sprintf('"%s()" expects parameter 3 to be an array of strings, a string or null, "%s" given.', __METHOD__, get_debug_type($topics)));
}
$this->publisher = $publisher;
$this->publisherId = $publisherId;
$this->hub = $hub;
$this->hubId = $hubId;
$this->topics = $topics ?? 'https://symfony.com/notifier';
parent::__construct($client, $dispatcher);
@ -54,7 +52,7 @@ final class MercureTransport extends AbstractTransport
public function __toString(): string
{
return sprintf('mercure://%s?%s', $this->publisherId, http_build_query(['topic' => $this->topics]));
return sprintf('mercure://%s?%s', $this->hubId, http_build_query(['topic' => $this->topics]));
}
public function supports(MessageInterface $message): bool
@ -87,18 +85,14 @@ final class MercureTransport extends AbstractTransport
]), $options->isPrivate(), $options->getId(), $options->getType(), $options->getRetry());
try {
$messageId = ($this->publisher)($update);
$messageId = $this->hub->publish($update);
$sentMessage = new SentMessage($message, (string) $this);
$sentMessage->setMessageId($messageId);
return $sentMessage;
} catch (HttpExceptionInterface $e) {
throw new TransportException('Unable to post the Mercure message: '.$e->getResponse()->getContent(false), $e->getResponse(), $e->getCode(), $e);
} catch (ExceptionInterface $e) {
} catch (MercureRuntimeException | InvalidArgumentException $e) {
throw new RuntimeException('Unable to post the Mercure message: '.$e->getMessage(), $e->getCode(), $e);
} catch (\InvalidArgumentException $e) {
throw new InvalidArgumentException('Unable to post the Mercure message: '.$e->getMessage(), $e->getCode(), $e);
}
}
}

View File

@ -11,30 +11,26 @@
namespace Symfony\Component\Notifier\Bridge\Mercure;
use Symfony\Bundle\MercureBundle\MercureBundle;
use Symfony\Component\Mercure\PublisherInterface;
use Symfony\Component\Notifier\Exception\LogicException;
use Symfony\Component\Mercure\Exception\InvalidArgumentException;
use Symfony\Component\Mercure\HubRegistry;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn;
use Symfony\Component\Notifier\Transport\TransportInterface;
use Symfony\Contracts\Service\ServiceProviderInterface;
/**
* @author Mathias Arlaud <mathias.arlaud@gmail.com>
*/
final class MercureTransportFactory extends AbstractTransportFactory
{
private $publisherLocator;
private $registry;
/**
* @param ServiceProviderInterface $publisherLocator A container that holds {@see PublisherInterface} instances
*/
public function __construct(ServiceProviderInterface $publisherLocator)
public function __construct(HubRegistry $registry)
{
parent::__construct();
$this->publisherLocator = $publisherLocator;
$this->registry = $registry;
}
/**
@ -46,18 +42,16 @@ final class MercureTransportFactory extends AbstractTransportFactory
throw new UnsupportedSchemeException($dsn, 'mercure', $this->getSupportedSchemes());
}
$publisherId = $dsn->getHost();
if (!$this->publisherLocator->has($publisherId)) {
if (!class_exists(MercureBundle::class) && !$this->publisherLocator->getProvidedServices()) {
throw new LogicException('No publishers found. Did you forget to install the MercureBundle? Try running "composer require symfony/mercure-bundle".');
}
throw new LogicException(sprintf('"%s" not found. Did you mean one of: %s?', $publisherId, implode(', ', array_keys($this->publisherLocator->getProvidedServices()))));
}
$hubId = $dsn->getHost();
$topic = $dsn->getOption('topic');
return new MercureTransport($this->publisherLocator->get($publisherId), $publisherId, $topic);
try {
$hub = $this->registry->getHub($hubId);
} catch (InvalidArgumentException $exception) {
throw new IncompleteDsnException(sprintf('Hub "%s" not found. Did you mean one of: "%s"?', $hubId, implode('", "', array_keys($this->registry->all()))));
}
return new MercureTransport($hub, $hubId, $topic);
}
protected function getSupportedSchemes(): array

View File

@ -7,11 +7,11 @@ DSN example
-----------
```
MERCURE_DSN=mercure://PUBLISHER_SERVICE_ID?topic=TOPIC
MERCURE_DSN=mercure://HUB_ID?topic=TOPIC
```
where:
- `PUBLISHER_SERVICE_ID` is the Mercure publisher service id
- `HUB_ID` is the Mercure hub id
- `TOPIC` is the topic IRI (optional, default: `https://symfony.com/notifier`. Could be either a single topic: `topic=https://foo` or multiple topics: `topic[]=/foo/1&topic[]=https://bar`)
Resources

View File

@ -11,15 +11,13 @@
namespace Symfony\Component\Notifier\Bridge\Mercure\Tests;
use LogicException;
use Symfony\Bridge\PhpUnit\ClassExistsMock;
use Symfony\Bundle\MercureBundle\MercureBundle;
use Symfony\Component\Mercure\PublisherInterface;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\HubRegistry;
use Symfony\Component\Notifier\Bridge\Mercure\MercureTransportFactory;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Test\TransportFactoryTestCase;
use Symfony\Component\Notifier\Transport\Dsn;
use Symfony\Component\Notifier\Transport\TransportFactoryInterface;
use Symfony\Contracts\Service\ServiceProviderInterface;
/**
* @author Mathias Arlaud <mathias.arlaud@gmail.com>
@ -28,73 +26,49 @@ final class MercureTransportFactoryTest extends TransportFactoryTestCase
{
public function createFactory(): TransportFactoryInterface
{
$publisherLocator = $this->createMock(ServiceProviderInterface::class);
$publisherLocator->method('has')->willReturn(true);
$publisherLocator->method('get')->willReturn($this->createMock(PublisherInterface::class));
$hub = $this->createMock(HubInterface::class);
$hubRegistry = new HubRegistry($hub, ['hubId' => $hub]);
return new MercureTransportFactory($publisherLocator);
return new MercureTransportFactory($hubRegistry);
}
public function supportsProvider(): iterable
{
yield [true, 'mercure://publisherId?topic=topic'];
yield [false, 'somethingElse://publisherId?topic=topic'];
yield [true, 'mercure://hubId?topic=topic'];
yield [false, 'somethingElse://hubId?topic=topic'];
}
public function createProvider(): iterable
{
yield [
'mercure://publisherId?topic=%2Ftopic%2F1',
'mercure://publisherId?topic=/topic/1',
'mercure://hubId?topic=%2Ftopic%2F1',
'mercure://hubId?topic=/topic/1',
];
yield [
'mercure://publisherId?topic%5B0%5D=%2Ftopic%2F1&topic%5B1%5D=%2Ftopic%2F2',
'mercure://publisherId?topic[]=/topic/1&topic[]=/topic/2',
'mercure://hubId?topic%5B0%5D=%2Ftopic%2F1&topic%5B1%5D=%2Ftopic%2F2',
'mercure://hubId?topic[]=/topic/1&topic[]=/topic/2',
];
yield [
'mercure://publisherId?topic=https%3A%2F%2Fsymfony.com%2Fnotifier',
'mercure://publisherId',
'mercure://hubId?topic=https%3A%2F%2Fsymfony.com%2Fnotifier',
'mercure://hubId',
];
}
public function unsupportedSchemeProvider(): iterable
{
yield ['somethingElse://publisherId?topic=topic'];
yield ['somethingElse://hubId?topic=topic'];
}
public function testCreateWithEmptyServiceProviderAndWithoutMercureBundleThrows()
public function testNotFoundHubThrows()
{
ClassExistsMock::register(MercureTransportFactory::class);
ClassExistsMock::withMockedClasses([MercureBundle::class => false]);
$hub = $this->createMock(HubInterface::class);
$hubRegistry = new HubRegistry($hub, ['hubId' => $hub, 'anotherHubId' => $hub]);
$factory = new MercureTransportFactory($hubRegistry);
$publisherLocator = $this->createMock(ServiceProviderInterface::class);
$publisherLocator->method('has')->willReturn(false);
$publisherLocator->method('getProvidedServices')->willReturn([]);
$factory = new MercureTransportFactory($publisherLocator);
$this->expectException(LogicException::class);
$this->expectExceptionMessage('No publishers found. Did you forget to install the MercureBundle? Try running "composer require symfony/mercure-bundle".');
try {
$factory->create(new Dsn('mercure://publisherId'));
} finally {
ClassExistsMock::withMockedClasses([MercureBundle::class => true]);
}
}
public function testNotFoundPublisherThrows()
{
$publisherLocator = $this->createMock(ServiceProviderInterface::class);
$publisherLocator->method('has')->willReturn(false);
$publisherLocator->method('getProvidedServices')->willReturn(['fooPublisher' => 'fooFqcn', 'barPublisher' => 'barFqcn']);
$factory = new MercureTransportFactory($publisherLocator);
$this->expectException(LogicException::class);
$this->expectExceptionMessage('"publisherId" not found. Did you mean one of: fooPublisher, barPublisher?');
$factory->create(new Dsn('mercure://publisherId'));
$this->expectException(IncompleteDsnException::class);
$this->expectExceptionMessage('Hub "wrongHubId" not found. Did you mean one of: "hubId", "anotherHubId"?');
$factory->create(new Dsn('mercure://wrongHubId'));
}
}

View File

@ -11,24 +11,23 @@
namespace Symfony\Component\Notifier\Bridge\Mercure\Tests;
use Symfony\Component\HttpClient\Exception\TransportException as HttpClientTransportException;
use Symfony\Component\Mercure\PublisherInterface;
use Symfony\Component\Mercure\Exception\InvalidArgumentException;
use Symfony\Component\Mercure\Exception\RuntimeException as MercureRuntimeException;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Jwt\StaticTokenProvider;
use Symfony\Component\Mercure\MockHub;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Notifier\Bridge\Mercure\MercureOptions;
use Symfony\Component\Notifier\Bridge\Mercure\MercureTransport;
use Symfony\Component\Notifier\Exception\InvalidArgumentException;
use Symfony\Component\Notifier\Exception\LogicException;
use Symfony\Component\Notifier\Exception\RuntimeException;
use Symfony\Component\Notifier\Exception\TransportException;
use Symfony\Component\Notifier\Message\ChatMessage;
use Symfony\Component\Notifier\Message\MessageInterface;
use Symfony\Component\Notifier\Message\MessageOptionsInterface;
use Symfony\Component\Notifier\Message\SmsMessage;
use Symfony\Component\Notifier\Test\TransportTestCase;
use Symfony\Component\Notifier\Transport\TransportInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use TypeError;
/**
@ -36,18 +35,18 @@ use TypeError;
*/
final class MercureTransportTest extends TransportTestCase
{
public function createTransport(?HttpClientInterface $client = null, ?PublisherInterface $publisher = null, string $publisherId = 'publisherId', $topics = null): TransportInterface
public function createTransport(?HttpClientInterface $client = null, ?HubInterface $hub = null, string $hubId = 'hubId', $topics = null): TransportInterface
{
$publisher = $publisher ?? $this->createMock(PublisherInterface::class);
$hub = $hub ?? $this->createMock(HubInterface::class);
return new MercureTransport($publisher, $publisherId, $topics);
return new MercureTransport($hub, $hubId, $topics);
}
public function toStringProvider(): iterable
{
yield ['mercure://publisherId?topic=https%3A%2F%2Fsymfony.com%2Fnotifier', $this->createTransport()];
yield ['mercure://customPublisherId?topic=%2Ftopic', $this->createTransport(null, null, 'customPublisherId', '/topic')];
yield ['mercure://customPublisherId?topic%5B0%5D=%2Ftopic%2F1&topic%5B1%5D%5B0%5D=%2Ftopic%2F2', $this->createTransport(null, null, 'customPublisherId', ['/topic/1', ['/topic/2']])];
yield ['mercure://hubId?topic=https%3A%2F%2Fsymfony.com%2Fnotifier', $this->createTransport()];
yield ['mercure://customHubId?topic=%2Ftopic', $this->createTransport(null, null, 'customHubId', '/topic')];
yield ['mercure://customHubId?topic%5B0%5D=%2Ftopic%2F1&topic%5B1%5D%5B0%5D=%2Ftopic%2F2', $this->createTransport(null, null, 'customHubId', ['/topic/1', ['/topic/2']])];
}
public function supportedMessagesProvider(): iterable
@ -90,87 +89,82 @@ final class MercureTransportTest extends TransportTestCase
public function testSendWithTransportFailureThrows()
{
$publisher = $this->createMock(PublisherInterface::class);
$publisher->method('__invoke')->willThrowException(new HttpClientTransportException('Cannot connect to mercure'));
$hub = new MockHub('https://foo.com/.well-known/mercure', new StaticTokenProvider('foo'), static function (): void {
throw new MercureRuntimeException('Cannot connect to mercure');
});
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Unable to post the Mercure message: Cannot connect to mercure');
$this->createTransport(null, $publisher)->send(new ChatMessage('subject'));
}
public function testSendWithWrongResponseThrows()
{
$response = $this->createMock(ResponseInterface::class);
$response->method('getContent')->willReturn('Service Unavailable');
$httpException = $this->createMock(ServerExceptionInterface::class);
$httpException->method('getResponse')->willReturn($response);
$publisher = $this->createMock(PublisherInterface::class);
$publisher->method('__invoke')->willThrowException($httpException);
$this->expectException(TransportException::class);
$this->expectExceptionMessage('Unable to post the Mercure message: Service Unavailable');
$this->createTransport(null, $publisher)->send(new ChatMessage('subject'));
$this->createTransport(null, $hub)->send(new ChatMessage('subject'));
}
public function testSendWithWrongTokenThrows()
{
$publisher = $this->createMock(PublisherInterface::class);
$publisher->method('__invoke')->willThrowException(new \InvalidArgumentException('The provided JWT is not valid'));
$hub = new MockHub('https://foo.com/.well-known/mercure', new StaticTokenProvider('foo'), static function (): void {
throw new InvalidArgumentException('The provided JWT is not valid');
});
$this->expectException(InvalidArgumentException::class);
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Unable to post the Mercure message: The provided JWT is not valid');
$this->createTransport(null, $publisher)->send(new ChatMessage('subject'));
$this->createTransport(null, $hub)->send(new ChatMessage('subject'));
}
public function testSendWithMercureOptions()
{
$publisher = $this->createMock(PublisherInterface::class);
$publisher
->expects($this->once())
->method('__invoke')
->with(new Update(['/topic/1', '/topic/2'], '{"@context":"https:\/\/www.w3.org\/ns\/activitystreams","type":"Announce","summary":"subject"}', true, 'id', 'type', 1))
;
$hub = new MockHub('https://foo.com/.well-known/mercure', new StaticTokenProvider('foo'), function (Update $update): string {
$this->assertSame(['/topic/1', '/topic/2'], $update->getTopics());
$this->assertSame('{"@context":"https:\/\/www.w3.org\/ns\/activitystreams","type":"Announce","summary":"subject"}', $update->getData());
$this->assertSame('id', $update->getId());
$this->assertSame('type', $update->getType());
$this->assertSame(1, $update->getRetry());
$this->assertTrue($update->isPrivate());
$this->createTransport(null, $publisher)->send(new ChatMessage('subject', new MercureOptions(['/topic/1', '/topic/2'], true, 'id', 'type', 1)));
return 'id';
});
$this->createTransport(null, $hub)->send(new ChatMessage('subject', new MercureOptions(['/topic/1', '/topic/2'], true, 'id', 'type', 1)));
}
public function testSendWithMercureOptionsButWithoutOptionTopic()
{
$publisher = $this->createMock(PublisherInterface::class);
$publisher
->expects($this->once())
->method('__invoke')
->with(new Update(['https://symfony.com/notifier'], '{"@context":"https:\/\/www.w3.org\/ns\/activitystreams","type":"Announce","summary":"subject"}', true, 'id', 'type', 1))
;
$hub = new MockHub('https://foo.com/.well-known/mercure', new StaticTokenProvider('foo'), function (Update $update): string {
$this->assertSame(['https://symfony.com/notifier'], $update->getTopics());
$this->assertSame('{"@context":"https:\/\/www.w3.org\/ns\/activitystreams","type":"Announce","summary":"subject"}', $update->getData());
$this->assertSame('id', $update->getId());
$this->assertSame('type', $update->getType());
$this->assertSame(1, $update->getRetry());
$this->assertTrue($update->isPrivate());
$this->createTransport(null, $publisher)->send(new ChatMessage('subject', new MercureOptions(null, true, 'id', 'type', 1)));
return 'id';
});
$this->createTransport(null, $hub)->send(new ChatMessage('subject', new MercureOptions(null, true, 'id', 'type', 1)));
}
public function testSendWithoutMercureOptions()
{
$publisher = $this->createMock(PublisherInterface::class);
$publisher
->expects($this->once())
->method('__invoke')
->with(new Update(['https://symfony.com/notifier'], '{"@context":"https:\/\/www.w3.org\/ns\/activitystreams","type":"Announce","summary":"subject"}'))
;
$hub = new MockHub('https://foo.com/.well-known/mercure', new StaticTokenProvider('foo'), function (Update $update): string {
$this->assertSame(['https://symfony.com/notifier'], $update->getTopics());
$this->assertSame('{"@context":"https:\/\/www.w3.org\/ns\/activitystreams","type":"Announce","summary":"subject"}', $update->getData());
$this->assertFalse($update->isPrivate());
$this->createTransport(null, $publisher)->send(new ChatMessage('subject'));
return 'id';
});
$this->createTransport(null, $hub)->send(new ChatMessage('subject'));
}
public function testSendSuccessfully()
{
$messageId = 'urn:uuid:a7045be0-a75d-4d40-8bd2-29fa4e5dd10b';
$publisher = $this->createMock(PublisherInterface::class);
$publisher->method('__invoke')->willReturn($messageId);
$hub = new MockHub('https://foo.com/.well-known/mercure', new StaticTokenProvider('foo'), function (Update $update) use ($messageId): string {
return $messageId;
});
$sentMessage = $this->createTransport(null, $publisher)->send(new ChatMessage('subject'));
$sentMessage = $this->createTransport(null, $hub)->send(new ChatMessage('subject'));
$this->assertSame($messageId, $sentMessage->getMessageId());
}
}

View File

@ -18,7 +18,7 @@
"require": {
"php": ">=7.2.5",
"ext-json": "*",
"symfony/mercure": "^0.4",
"symfony/mercure": "^0.5.2",
"symfony/notifier": "^5.3",
"symfony/service-contracts": "^1.10|^2"
},