From 617e9a7a7392705d058e4f030c68795d30a8a93f Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 17 Feb 2023 10:56:43 +0100 Subject: [PATCH] [4.x] Allow user to customize tenant's URL root in CLI (#1044) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add UrlTenancyBootstrapper * Fix code style (php-cs-fixer) * Move URL overriding to a separate method, call it in `boot()` * Test URL root overriding * Change parameter formatting Co-authored-by: Samuel Štancl * Fix code style (php-cs-fixer) * Improve URL bootstrapper test * Move `$scheme` and `$hostname` to the closure * Update code example comment * Hardcode values instead of referencing variables * Delete extra line --------- Co-authored-by: PHP CS Fixer Co-authored-by: Samuel Štancl --- assets/TenancyServiceProvider.stub.php | 26 ++++++++--- assets/config.php | 1 + src/Bootstrappers/UrlTenancyBootstrapper.php | 35 +++++++++++++++ tests/BootstrapperTest.php | 46 +++++++++++++++++++- 4 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 src/Bootstrappers/UrlTenancyBootstrapper.php diff --git a/assets/TenancyServiceProvider.stub.php b/assets/TenancyServiceProvider.stub.php index 6735b37f..a2679061 100644 --- a/assets/TenancyServiceProvider.stub.php +++ b/assets/TenancyServiceProvider.stub.php @@ -4,14 +4,14 @@ declare(strict_types=1); namespace App\Providers; +use Stancl\Tenancy\Jobs; +use Stancl\Tenancy\Events; +use Stancl\Tenancy\Listeners; +use Stancl\Tenancy\Middleware; +use Stancl\JobPipeline\JobPipeline; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; -use Stancl\JobPipeline\JobPipeline; -use Stancl\Tenancy\Events; -use Stancl\Tenancy\Jobs; -use Stancl\Tenancy\Listeners; -use Stancl\Tenancy\Middleware; class TenancyServiceProvider extends ServiceProvider { @@ -118,6 +118,21 @@ class TenancyServiceProvider extends ServiceProvider ]; } + protected function overrideUrlInTenantContext(): void + { + /** + * Example of CLI tenant URL root override: + * + * UrlTenancyBootstrapper::$rootUrlOverride = function (Tenant $tenant) { + * $baseUrl = url('/'); + * $scheme = str($baseUrl)->before('://'); + * $hostname = str($baseUrl)->after($scheme . '://'); + * + * return $scheme . '://' . $tenant->getTenantKey() . '.' . $hostname; + *}; + */ + } + public function register() { // @@ -129,6 +144,7 @@ class TenancyServiceProvider extends ServiceProvider $this->mapRoutes(); $this->makeTenancyMiddlewareHighestPriority(); + $this->overrideUrlInTenantContext(); } protected function bootEvents() diff --git a/assets/config.php b/assets/config.php index c6f3e5a9..bbfa9974 100644 --- a/assets/config.php +++ b/assets/config.php @@ -102,6 +102,7 @@ return [ Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\QueueTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\BatchTenancyBootstrapper::class, + // Stancl\Tenancy\Bootstrappers\UrlTenancyBootstrapper::class, // Stancl\Tenancy\Bootstrappers\SessionTenancyBootstrapper::class, // Stancl\Tenancy\Bootstrappers\MailTenancyBootstrapper::class, // Queueing mail requires using QueueTenancyBootstrapper with $forceRefresh set to true // Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper::class, // Note: phpredis is needed diff --git a/src/Bootstrappers/UrlTenancyBootstrapper.php b/src/Bootstrappers/UrlTenancyBootstrapper.php new file mode 100644 index 00000000..0a4122a6 --- /dev/null +++ b/src/Bootstrappers/UrlTenancyBootstrapper.php @@ -0,0 +1,35 @@ +originalRootUrl = $this->urlGenerator->to('/'); + + if (static::$rootUrlOverride) { + $this->urlGenerator->forceRootUrl((static::$rootUrlOverride)($tenant)); + } + } + + public function revert(): void + { + $this->urlGenerator->forceRootUrl($this->originalRootUrl); + } +} diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index 3cc50b58..fc2d4709 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -3,14 +3,15 @@ declare(strict_types=1); use Illuminate\Support\Str; -use Illuminate\Mail\MailManager; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\URL; use Stancl\JobPipeline\JobPipeline; use Illuminate\Support\Facades\File; use Stancl\Tenancy\Tests\Etc\Tenant; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Redis; +use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Storage; use Stancl\Tenancy\Events\TenancyEnded; use Stancl\Tenancy\Jobs\CreateDatabase; @@ -24,9 +25,11 @@ use Stancl\Tenancy\Jobs\RemoveStorageSymlinks; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\DeleteTenantStorage; use Stancl\Tenancy\Listeners\RevertToCentralContext; +use Stancl\Tenancy\Bootstrappers\UrlTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\MailTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper; +use Stancl\Tenancy\Middleware\InitializeTenancyBySubdomain; use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; @@ -380,3 +383,44 @@ function getDiskPrefix(string $disk): string return $prefix; } + +test('url bootstrapper overrides the root url when tenancy gets initialized and reverts the url to the central one after tenancy ends', function() { + config(['tenancy.bootstrappers.url' => UrlTenancyBootstrapper::class]); + + Route::group([ + 'middleware' => InitializeTenancyBySubdomain::class, + ], function () { + Route::get('/', function () { + return true; + })->name('home'); + }); + + $baseUrl = url(route('home')); + + $rootUrlOverride = function (Tenant $tenant) use ($baseUrl) { + $scheme = str($baseUrl)->before('://'); + $hostname = str($baseUrl)->after($scheme . '://'); + + return $scheme . '://' . $tenant->getTenantKey() . '.' . $hostname; + }; + + UrlTenancyBootstrapper::$rootUrlOverride = $rootUrlOverride; + + $tenant = Tenant::create(); + $tenantUrl = $rootUrlOverride($tenant); + + expect($tenantUrl)->not()->toBe($baseUrl); + + expect(url(route('home')))->toBe($baseUrl); + expect(URL::to('/'))->toBe($baseUrl); + + tenancy()->initialize($tenant); + + expect(url(route('home')))->toBe($tenantUrl); + expect(URL::to('/'))->toBe($tenantUrl); + + tenancy()->end(); + + expect(url(route('home')))->toBe($baseUrl); + expect(URL::to('/'))->toBe($baseUrl); +});