From ec4752881ce993b5fe080839648092e260b89c99 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 29 Jul 2025 12:48:11 +0200 Subject: [PATCH] Refactor bootstrapper, make comments more concise --- src/Bootstrappers/LogTenancyBootstrapper.php | 71 +++++++++++--------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/src/Bootstrappers/LogTenancyBootstrapper.php b/src/Bootstrappers/LogTenancyBootstrapper.php index 63ba2ee5..1493a610 100644 --- a/src/Bootstrappers/LogTenancyBootstrapper.php +++ b/src/Bootstrappers/LogTenancyBootstrapper.php @@ -11,27 +11,33 @@ use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; /** - * This bootstrapper allows modifying the logs so that they're tenant-specific. + * Bootstrapper for tenant-specific logging configuration. * - * If the used channel is 'single' or 'daily', it will set the log path to - * storage_path('logs/laravel.log') for the tenant (so the tenant log will be located at storage/tenantX/logs/laravel.log). - * For this to work correctly, the bootstrapper needs to run after FilesystemTenancyBootstrapper. + * Automatically configures storage path channels (single, daily) to use tenant storage directories. + * Supports custom channel overrides via the $channelOverrides property. * - * Channels that don't use the storage path (e.g. 'slack') will be modified as specified in the $channelOverrides property. - * - * You can also completely override configuration of specific channels by specifying a closure in the $channelOverrides property. + * Note: Must run after FilesystemTenancyBootstrapper for storage path channels to work correctly. */ class LogTenancyBootstrapper implements TenancyBootstrapper { protected array $defaultConfig = []; - // The channels that were modified (set during bootstrap so that they can be reverted later) + /** Channels that were modified during bootstrap (for reverting later) */ protected array $channels = []; + /** + * Log channels that use storage paths for storing the logs. + * Requires FilesystemTenancyBootstrapper to run first. + */ public static array $storagePathChannels = ['single', 'daily']; - // E.g. 'slack' => ['url' => 'webhookUrl'] - // or 'slack' => function ($config, $tenant) { ... } + /** + * Custom channel configuration overrides. + * + * Examples: + * - Array mapping: ['slack' => ['url' => 'webhookUrl']] maps $tenant->webhookUrl to slack.url + * - Closure: ['slack' => fn ($config, $tenant) => $config->set('logging.channels.slack.url', $tenant->slackUrl)] + */ public static array $channelOverrides = []; public function __construct( @@ -57,6 +63,7 @@ class LogTenancyBootstrapper implements TenancyBootstrapper $this->channels = []; } + /** Get all channels that need to be configured, including channels in the log stack. */ protected function getChannels(): array { $channels = [$this->config->get('logging.default')]; @@ -69,38 +76,42 @@ class LogTenancyBootstrapper implements TenancyBootstrapper return $channels; } + /** Configure channels for the tenant context. */ protected function configureChannels(array $channels, Tenant $tenant): void { foreach ($channels as $channel) { - if (in_array($channel, array_keys(static::$channelOverrides))) { - // Override specified channel's config as specified in the $channelOverrides property - // Takes precedence over the storage path channels handling - // The override is an array, use tenant property for overriding the channel config (the default approach) - if (is_array(static::$channelOverrides[$channel])) { - foreach (static::$channelOverrides[$channel] as $channelConfigKey => $tenantProperty) { - // E.g. set 'slack' channel's 'url' to $tenant->webhookUrl - $this->config->set("logging.channels.{$channel}.{$channelConfigKey}", $tenant->$tenantProperty); - } - } - - // If the override is a closure, call it with the config and tenant - // This allows for more custom configurations - if (static::$channelOverrides[$channel] instanceof Closure) { - static::$channelOverrides[$channel]($this->config, $tenant); - } + if (isset(static::$channelOverrides[$channel])) { + $this->overrideChannelConfig($channel, static::$channelOverrides[$channel], $tenant); } elseif (in_array($channel, static::$storagePathChannels)) { - // Default handling for storage path channels ('single', 'daily') - // Can be overriden by the $channelOverrides property - // Set the log path to storage_path('logs/laravel.log') for the tenant + // Set storage path channels to use tenant-specific directory (default behavior) // The tenant log will be located at e.g. "storage/tenant{$tenantKey}/logs/laravel.log" $this->config->set("logging.channels.{$channel}.path", storage_path('logs/laravel.log')); } } } + /** + * Apply channel override configuration. + */ + protected function overrideChannelConfig(string $channel, array|Closure $override, Tenant $tenant): void + { + if (is_array($override)) { + // Map tenant properties to channel config keys + foreach ($override as $configKey => $tenantProperty) { + $this->config->set("logging.channels.{$channel}.{$configKey}", $tenant->$tenantProperty); + } + } elseif ($override instanceof Closure) { + // Execute custom configuration closure + $override($this->config, $tenant); + } + } + + /** + * Forget channels so they can be re-resolved + * with updated configuration on the next log attempt. + */ protected function forgetChannels(): void { - // Forget the channels so that they can be re-resolved with the new config on the next log attempt foreach ($this->channels as $channel) { $this->logManager->forgetChannel($channel); }