diff --git a/src/Contracts/TenancyBootstrapper.php b/src/Contracts/TenancyBootstrapper.php index 2e1e6559..205ef72f 100644 --- a/src/Contracts/TenancyBootstrapper.php +++ b/src/Contracts/TenancyBootstrapper.php @@ -4,10 +4,8 @@ declare(strict_types=1); namespace Stancl\Tenancy\Contracts; -use Stancl\Tenancy\Tenant; - /** - * TenancyBootstrappers are classes that make existing code tenant-aware. + * TenancyBootstrappers are classes that make your application tenant-aware automatically. */ interface TenancyBootstrapper { diff --git a/src/Contracts/TenantWithDatabase.php b/src/Contracts/TenantWithDatabase.php new file mode 100644 index 00000000..02f4e80e --- /dev/null +++ b/src/Contracts/TenantWithDatabase.php @@ -0,0 +1,10 @@ +tenancy = $tenantManager; @@ -51,7 +53,7 @@ class DatabaseManager /** * Connect to a tenant's database. */ - public function connect(Tenant $tenant) + public function connect(TenantWithDatabase $tenant) { $this->createTenantConnection($tenant); $this->setDefaultConnection('tenant'); diff --git a/src/Events/Listeners/BootstrapTenancy.php b/src/Events/Listeners/BootstrapTenancy.php index e69de29b..865bc700 100644 --- a/src/Events/Listeners/BootstrapTenancy.php +++ b/src/Events/Listeners/BootstrapTenancy.php @@ -0,0 +1,15 @@ +tenancy->getBootstrappers() as $bootstrapper) { + $bootstrapper->start($event->tenancy->tenant); + } + } +} diff --git a/src/Events/Listeners/RevertToCentral.php b/src/Events/Listeners/RevertToCentralContext.php similarity index 62% rename from src/Events/Listeners/RevertToCentral.php rename to src/Events/Listeners/RevertToCentralContext.php index 4b485254..18348dc8 100644 --- a/src/Events/Listeners/RevertToCentral.php +++ b/src/Events/Listeners/RevertToCentralContext.php @@ -4,12 +4,12 @@ namespace Stancl\Tenancy\Events\Listeners; use Stancl\Tenancy\Events\TenancyEnded; -class RevertToCentral +class RevertToCentralContext { public function handle(TenancyEnded $event) { - foreach (tenancy()->getBootstrappers() as $bootstrapper) { + foreach ($event->tenancy->getBootstrappers() as $bootstrapper) { $bootstrapper->end(); } - } -} \ No newline at end of file + } +} diff --git a/src/Events/TenancyEnded.php b/src/Events/TenancyEnded.php index f22080d4..8e4323b7 100644 --- a/src/Events/TenancyEnded.php +++ b/src/Events/TenancyEnded.php @@ -2,15 +2,15 @@ namespace Stancl\Tenancy\Events; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tenancy; class TenancyEnded { - /** @var Tenant */ - protected $tenant; + /** @var Tenancy */ + public $tenancy; - public function __construct(Tenant $tenant) + public function __construct(Tenancy $tenancy) { - $this->tenant = $tenant; + $this->tenancy = $tenancy; } } diff --git a/src/Events/TenancyInitialized.php b/src/Events/TenancyInitialized.php index 43c53c38..904323d2 100644 --- a/src/Events/TenancyInitialized.php +++ b/src/Events/TenancyInitialized.php @@ -2,15 +2,15 @@ namespace Stancl\Tenancy\Events; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tenancy; class TenancyInitialized { - /** @var Tenant */ - protected $tenant; + /** @var Tenancy */ + public $tenancy; - public function __construct(Tenant $tenant) + public function __construct(Tenancy $tenancy) { - $this->tenant = $tenant; + $this->tenancy = $tenancy; } } diff --git a/src/Tenancy.php b/src/Tenancy.php index ac7fc90f..053baa18 100644 --- a/src/Tenancy.php +++ b/src/Tenancy.php @@ -26,14 +26,14 @@ class Tenancy $this->initialized = true; - event(new Events\TenancyInitialized($tenant)); + event(new Events\TenancyInitialized($this)); } public function end(): void { $this->initialized = false; - event(new Events\TenancyEnded($this->tenant)); + event(new Events\TenancyEnded($this)); $this->tenant = null; } @@ -43,7 +43,7 @@ class Tenancy { // If no callback for getting bootstrappers is set, we just return all of them. $resolve = static::$getBootstrappers ?? function (Tenant $tenant) { - return config('tenancy.bootstrappers'); + return array_map('app', config('tenancy.bootstrappers')); }; return $resolve($this->tenant); diff --git a/src/TenancyBootstrappers/CacheTenancyBootstrapper.php b/src/TenancyBootstrappers/CacheTenancyBootstrapper.php index ffd1ef6d..8564bd44 100644 --- a/src/TenancyBootstrappers/CacheTenancyBootstrapper.php +++ b/src/TenancyBootstrappers/CacheTenancyBootstrapper.php @@ -8,7 +8,7 @@ use Illuminate\Cache\CacheManager; use Illuminate\Contracts\Foundation\Application; use Stancl\Tenancy\CacheManager as TenantCacheManager; use Stancl\Tenancy\Contracts\TenancyBootstrapper; -use Stancl\Tenancy\Tenant; +use Stancl\Tenancy\Contracts\Tenant; class CacheTenancyBootstrapper implements TenancyBootstrapper { diff --git a/src/TenancyBootstrappers/DatabaseTenancyBootstrapper.php b/src/TenancyBootstrappers/DatabaseTenancyBootstrapper.php index bc9cc9b4..9780af8a 100644 --- a/src/TenancyBootstrappers/DatabaseTenancyBootstrapper.php +++ b/src/TenancyBootstrappers/DatabaseTenancyBootstrapper.php @@ -7,7 +7,7 @@ namespace Stancl\Tenancy\TenancyBootstrappers; use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\DatabaseManager; use Stancl\Tenancy\Exceptions\TenantDatabaseDoesNotExistException; -use Stancl\Tenancy\Tenant; +use Stancl\Tenancy\Contracts\TenantWithDatabase; class DatabaseTenancyBootstrapper implements TenancyBootstrapper { @@ -19,18 +19,18 @@ class DatabaseTenancyBootstrapper implements TenancyBootstrapper $this->database = $database; } - public function start(Tenant $tenant) + public function start(TenantWithDatabase $tenant) { $database = $tenant->database()->getName(); if (! $tenant->database()->manager()->databaseExists($database)) { throw new TenantDatabaseDoesNotExistException($database); } - $this->database->connect($tenant); + $this->database->connectToTenant($tenant); } public function end() { - $this->database->reconnect(); + $this->database->revertToCentral(); } } diff --git a/src/TenancyBootstrappers/FilesystemTenancyBootstrapper.php b/src/TenancyBootstrappers/FilesystemTenancyBootstrapper.php index 35ea5b2b..1e458dcd 100644 --- a/src/TenancyBootstrappers/FilesystemTenancyBootstrapper.php +++ b/src/TenancyBootstrappers/FilesystemTenancyBootstrapper.php @@ -8,7 +8,7 @@ use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Foundation\Application; use Illuminate\Support\Facades\Storage; use Stancl\Tenancy\Contracts\TenancyBootstrapper; -use Stancl\Tenancy\Tenant; +use Stancl\Tenancy\Contracts\Tenant; class FilesystemTenancyBootstrapper implements TenancyBootstrapper { @@ -36,7 +36,7 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper public function start(Tenant $tenant) { - $suffix = $this->app['config']['tenancy.filesystem.suffix_base'] . $tenant->id; + $suffix = $this->app['config']['tenancy.filesystem.suffix_base'] . $tenant->getTenantKey(); // storage_path() if ($this->app['config']['tenancy.filesystem.suffix_storage_path'] ?? true) { diff --git a/src/TenancyBootstrappers/QueueTenancyBootstrapper.php b/src/TenancyBootstrappers/QueueTenancyBootstrapper.php index b2a0fbf2..7f8ee49b 100644 --- a/src/TenancyBootstrappers/QueueTenancyBootstrapper.php +++ b/src/TenancyBootstrappers/QueueTenancyBootstrapper.php @@ -8,8 +8,9 @@ use Illuminate\Config\Repository; use Illuminate\Queue\QueueManager; use Illuminate\Support\Testing\Fakes\QueueFake; use Stancl\Tenancy\Contracts\TenancyBootstrapper; -use Stancl\Tenancy\Tenant; +use Stancl\Tenancy\Contracts\Tenant; +// todo rewrite this class QueueTenancyBootstrapper implements TenancyBootstrapper { /** @var bool Has tenancy been started. */ diff --git a/src/TenancyBootstrappers/RedisTenancyBootstrapper.php b/src/TenancyBootstrappers/RedisTenancyBootstrapper.php index ae20e2c4..f80d0033 100644 --- a/src/TenancyBootstrappers/RedisTenancyBootstrapper.php +++ b/src/TenancyBootstrappers/RedisTenancyBootstrapper.php @@ -7,7 +7,7 @@ namespace Stancl\Tenancy\TenancyBootstrappers; use Illuminate\Contracts\Config\Repository; use Illuminate\Support\Facades\Redis; use Stancl\Tenancy\Contracts\TenancyBootstrapper; -use Stancl\Tenancy\Tenant; +use Stancl\Tenancy\Contracts\Tenant; class RedisTenancyBootstrapper implements TenancyBootstrapper { @@ -25,7 +25,7 @@ class RedisTenancyBootstrapper implements TenancyBootstrapper public function start(Tenant $tenant) { foreach ($this->prefixedConnections() as $connection) { - $prefix = $this->config['tenancy.redis.prefix_base'] . $tenant['id']; + $prefix = $this->config['tenancy.redis.prefix_base'] . $tenant->getTenantKey(); $client = Redis::connection($connection)->client(); $this->originalPrefixes[$connection] = $client->getOption($client::OPT_PREFIX); diff --git a/tests/v3/AutomaticModeTest.php b/tests/v3/AutomaticModeTest.php index b273bb06..9f5967bd 100644 --- a/tests/v3/AutomaticModeTest.php +++ b/tests/v3/AutomaticModeTest.php @@ -2,31 +2,85 @@ namespace Stancl\Tenancy\Tests\v3; +use Illuminate\Support\Facades\Event; +use Stancl\Tenancy\Contracts\TenancyBootstrapper; +use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Events\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Events\Listeners\RevertToCentralContext; +use Stancl\Tenancy\Events\TenancyEnded; +use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Tests\TestCase; class AutomaticModeTest extends TestCase { - /** @test */ - public function custom_bootstrappers_can_be_registered() + public function setUp(): void { - + parent::setUp(); + + Event::listen(TenancyInitialized::class, BootstrapTenancy::class); + Event::listen(TenancyEnded::class, RevertToCentralContext::class); } /** @test */ public function context_is_switched_when_tenancy_is_initialized() { - + config(['tenancy.bootstrappers' => [ + MyBootstrapper::class, + ]]); + + $tenant = Tenant::create([ + 'id' => 'acme', + ]); + + tenancy()->initialize($tenant); + + $this->assertSame('acme', app('tenancy_initialized_for_tenant')); } /** @test */ public function context_is_reverted_when_tenancy_is_ended() { - + $this->context_is_switched_when_tenancy_is_initialized(); + + tenancy()->end(); + + $this->assertSame(true, app('tenancy_ended')); } /** @test */ public function context_is_switched_when_tenancy_is_reinitialized() { - + config(['tenancy.bootstrappers' => [ + MyBootstrapper::class, + ]]); + + $tenant = Tenant::create([ + 'id' => 'acme', + ]); + + tenancy()->initialize($tenant); + + $this->assertSame('acme', app('tenancy_initialized_for_tenant')); + + $tenant2 = Tenant::create([ + 'id' => 'foobar', + ]); + + tenancy()->initialize($tenant2); + + $this->assertSame('foobar', app('tenancy_initialized_for_tenant')); + } +} + +class MyBootstrapper implements TenancyBootstrapper +{ + public function start(\Stancl\Tenancy\Contracts\Tenant $tenant) + { + app()->instance('tenancy_initialized_for_tenant', $tenant->getTenantKey()); + } + + public function end() + { + app()->instance('tenancy_ended', true); } } \ No newline at end of file diff --git a/tests/v3/DatabasePreparationTest.php b/tests/v3/DatabasePreparationTest.php index e69de29b..4bd4834b 100644 --- a/tests/v3/DatabasePreparationTest.php +++ b/tests/v3/DatabasePreparationTest.php @@ -0,0 +1 @@ +// test DB creation, migration, seeding \ No newline at end of file diff --git a/tests/v3/TenantModelTest.php b/tests/v3/TenantModelTest.php index 774a73cf..2aff19a7 100644 --- a/tests/v3/TenantModelTest.php +++ b/tests/v3/TenantModelTest.php @@ -2,6 +2,7 @@ namespace Stancl\Tenancy\Tests\v3; +use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Event; @@ -10,6 +11,7 @@ use Stancl\Tenancy\Database\Models\Tenant; use Stancl\Tenancy\Events\TenantCreated; use Stancl\Tenancy\Tests\TestCase; use Stancl\Tenancy\UniqueIDGenerators\UUIDGenerator; +use Stancl\Tenancy\Contracts; class TenantModelTest extends TestCase { @@ -110,12 +112,43 @@ class TenantModelTest extends TestCase /** @test */ public function custom_tenant_model_can_be_used() { - + $tenant = MyTenant::create(); + + tenancy()->initialize($tenant); + + $this->assertTrue(tenant() instanceof MyTenant); } /** @test */ public function custom_tenant_model_that_doesnt_extend_vendor_Tenant_model_can_be_used() { - + $tenant = AnotherTenant::create([ + 'id' => 'acme', + ]); + + tenancy()->initialize($tenant); + + $this->assertTrue(tenant() instanceof AnotherTenant); + } +} + +class MyTenant extends Tenant +{ + protected $table = 'tenants'; +} + +class AnotherTenant extends Model implements Contracts\Tenant +{ + protected $guarded = []; + protected $table = 'tenants'; + + public function getTenantKeyName(): string + { + return 'id'; + } + + public function getTenantKey(): string + { + return $this->getAttribute('id'); } }