mirror of
https://github.com/stancl/tenancy-docs.git
synced 2025-12-12 10:14:03 +00:00
improve hook & testing docs (fix #38)
This commit is contained in:
parent
90545f715e
commit
34a6b2cadd
2 changed files with 162 additions and 33 deletions
|
|
@ -7,9 +7,11 @@ section: content
|
||||||
|
|
||||||
# Application Testing {#application-testing}
|
# 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
|
```php
|
||||||
protected function setUp(): void
|
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
|
```php
|
||||||
public function tearDown(): void
|
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
|
```php
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
|
|
@ -43,8 +86,7 @@ protected function setUp(): void
|
||||||
|
|
||||||
$this->artisan('migrate:fresh');
|
$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
|
// make sure you're using a different connection for testing to avoid losing data
|
||||||
Redis::connection('tenancyTesting')->flushdb();
|
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
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||||
|
|
||||||
|
abstract class TestCase extends BaseTestCase
|
||||||
|
{
|
||||||
|
use CreatesApplication;
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->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
|
||||||
|
<server name="DB_DRIVER" value="sqlite"/>
|
||||||
|
<server name="DB_DATABASE" value="database/testing.sqlite"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
> Don't forget to create an empty database/testing.sqlite
|
||||||
|
|
||||||
|
You may also wish toa dd `testing.sqlite` to `database/.gitignore`.
|
||||||
|
|
@ -7,7 +7,62 @@ section: content
|
||||||
|
|
||||||
# Hooks / The Event System
|
# 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:
|
The following events are available:
|
||||||
- `bootstrapping`
|
- `bootstrapping`
|
||||||
|
|
@ -15,23 +70,7 @@ The following events are available:
|
||||||
- `ending`
|
- `ending`
|
||||||
- `ended`
|
- `ended`
|
||||||
|
|
||||||
### Tenant-specific database connection example {#tenant-specific-database-connection-example}
|
You may use the `bootstrapping` & `ending` events to prevent some bootstrappers from being executed.
|
||||||
|
|
||||||
> 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(<eventName>, 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.
|
|
||||||
|
|
||||||
The following actions can be prevented:
|
The following actions can be prevented:
|
||||||
- database connection switch: `database`
|
- database connection switch: `database`
|
||||||
|
|
@ -41,11 +80,7 @@ The following actions can be prevented:
|
||||||
- Queue tenancy: `queue`
|
- Queue tenancy: `queue`
|
||||||
- and anything else listed in the [`tenancy.bootstrappers` config]({{ $page->link('configuration#bootstrappers') }})
|
- and anything else listed in the [`tenancy.bootstrappers` config]({{ $page->link('configuration#bootstrappers') }})
|
||||||
|
|
||||||
### Tenant-specific configuration example {#tenant-specific-configuration-example}
|
Callbacks for these events may accept the following arguments:
|
||||||
|
|
||||||
Another common use case for events is tenant-specific config:
|
|
||||||
```php
|
```php
|
||||||
\Tenancy::hook('bootstrapped', function ($tenantManager) {
|
TenantManager $tenantManager, Tenant $tenant
|
||||||
config(['some.api.key' => $tenantManager->tenant['api_key']);
|
|
||||||
});
|
|
||||||
```
|
```
|
||||||
Loading…
Add table
Add a link
Reference in a new issue