diff --git a/benchmarks/QueryBench.php b/benchmarks/QueryBench.php index a66f38a0ef..f3262f8251 100644 --- a/benchmarks/QueryBench.php +++ b/benchmarks/QueryBench.php @@ -20,10 +20,10 @@ public function setUp(): void { parent::setUp(); - $configRepository = $this->app->make(ConfigRepository::class); - assert($configRepository instanceof ConfigRepository); + $config = $this->app->make(ConfigRepository::class); + assert($config instanceof ConfigRepository); - $routeName = $configRepository->get('lighthouse.route.name'); + $routeName = $config->get('lighthouse.route.name'); $this->graphQLEndpoint = route($routeName); } diff --git a/phpstan.neon b/phpstan.neon index 12812a6350..cc8ced9a01 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -86,9 +86,8 @@ parameters: message: '#Call to method version\(\) on an unknown class Laravel\\Lumen\\Application.#' - path: src/Subscriptions/SubscriptionRouter.php messages: - - '#Parameter \$router of method Nuwave\\Lighthouse\\Subscriptions\\SubscriptionRouter::pusher\(\) has invalid type Laravel\\Lumen\\Routing\\Router\.#' + - '#Parameter \$router of method Nuwave\\Lighthouse\\Subscriptions\\SubscriptionRouter::.+\(\) has invalid type Laravel\\Lumen\\Routing\\Router\.#' - '#Call to method post\(\) on an unknown class Laravel\\Lumen\\Routing\\Router\.#' - - '#Parameter \$router of method Nuwave\\Lighthouse\\Subscriptions\\SubscriptionRouter::echoRoutes\(\) has invalid type Laravel\\Lumen\\Routing\\Router\.#' - path: src/Http/routes.php messages: - '#PHPDoc tag @var for variable \$router contains unknown class Laravel\\Lumen\\Routing\\Router\.#' diff --git a/src/Subscriptions/BroadcastManager.php b/src/Subscriptions/BroadcastDriverManager.php similarity index 89% rename from src/Subscriptions/BroadcastManager.php rename to src/Subscriptions/BroadcastDriverManager.php index 1bc9fb0bfd..12eb8242ae 100644 --- a/src/Subscriptions/BroadcastManager.php +++ b/src/Subscriptions/BroadcastDriverManager.php @@ -17,7 +17,7 @@ * @method \Symfony\Component\HttpFoundation\Response authorized(\Illuminate\Http\Request $request) * @method \Symfony\Component\HttpFoundation\Response unauthorized(\Illuminate\Http\Request $request) */ -class BroadcastManager extends DriverManager +class BroadcastDriverManager extends DriverManager { protected function configKey(): string { @@ -38,11 +38,9 @@ protected function interface(): string protected function createPusherDriver(array $config): PusherBroadcaster { $connection = $config['connection'] ?? 'pusher'; - $driverConfig = config("broadcasting.connections.{$connection}"); - if (empty($driverConfig) || $driverConfig['driver'] !== 'pusher') { - throw new \RuntimeException("Could not initialize Pusher broadcast driver for connection: {$connection}."); - } + $driverConfig = config("broadcasting.connections.{$connection}") + ?? throw new \RuntimeException("Missing connection {$connection} from config/broadcasting.php."); $pusher = new Pusher( $driverConfig['key'], diff --git a/src/Subscriptions/SubscriptionBroadcaster.php b/src/Subscriptions/SubscriptionBroadcaster.php index b88260b26e..22a855218d 100644 --- a/src/Subscriptions/SubscriptionBroadcaster.php +++ b/src/Subscriptions/SubscriptionBroadcaster.php @@ -19,7 +19,7 @@ public function __construct( protected AuthorizesSubscriptions $subscriptionAuthorizer, protected StoresSubscriptions $subscriptionStorage, protected SubscriptionIterator $subscriptionIterator, - protected BroadcastManager $broadcastManager, + protected BroadcastDriverManager $broadcastDriverManager, protected BusDispatcher $busDispatcher, ) {} @@ -50,7 +50,7 @@ function (Subscriber $subscriber) use ($root): void { $subscriber->variables, $subscriber, ); - $this->broadcastManager->broadcast($subscriber, $result); + $this->broadcastDriverManager->broadcast($subscriber, $result); }, ); } @@ -58,7 +58,7 @@ function (Subscriber $subscriber) use ($root): void { public function authorize(Request $request): Response { return $this->subscriptionAuthorizer->authorize($request) - ? $this->broadcastManager->authorized($request) - : $this->broadcastManager->unauthorized($request); + ? $this->broadcastDriverManager->authorized($request) + : $this->broadcastDriverManager->unauthorized($request); } } diff --git a/src/Subscriptions/SubscriptionController.php b/src/Subscriptions/SubscriptionController.php index d4d0ae0bc6..ebd6716ae3 100644 --- a/src/Subscriptions/SubscriptionController.php +++ b/src/Subscriptions/SubscriptionController.php @@ -13,8 +13,8 @@ public function authorize(Request $request, BroadcastsSubscriptions $broadcaster return $broadcaster->authorize($request); } - public function webhook(Request $request, BroadcastManager $broadcastManager): Response + public function webhook(Request $request, BroadcastDriverManager $broadcastDriverManager): Response { - return $broadcastManager->hook($request); + return $broadcastDriverManager->hook($request); } } diff --git a/src/Subscriptions/SubscriptionRouter.php b/src/Subscriptions/SubscriptionRouter.php index e087c90e70..513e2e59a1 100644 --- a/src/Subscriptions/SubscriptionRouter.php +++ b/src/Subscriptions/SubscriptionRouter.php @@ -7,7 +7,7 @@ class SubscriptionRouter { - /** Register the routes for pusher based subscriptions. */ + /** Register the routes for Pusher based subscriptions. */ public function pusher(Registrar|Router $router): void { $router->post('graphql/subscriptions/auth', [ @@ -21,6 +21,16 @@ public function pusher(Registrar|Router $router): void ]); } + /** Register the routes for Laravel Reverb based subscriptions. */ + public function reverb(Registrar|Router $router): void + { + $router->post('graphql/subscriptions/auth', [ + 'as' => 'lighthouse.subscriptions.auth', + 'uses' => SubscriptionController::class . '@authorize', + ]); + } + + /** Register the routes for Laravel Echo based subscriptions. */ public function echoRoutes(Registrar|Router $router): void { $router->post('graphql/subscriptions/auth', [ diff --git a/src/Subscriptions/SubscriptionServiceProvider.php b/src/Subscriptions/SubscriptionServiceProvider.php index 0ac54d3ea2..44cb89d622 100644 --- a/src/Subscriptions/SubscriptionServiceProvider.php +++ b/src/Subscriptions/SubscriptionServiceProvider.php @@ -26,7 +26,7 @@ class SubscriptionServiceProvider extends ServiceProvider { public function register(): void { - $this->app->singleton(BroadcastManager::class); + $this->app->singleton(BroadcastDriverManager::class); $this->app->singleton(SubscriptionRegistry::class); $this->app->singleton(StoresSubscriptions::class, static function (Container $app): StoresSubscriptions { $configRepository = $app->make(ConfigRepository::class); diff --git a/src/Testing/MakesGraphQLRequests.php b/src/Testing/MakesGraphQLRequests.php index 7e02c1dd3d..18531097d2 100644 --- a/src/Testing/MakesGraphQLRequests.php +++ b/src/Testing/MakesGraphQLRequests.php @@ -8,8 +8,8 @@ use Illuminate\Support\Arr; use Illuminate\Testing\TestResponse; use Nuwave\Lighthouse\Http\Responses\MemoryStream; +use Nuwave\Lighthouse\Subscriptions\BroadcastDriverManager; use Nuwave\Lighthouse\Subscriptions\Broadcasters\LogBroadcaster; -use Nuwave\Lighthouse\Subscriptions\BroadcastManager; use Nuwave\Lighthouse\Subscriptions\Contracts\Broadcaster; use Nuwave\Lighthouse\Support\Contracts\CanStreamResponse; use PHPUnit\Framework\Assert; @@ -246,11 +246,11 @@ protected function setUpSubscriptionEnvironment(): void $config->get('lighthouse.subscriptions.broadcasters.log'), )); - $broadcastManager = $app->make(BroadcastManager::class); - assert($broadcastManager instanceof BroadcastManager); + $broadcastDriverManager = $app->make(BroadcastDriverManager::class); + assert($broadcastDriverManager instanceof BroadcastDriverManager); // adding a custom driver which is a spied version of log driver - $broadcastManager->extend('mock', fn () => $this->spy(LogBroadcaster::class)->makePartial()); + $broadcastDriverManager->extend('mock', fn () => $this->spy(LogBroadcaster::class)->makePartial()); // set the custom driver as the default driver $config->set('lighthouse.subscriptions.broadcaster', 'mock'); diff --git a/src/Testing/MakesGraphQLRequestsLumen.php b/src/Testing/MakesGraphQLRequestsLumen.php index 3f25a48c70..ea73d6e7c2 100644 --- a/src/Testing/MakesGraphQLRequestsLumen.php +++ b/src/Testing/MakesGraphQLRequestsLumen.php @@ -8,8 +8,8 @@ use Illuminate\Support\Arr; use Illuminate\Testing\TestResponse; use Nuwave\Lighthouse\Http\Responses\MemoryStream; +use Nuwave\Lighthouse\Subscriptions\BroadcastDriverManager; use Nuwave\Lighthouse\Subscriptions\Broadcasters\LogBroadcaster; -use Nuwave\Lighthouse\Subscriptions\BroadcastManager; use Nuwave\Lighthouse\Subscriptions\Contracts\Broadcaster; use Nuwave\Lighthouse\Support\Contracts\CanStreamResponse; use PHPUnit\Framework\Assert; @@ -265,11 +265,11 @@ protected function setUpSubscriptionEnvironment(): void $config->get('lighthouse.subscriptions.broadcasters.log'), )); - $broadcastManager = $app->make(BroadcastManager::class); - assert($broadcastManager instanceof BroadcastManager); + $broadcastDriverManager = $app->make(BroadcastDriverManager::class); + assert($broadcastDriverManager instanceof BroadcastDriverManager); // adding a custom driver which is a spied version of log driver - $broadcastManager->extend('mock', fn () => $this->spy(LogBroadcaster::class)->makePartial()); + $broadcastDriverManager->extend('mock', fn () => $this->spy(LogBroadcaster::class)->makePartial()); // set the custom driver as the default driver $config->set('lighthouse.subscriptions.broadcaster', 'mock'); diff --git a/src/Testing/TestResponseMixin.php b/src/Testing/TestResponseMixin.php index ab3ce05b02..dc086a668e 100644 --- a/src/Testing/TestResponseMixin.php +++ b/src/Testing/TestResponseMixin.php @@ -8,15 +8,13 @@ use Illuminate\Testing\TestResponse; use Mockery\LegacyMockInterface; use Mockery\MockInterface; -use Nuwave\Lighthouse\Subscriptions\BroadcastManager; +use Nuwave\Lighthouse\Subscriptions\BroadcastDriverManager; use Nuwave\Lighthouse\Subscriptions\Contracts\Broadcaster; use Nuwave\Lighthouse\Subscriptions\Subscriber; use PHPUnit\Framework\Assert; use PHPUnit\Framework\TestCase; -/** - * @mixin \Illuminate\Testing\TestResponse - */ +/** @mixin \Illuminate\Testing\TestResponse */ class TestResponseMixin { public function assertGraphQLValidationError(): \Closure @@ -155,12 +153,13 @@ public function assertGraphQLSubscriptionNotAuthorized(): \Closure public function graphQLSubscriptionMock(): \Closure { return function (): MockInterface { - $broadcastManager = Container::getInstance()->make(BroadcastManager::class); - assert($broadcastManager instanceof BroadcastManager); - $mock = $broadcastManager->driver(); - assert($mock instanceof Broadcaster && $mock instanceof MockInterface); + $broadcastDriverManager = Container::getInstance()->make(BroadcastDriverManager::class); + assert($broadcastDriverManager instanceof BroadcastDriverManager); - return $mock; + $broadcastDriver = $broadcastDriverManager->driver(); + assert($broadcastDriver instanceof Broadcaster && $broadcastDriver instanceof MockInterface); + + return $broadcastDriver; }; } diff --git a/src/Testing/TestsSubscriptions.php b/src/Testing/TestsSubscriptions.php index 97c5ed02e6..320cf2378e 100644 --- a/src/Testing/TestsSubscriptions.php +++ b/src/Testing/TestsSubscriptions.php @@ -4,13 +4,11 @@ use Illuminate\Container\Container; use Illuminate\Contracts\Config\Repository as ConfigRepository; +use Nuwave\Lighthouse\Subscriptions\BroadcastDriverManager; use Nuwave\Lighthouse\Subscriptions\Broadcasters\LogBroadcaster; -use Nuwave\Lighthouse\Subscriptions\BroadcastManager; use Nuwave\Lighthouse\Subscriptions\Contracts\Broadcaster; -/** - * Sets up the environment for testing subscriptions. - */ +/** Sets up the environment for testing subscriptions. */ trait TestsSubscriptions { protected function setUpTestsSubscriptions(): void @@ -27,11 +25,11 @@ protected function setUpTestsSubscriptions(): void $config->get('lighthouse.subscriptions.broadcasters.log'), )); - $broadcastManager = $app->make(BroadcastManager::class); - assert($broadcastManager instanceof BroadcastManager); + $broadcastDriverManager = $app->make(BroadcastDriverManager::class); + assert($broadcastDriverManager instanceof BroadcastDriverManager); // adding a custom driver which is a spied version of log driver - $broadcastManager->extend('mock', fn () => $this->spy(LogBroadcaster::class)->makePartial()); + $broadcastDriverManager->extend('mock', fn () => $this->spy(LogBroadcaster::class)->makePartial()); // set the custom driver as the default driver $config->set('lighthouse.subscriptions.broadcaster', 'mock'); diff --git a/src/lighthouse.php b/src/lighthouse.php index b0dd26ccd1..fdf19b54b4 100644 --- a/src/lighthouse.php +++ b/src/lighthouse.php @@ -435,16 +435,21 @@ 'log' => [ 'driver' => 'log', ], - 'pusher' => [ - 'driver' => 'pusher', - 'routes' => Nuwave\Lighthouse\Subscriptions\SubscriptionRouter::class . '@pusher', - 'connection' => 'pusher', - ], 'echo' => [ 'driver' => 'echo', 'connection' => env('LIGHTHOUSE_SUBSCRIPTION_REDIS_CONNECTION', 'default'), 'routes' => Nuwave\Lighthouse\Subscriptions\SubscriptionRouter::class . '@echoRoutes', ], + 'pusher' => [ + 'driver' => 'pusher', + 'connection' => 'pusher', + 'routes' => Nuwave\Lighthouse\Subscriptions\SubscriptionRouter::class . '@pusher', + ], + 'reverb' => [ + 'driver' => 'pusher', + 'connection' => 'reverb', + 'routes' => Nuwave\Lighthouse\Subscriptions\SubscriptionRouter::class . '@reverb', + ], ], /* diff --git a/tests/Integration/Subscriptions/SubscriptionTest.php b/tests/Integration/Subscriptions/SubscriptionTest.php index 6471fe1fd4..11cfef7c98 100644 --- a/tests/Integration/Subscriptions/SubscriptionTest.php +++ b/tests/Integration/Subscriptions/SubscriptionTest.php @@ -8,8 +8,8 @@ use Illuminate\Support\Arr; use Illuminate\Testing\TestResponse; use Mockery\MockInterface; +use Nuwave\Lighthouse\Subscriptions\BroadcastDriverManager; use Nuwave\Lighthouse\Subscriptions\Broadcasters\LogBroadcaster; -use Nuwave\Lighthouse\Subscriptions\BroadcastManager; use Nuwave\Lighthouse\Subscriptions\Storage\CacheStorageManager; use Nuwave\Lighthouse\Subscriptions\Subscriber; use Nuwave\Lighthouse\Testing\TestsSubscriptions; @@ -118,14 +118,14 @@ public function testBroadcastSubscriptions(): void title } } - '); + ')->assertGraphQLErrorFree(); - $broadcastManager = $this->app->make(BroadcastManager::class); + $broadcastDriverManager = $this->app->make(BroadcastDriverManager::class); - $log = $broadcastManager->driver(); - assert($log instanceof LogBroadcaster); + $logDriver = $broadcastDriverManager->driver(); + assert($logDriver instanceof LogBroadcaster); - $broadcasts = $log->broadcasts(); + $broadcasts = $logDriver->broadcasts(); $this->assertNotNull($broadcasts); /** @var array $broadcasts */ @@ -144,10 +144,10 @@ public function testWithFieldAlias(): void title } } - '); + ')->assertGraphQLErrorFree(); - /** @var CacheStorageManager $cache */ $cache = $this->app->make(CacheStorageManager::class); + assert($cache instanceof CacheStorageManager); $subscriber = $cache ->subscribersByTopic('ON_POST_CREATED') @@ -169,18 +169,15 @@ public function testWithFieldAlias(): void public function testWithoutExcludeEmpty(): void { $config = $this->app->make(ConfigRepository::class); - $config->set('lighthouse.subscriptions.exclude_empty', false); $this->subscribe(); - $response = $this->graphQL(/** @lang GraphQL */ ' - query foo { + $this->graphQL(/** @lang GraphQL */ ' + { foo } - '); - - $response->assertExactJson([ + ')->assertExactJson([ 'data' => [ 'foo' => '42', ], @@ -199,13 +196,11 @@ public function testWithExcludeEmpty(): void $this->subscribe(); - $response = $this->graphQL(/** @lang GraphQL */ ' - query foo { + $this->graphQL(/** @lang GraphQL */ ' + { foo } - '); - - $response->assertExactJson([ + ')->assertExactJson([ 'data' => [ 'foo' => '42', ], @@ -221,7 +216,7 @@ public function testWithGuard(): void body } } - '); + ')->assertGraphQLErrorFree(); $authFactory = $this->app->make(AuthFactory::class); $sessionGuard = $authFactory->guard(); @@ -234,10 +229,11 @@ public function testWithGuard(): void title } } - '); + ')->assertGraphQLErrorFree(); + + $broadcastDriverManager = $this->app->make(BroadcastDriverManager::class); - $broadcastManager = $this->app->make(BroadcastManager::class); - $log = $broadcastManager->driver(); + $log = $broadcastDriverManager->driver(); assert($log instanceof LogBroadcaster); $broadcasts = $log->broadcasts(); @@ -281,7 +277,7 @@ public function testGraphQLBroadcastedEvents(): void title } } - '); + ')->assertGraphQLErrorFree(); $response->assertGraphQLBroadcasted([ ['title' => 'foo'], @@ -298,7 +294,7 @@ public function testGraphQLBroadcastedEventsTwice(): void title } } - '); + ')->assertGraphQLErrorFree(); $this->graphQL(/** @lang GraphQL */ ' mutation { @@ -306,7 +302,7 @@ public function testGraphQLBroadcastedEventsTwice(): void title } } - '); + ')->assertGraphQLErrorFree(); $response->assertGraphQLBroadcasted([ ['title' => 'foo'], diff --git a/tests/Unit/Subscriptions/BroadcastManagerTest.php b/tests/Unit/Subscriptions/BroadcastDriverManagerTest.php similarity index 71% rename from tests/Unit/Subscriptions/BroadcastManagerTest.php rename to tests/Unit/Subscriptions/BroadcastDriverManagerTest.php index 5e21db5449..ce916e4ba3 100644 --- a/tests/Unit/Subscriptions/BroadcastManagerTest.php +++ b/tests/Unit/Subscriptions/BroadcastDriverManagerTest.php @@ -4,34 +4,34 @@ use Illuminate\Http\Request; use Nuwave\Lighthouse\Exceptions\InvalidDriverException; +use Nuwave\Lighthouse\Subscriptions\BroadcastDriverManager; use Nuwave\Lighthouse\Subscriptions\Broadcasters\LogBroadcaster; use Nuwave\Lighthouse\Subscriptions\Broadcasters\PusherBroadcaster; -use Nuwave\Lighthouse\Subscriptions\BroadcastManager; use Nuwave\Lighthouse\Subscriptions\Contracts\Broadcaster; use Nuwave\Lighthouse\Subscriptions\Subscriber; use Symfony\Component\HttpFoundation\Response; use Tests\EnablesSubscriptionServiceProvider; use Tests\TestCase; -final class BroadcastManagerTest extends TestCase +final class BroadcastDriverManagerTest extends TestCase { use EnablesSubscriptionServiceProvider; - protected BroadcastManager $broadcastManager; + protected BroadcastDriverManager $broadcastDriverManager; protected function setUp(): void { parent::setUp(); - $this->broadcastManager = $this->app->make(BroadcastManager::class); + $this->broadcastDriverManager = $this->app->make(BroadcastDriverManager::class); } public function testResolveDrivers(): void { - $pusherDriver = $this->broadcastManager->driver('pusher'); + $pusherDriver = $this->broadcastDriverManager->driver('pusher'); $this->assertInstanceOf(PusherBroadcaster::class, $pusherDriver); - $logDriver = $this->broadcastManager->driver('log'); + $logDriver = $this->broadcastDriverManager->driver('log'); $this->assertInstanceOf(LogBroadcaster::class, $logDriver); } @@ -58,13 +58,13 @@ public function hook(Request $request): Response public function broadcast(Subscriber $subscriber, mixed $data): void {} }; - $this->broadcastManager->extend('foo', static function ($app, array $config) use (&$broadcasterConfig, $broadcaster): Broadcaster { + $this->broadcastDriverManager->extend('foo', static function ($app, array $config) use (&$broadcasterConfig, $broadcaster): Broadcaster { $broadcasterConfig = $config; return $broadcaster; }); - $resolvedBroadcaster = $this->broadcastManager->driver('foo'); + $resolvedBroadcaster = $this->broadcastDriverManager->driver('foo'); assert($resolvedBroadcaster instanceof Broadcaster); $this->assertSame(['driver' => 'foo'], $broadcasterConfig); @@ -73,10 +73,10 @@ public function broadcast(Subscriber $subscriber, mixed $data): void {} public function testThrowsIfDriverDoesNotImplementInterface(): void { - $this->broadcastManager->extend('foo', static fn (): object => new class() {}); + $this->broadcastDriverManager->extend('foo', static fn (): object => new class() {}); $this->expectException(InvalidDriverException::class); - $this->broadcastManager->driver('foo'); + $this->broadcastDriverManager->driver('foo'); } } diff --git a/tests/Unit/Subscriptions/Broadcasters/PusherBroadcasterTest.php b/tests/Unit/Subscriptions/Broadcasters/PusherBroadcasterTest.php index e2d36063ef..87647b6c8e 100644 --- a/tests/Unit/Subscriptions/Broadcasters/PusherBroadcasterTest.php +++ b/tests/Unit/Subscriptions/Broadcasters/PusherBroadcasterTest.php @@ -3,8 +3,8 @@ namespace Tests\Unit\Subscriptions\Broadcasters; use Illuminate\Config\Repository as ConfigRepository; +use Nuwave\Lighthouse\Subscriptions\BroadcastDriverManager; use Nuwave\Lighthouse\Subscriptions\Broadcasters\PusherBroadcaster; -use Nuwave\Lighthouse\Subscriptions\BroadcastManager; use Nuwave\Lighthouse\Subscriptions\Subscriber; use Psr\Log\LoggerInterface; use Tests\EnablesSubscriptionServiceProvider; @@ -56,8 +56,9 @@ public function testPusherNeverUsesLoggerInterface(): void /** @param \Nuwave\Lighthouse\Subscriptions\Subscriber&\PHPUnit\Framework\MockObject\MockObject $subscriber */ private function broadcast(object $subscriber): void { - $broadcastManager = $this->app->make(BroadcastManager::class); - $pusherBroadcaster = $broadcastManager->driver('pusher'); + $broadcastDriverManager = $this->app->make(BroadcastDriverManager::class); + + $pusherBroadcaster = $broadcastDriverManager->driver('pusher'); assert($pusherBroadcaster instanceof PusherBroadcaster); $pusherBroadcaster->broadcast($subscriber, 'foo');