mirror of
https://github.com/archtechx/tenancy.git
synced 2025-12-12 15:54:03 +00:00
Add broadcasting channel prefixing bootstrapper (#12)
* Rename old broadcast bootstrapper, add new one * Add broadcast tenancy bootstrapper + tests * Fix code style (php-cs-fixer) * Fix prefixing * Work on th bootstrapper's tests (wip – problem with events) * Fix bootstrapper * Test that auth closures of channels work correctly * Fix bootstrapper * Fix code style (php-cs-fixer) * Delete channel cloning bootstrapper * Add bootstrapper that prefixes broadcastOn channels under the hood * Add broadcast channel registering helpers * Update prefixing tests (WIP) * Fix code style (php-cs-fixer) * Improve comment * Fix code style (php-cs-fixer) * Allow customization of Pusher/Ably broadcaster extension * Fix code style (php-cs-fixer) * Implement prefix bootstrapper logic, test channel prefixing using a closure * Work on the prefixing bootstrapper and tests * Fix code style (php-cs-fixer) * Add optional $options param to broadcasting helpers * Test broadcasting helpers * Fix code style (php-cs-fixer) * Broadcasting channel prefixing + testing progress * Improve helper methods * Fix and improve test * Fix extending in bootstrap() * Fix code style (php-cs-fixer) * Add docblocks, name things more accurately * Fix code style (php-cs-fixer) * Delete redundant method from testing broadcaster * Test Pusher channel prefixing (probabaly redundant?) * Test if channels get prefixed correctly when switching tenants * Work with the current broadcast manager instead of overriding it * Give the original channels to the overriden broadcasters * Fix code style (php-cs-fixer) * Simplify channel prefix bootstrapper * Fix code style (php-cs-fixer) * Fix comment * Fix test * Delete annotation * Delete unused classes from test * Delete outdated test * Move broadcasting bootstrapper test to BootstrapperTest * Improve bootstrapper test, delete unused event * Add annotations to the bootstrapper * Fix code style (php-cs-fixer) * Improve wording * Improve comment * Update src/Bootstrappers/BroadcastChannelPrefixBootstrapper.php * Apply suggestions from code review * Optionally skip prefixing of specific channels * Add and test central channel helper, update formatChannels overrides and tests * Fix code style (php-cs-fixer) * minor fixes * Improve annotation * Use "global__" prefix instead of "central__", add comments * Correct tests --------- Co-authored-by: PHP CS Fixer <phpcsfixer@example.com> Co-authored-by: Samuel Štancl <samuel.stancl@gmail.com>
This commit is contained in:
parent
b503dbf33d
commit
c34952f328
7 changed files with 450 additions and 24 deletions
160
src/Bootstrappers/BroadcastChannelPrefixBootstrapper.php
Normal file
160
src/Bootstrappers/BroadcastChannelPrefixBootstrapper.php
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Bootstrappers;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Broadcasting\Broadcasters\AblyBroadcaster;
|
||||
use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster;
|
||||
use Illuminate\Broadcasting\BroadcastManager;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Stancl\Tenancy\Contracts\TenancyBootstrapper;
|
||||
use Stancl\Tenancy\Contracts\Tenant;
|
||||
|
||||
/**
|
||||
* Overrides broadcasters (by default, using $broadcasterManager->extend())
|
||||
* so that the channel names they actually use to broadcast events get prefixed.
|
||||
*
|
||||
* Channels you return in the broadcastOn() methods of the events are passed to the formatChannels() method.
|
||||
* Broadcasters use that method to format the names of the channels on which the event will broadcast,
|
||||
* so we override it to prefix the final channel names the broadcasters use for event broadcasting.
|
||||
*/
|
||||
class BroadcastChannelPrefixBootstrapper implements TenancyBootstrapper
|
||||
{
|
||||
/**
|
||||
* Closures overriding broadcasters with custom broadcasters that prefix the channel names with the tenant keys.
|
||||
*
|
||||
* The key is the broadcaster's name, and the value is a closure that should prefix the broadcaster's channels.
|
||||
* $broadcasterOverrides['custom'] = fn () => ...; // Custom override closure
|
||||
*
|
||||
* For more info, see the default override methods in this class (pusher() and ably()).
|
||||
*/
|
||||
public static array $broadcasterOverrides = [];
|
||||
|
||||
protected array $originalBroadcasters = [];
|
||||
|
||||
public function __construct(
|
||||
protected Application $app,
|
||||
protected BroadcastManager $broadcastManager,
|
||||
) {
|
||||
}
|
||||
|
||||
public function bootstrap(Tenant $tenant): void
|
||||
{
|
||||
foreach (static::$broadcasterOverrides as $broadcaster => $broadcasterOverride) {
|
||||
// Save the original broadcaster, so that we can revert to it later
|
||||
$this->originalBroadcasters[$broadcaster] = $this->broadcastManager->driver($broadcaster);
|
||||
|
||||
// Delete the cached broadcaster, so that the manager uses the new one
|
||||
$this->broadcastManager->purge($broadcaster);
|
||||
|
||||
$broadcasterOverride();
|
||||
|
||||
// Get the overriden broadcaster
|
||||
$newBroadcaster = $this->broadcastManager->driver($broadcaster);
|
||||
|
||||
// Register the original broadcaster's channels in the new broadcaster
|
||||
foreach ($this->originalBroadcasters[$broadcaster]->getChannels() as $channel => $callback) {
|
||||
$newBroadcaster->channel($channel, $callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function revert(): void
|
||||
{
|
||||
// Revert to the original broadcasters
|
||||
foreach ($this->originalBroadcasters as $name => $broadcaster) {
|
||||
// Delete the cached (overriden) broadcaster
|
||||
$this->broadcastManager->purge($name);
|
||||
|
||||
// Make manager return the original broadcaster instance
|
||||
// Whenever the broadcaster is requested
|
||||
$this->broadcastManager->extend($name, fn ($app, $config) => $broadcaster);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the closure that overrides the 'pusher' broadcaster.
|
||||
*
|
||||
* By default, override the 'pusher' broadcaster with a broadcaster that
|
||||
* extends PusherBroadcaster, and overrides the formatChannels() method,
|
||||
* such that e.g. 'private-channel' becomes 'private-tenantKey.channel'.
|
||||
*/
|
||||
public static function pusher(Closure|null $override = null): void
|
||||
{
|
||||
static::$broadcasterOverrides['pusher'] = $override ?? function () {
|
||||
$broadcastManager = app(BroadcastManager::class);
|
||||
|
||||
return $broadcastManager->extend('pusher', function ($app, $config) use ($broadcastManager) {
|
||||
return new class($broadcastManager->pusher($config)) extends PusherBroadcaster {
|
||||
protected function formatChannels(array $channels)
|
||||
{
|
||||
$formatChannel = function (string $channel) {
|
||||
$prefixes = ['private-', 'presence-', 'private-encrypted-'];
|
||||
$defaultPrefix = '';
|
||||
|
||||
foreach ($prefixes as $prefix) {
|
||||
if (str($channel)->startsWith($prefix)) {
|
||||
$defaultPrefix = $prefix;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Give the tenant prefix to channels that aren't flagged as central
|
||||
if (! str($channel)->startsWith('global__')) {
|
||||
$channel = str($channel)->after($defaultPrefix)->prepend($defaultPrefix . tenant()->getTenantKey() . '.');
|
||||
}
|
||||
|
||||
return (string) $channel;
|
||||
};
|
||||
|
||||
return array_map($formatChannel, $channels);
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the closure that overrides the 'ably' broadcaster.
|
||||
*
|
||||
* By default, override the 'ably' broadcaster with a broadcaster that
|
||||
* Extends AblyBroadcaster, and overrides the formatChannels() method
|
||||
* such that e.g. 'private-channel' becomes 'private:tenantKey.channel'.
|
||||
*/
|
||||
public static function ably(Closure|null $override = null): void
|
||||
{
|
||||
static::$broadcasterOverrides['ably'] = $override ?? function () {
|
||||
$broadcastManager = app(BroadcastManager::class);
|
||||
|
||||
return $broadcastManager->extend('ably', function ($app, $config) use ($broadcastManager) {
|
||||
return new class($broadcastManager->ably($config)) extends AblyBroadcaster {
|
||||
protected function formatChannels(array $channels)
|
||||
{
|
||||
$formatChannel = function (string $channel) {
|
||||
$prefixes = ['private:', 'presence:'];
|
||||
$defaultPrefix = '';
|
||||
|
||||
foreach ($prefixes as $prefix) {
|
||||
if (str($channel)->startsWith($prefix)) {
|
||||
$defaultPrefix = $prefix;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Give the tenant prefix to channels that aren't flagged as central
|
||||
if (! str($channel)->startsWith('global__')) {
|
||||
$channel = str($channel)->after($defaultPrefix)->prepend($defaultPrefix . tenant()->getTenantKey() . '.');
|
||||
}
|
||||
|
||||
return (string) $channel;
|
||||
};
|
||||
|
||||
return array_map($formatChannel, parent::formatChannels($channels));
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue