From 34a6b2cadd6fb4f94df56525c40b392a74bf1376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Sun, 10 Nov 2019 15:00:23 +0100 Subject: [PATCH] improve hook & testing docs (fix #38) --- docs/source/v2/application-testing.blade.md | 110 ++++++++++++++++++-- docs/source/v2/hooks.blade.md | 85 ++++++++++----- 2 files changed, 162 insertions(+), 33 deletions(-) diff --git a/docs/source/v2/application-testing.blade.md b/docs/source/v2/application-testing.blade.md index f50739f..6510e30 100644 --- a/docs/source/v2/application-testing.blade.md +++ b/docs/source/v2/application-testing.blade.md @@ -7,9 +7,11 @@ section: content # Application Testing {#application-testing} -> Note: You cannot use `:memory:` SQLite databases or the `RefreshDatabase` trait due to the switching of default database. +> Note: At the moment it's not possible to use `:memory:` SQLite databases or the `RefreshDatabase` trait due to the switching of default database. This will hopefully change in the future. -To test your application with this package installed, you can create tenants in the `setUp()` method of your test case: +### Initializing tenancy + +You can create tenants in the `setUp()` method of your test case: ```php protected function setUp(): void @@ -21,7 +23,46 @@ protected function setUp(): void } ``` -And to delete tenants & their databases after tests: +If you don't want to initialize tenancy before each test, you may want to do something like this: +```php +class TestCase // extends ... +{ + protected $tenancy = false; + + public function setUp(): void + { + if ($this->tenancy) { + $this->initializeTenancy(); + } + } + + public function initializeTenancy($domain = 'test.localhost') + { + tenancy()->create($domain); + tenancy()->init($domain); + } + + // ... +} +``` + +And in your individual test classes: +```php +class FooTest +{ + protected $tenancy = true; + + /** @test */ + public function some_test() + { + $this->assertTrue(...); + } +} +``` + +### Cleanup + +To delete tenants & their databases after tests, you may use this: ```php public function tearDown(): void { @@ -35,7 +76,9 @@ public function tearDown(): void } ``` -If you're using the database storage driver, you will also need to run the migrations: +### Storage setup + +If you're using the database storage driver, you will need to run the migrations in `setUp()`: ```php protected function setUp(): void { @@ -43,8 +86,7 @@ protected function setUp(): void $this->artisan('migrate:fresh'); - tenancy()->create('test.localhost'); - tenancy()->init('test.localhost'); + // ... } ``` @@ -58,7 +100,59 @@ protected function setUp(): void // make sure you're using a different connection for testing to avoid losing data Redis::connection('tenancyTesting')->flushdb(); - tenant()->create('test.localhost'); - tenancy()->init('test.localhost'); + // ... } ``` + +### Sample TestCase + +Put together, here's a ready-to-use base TestCase for the DB storage driver +```php +artisan('migrate:fresh'); + + config([ + 'tenancy.queue_database_creation' => false, + ]); + + config(['tenancy.exempt_domains' => [ + '127.0.0.1', + 'localhost', + ]]); + } + + public function tearDown(): void + { + config([ + 'tenancy.queue_database_deletion' => false, + 'tenancy.delete_database_after_tenant_deletion' => true, + ]); + tenancy()->all()->each->delete(); + + parent::tearDown(); + } +} +``` + +phpunit.xml: +```xml + + +``` + +> Don't forget to create an empty database/testing.sqlite + +You may also wish toa dd `testing.sqlite` to `database/.gitignore`. \ No newline at end of file diff --git a/docs/source/v2/hooks.blade.md b/docs/source/v2/hooks.blade.md index 1d21814..17cedc1 100644 --- a/docs/source/v2/hooks.blade.md +++ b/docs/source/v2/hooks.blade.md @@ -7,7 +7,62 @@ section: content # Hooks / The Event System -You can use event hooks to change the behavior of the tenancy bootstrapping and tenancy ending processes. +You can use event hooks to change the behavior of the package. + +All hook callbacks receive the `TenantManager` as the first argument. + +## Tenant events + +A common use case for these events is seeding the tenant data during creation: +```php +// AppServiceProvider::boot() +tenancy()->hook('tenant.creating', function (TenantManager $tm, Tenant $tenant) { + $tenant->put([ + 'posts_per_page' => '15', + ]); +}); +``` + +The following events are available: +- `tenant.creating` +- `tenant.created` +- `tenant.updating` +- `tenant.updated` +- `tenant.deleting` +- `tenant.deleted` +- `tenant.softDeleting` +- `tenant.softDeleted` + +Callbacks for these events may accept the following arguments: +```php +TenantManager $tenantManager, Tenant $tenant +``` + +## Database events + +A use case for these events is executing something after the tenant database is created (& migrated/seeded) without running into race conditions. + +Say you have a `AfterCreatingTenant` job that creates a superadmin user. You may use the `database.creating` event to add this job into the queue chain of the job that creates the tenant's database. +```php +tenancy()->hook('database.creating', function (TenantManager $tm, string $db, Tenant $tenant) { + return [ + new AfterCreatingTenant($tenant->id); + ] +}); +``` + +The following events are available: +- `database.creating` +- `database.created` +- `database.deleting` +- `database.deleted` + +Callbacks for these events may accept the following arguments: +```php +TenantManager $tenantManager, string $db, Tenant $tenant +``` + +## Bootstrapping/ending events The following events are available: - `bootstrapping` @@ -15,23 +70,7 @@ The following events are available: - `ending` - `ended` -### Tenant-specific database connection example {#tenant-specific-database-connection-example} - -> Note: Tenant-specific DB connections can now be achieved using a first-class feature: [Custom DB connections]({{ $page->link('custom-db-connections') }}) - -You can hook into these events using `Tenancy::hook(, function () {})`: -```php -\Tenancy::hook('bootstrapping', function ($tenantManager) { - if ($tenantManager->tenant['id'] === 'someID') { - config(['database.connections.someDatabaseConnection' => $tenantManager->tenant['databaseConnection']]); - $tenantManager->database->useConnection('someDatabaseConnection'); - - return ['database']; - } -}); -``` - -The example above checks whether the current tenant has an id of `someID`. If yes, it creates a new database connection based on data stored in the tenant's storage. Then it changes the default database connection. Finally, it returns an array of the events that this callback prevents. +You may use the `bootstrapping` & `ending` events to prevent some bootstrappers from being executed. The following actions can be prevented: - database connection switch: `database` @@ -41,11 +80,7 @@ The following actions can be prevented: - Queue tenancy: `queue` - and anything else listed in the [`tenancy.bootstrappers` config]({{ $page->link('configuration#bootstrappers') }}) -### Tenant-specific configuration example {#tenant-specific-configuration-example} - -Another common use case for events is tenant-specific config: +Callbacks for these events may accept the following arguments: ```php -\Tenancy::hook('bootstrapped', function ($tenantManager) { - config(['some.api.key' => $tenantManager->tenant['api_key']); -}); -``` +TenantManager $tenantManager, Tenant $tenant +``` \ No newline at end of file