From b6c035c912122bb7eb0cbb56adffe4a8121b2139 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 2 Apr 2026 15:28:33 +0200 Subject: [PATCH] Improve comments --- .../BroadcastingConfigBootstrapper.php | 15 ++++++--- src/Overrides/TenancyBroadcastManager.php | 31 +++++++++---------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/Bootstrappers/BroadcastingConfigBootstrapper.php b/src/Bootstrappers/BroadcastingConfigBootstrapper.php index df00beda..7bf1ab30 100644 --- a/src/Bootstrappers/BroadcastingConfigBootstrapper.php +++ b/src/Bootstrappers/BroadcastingConfigBootstrapper.php @@ -66,8 +66,9 @@ class BroadcastingConfigBootstrapper implements TenancyBootstrapper $this->setConfig($tenant); - // Make BroadcastManager resolve to a custom BroadcastManager which makes the broadcasters use the tenant credentials. - // TenantBroadcastManager also inherits the custom drivers registered in the original BroadcastManager, so that they can be used in tenant context as well. + // Make BroadcastManager resolve to TenancyBroadcastManager which always re-resolves the used broadcasters (so that + // the broadcasting credentials are always up-to-date at the point of broadcasting) and gives the channels of + // the broadcaster from the central context to the newly resolved broadcasters in tenant context. $this->app->extend(BroadcastManager::class, function (BroadcastManager $broadcastManager) { $originalCustomCreators = invade($broadcastManager)->customCreators; $tenantBroadcastManager = new TenancyBroadcastManager($this->app); @@ -79,13 +80,17 @@ class BroadcastingConfigBootstrapper implements TenancyBootstrapper return $tenantBroadcastManager; }); - // Make the Broadcaster singleton resolve to the broadcaster of the TenantBroadcastManager so that it uses the tenant credentials + // Swap currently bound Broadcaster instance for one that's resolved through the tenant broadcast manager. + // Note that changing tenant's credentials in tenant context doesn't update them in the bound Broadcaster instance. + // If you need to e.g. send a notification in response to changing tenant's broadcasting credentials, + // it's recommended to use the broadcast() helper which always uses fresh broadcasters with the current credentials. $this->app->extend(Broadcaster::class, function (Broadcaster $broadcaster) { return $this->app->make(BroadcastManager::class)->connection(); }); - // Clear the resolved Broadcast facade instance so that it gets re-resolved as the tenant broadcast manager - // when used (e.g. in BroadcastController::authenticate) + // Clear the resolved Broadcast facade's Illuminate\Contracts\Broadcasting\Factory instance + // so that it gets re-resolved as the tenant broadcast manager when used (e.g. the + // Broadcast::auth() call in BroadcastController::authenticate). Broadcast::clearResolvedInstance(BroadcastingFactory::class); } diff --git a/src/Overrides/TenancyBroadcastManager.php b/src/Overrides/TenancyBroadcastManager.php index 3f1935c9..5f3fc4cd 100644 --- a/src/Overrides/TenancyBroadcastManager.php +++ b/src/Overrides/TenancyBroadcastManager.php @@ -11,21 +11,18 @@ use Illuminate\Contracts\Broadcasting\Broadcaster as BroadcasterContract; class TenancyBroadcastManager extends BroadcastManager { /** - * Names of broadcasters that should always be recreated using $this->resolve() - * (even when they're cached and available in the $broadcasters property to prevent - * any potential leaks between contexts) and that should inherit the original broadcaster's channels. - * - * The main concern is inheriting the channels, since the channels get registered - * (e.g. in routes/channels.php) before this manager overrides the BroadcastManager instance - * and new broadcaster instances don't receive the channels automatically. + * Names of broadcasters that + * - should always be recreated using $this->resolve(), even when they're cached and available + * in $this->drivers (so that e.g. when you update tenant's broadcaster credentials in the tenant context, + * the updated credentials will be used for broadcasting in the same context) + * - should inherit the original broadcaster's channels (= the channels registered in + * the central context, e.g. in routes/channels.php, before this manager overrides the bound BroadcastManager) */ public static array $tenantBroadcasters = ['pusher', 'ably']; /** - * Override the get method so that the broadcasters in $tenantBroadcasters - * receive the original broadcaster's channels and always get freshly resolved - * even when they're cached and available in the $broadcasters property, - * and that the resolved broadcaster will override the BroadcasterContract::class singleton. + * Override the get method so that the broadcasters in static::$tenantBroadcasters + * receive the original broadcaster's channels and always get freshly resolved. */ protected function get($name) { @@ -34,10 +31,10 @@ class TenancyBroadcastManager extends BroadcastManager $originalBroadcaster = $this->app->make(BroadcasterContract::class); $newBroadcaster = $this->resolve($name); - // If there is a current broadcaster, give its channels to the newly resolved one + // Give the channels of the original broadcaster (from the central context) to the newly resolved one. // Broadcasters only have to implement the Illuminate\Contracts\Broadcasting\Broadcaster contract - // Which doesn't require the channels property - // So passing the channels is only needed for Illuminate\Broadcasting\Broadcasters\Broadcaster instances + // which doesn't require the channels property, so passing the channels is only + // needed for Illuminate\Broadcasting\Broadcasters\Broadcaster instances. if ($originalBroadcaster instanceof Broadcaster && $newBroadcaster instanceof Broadcaster) { $this->passChannelsFromOriginalBroadcaster($originalBroadcaster, $newBroadcaster); } @@ -48,8 +45,10 @@ class TenancyBroadcastManager extends BroadcastManager return parent::get($name); } - // Because, unlike the original broadcaster, the newly resolved broadcaster won't have the channels registered using routes/channels.php - // Using it for broadcasting won't work, unless we make it have the original broadcaster's channels + // The newly resolved broadcasters don't automatically receive the channels registered + // in central context (e.g. in routes/channels.php), so we have to obtain the channels from the + // broadcaster used in central context and manually pass them to the new broadcasters + // (attempting to broadcast using a broadcaster with no channels results in a 403 error). protected function passChannelsFromOriginalBroadcaster(Broadcaster $originalBroadcaster, Broadcaster $newBroadcaster): void { // invade() because channels can't be retrieved through any of the broadcaster's public methods