diff --git a/assets/TenancyServiceProvider.stub.php b/assets/TenancyServiceProvider.stub.php index a53e5525..87209bd8 100644 --- a/assets/TenancyServiceProvider.stub.php +++ b/assets/TenancyServiceProvider.stub.php @@ -2,20 +2,36 @@ namespace App\Providers; -use Closure; +use Stancl\Tenancy\Contracts\Tenant; use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; +use Stancl\Tenancy\Contracts\UniqueIdentifierGenerator; use Stancl\Tenancy\Events\DatabaseCreated; use Stancl\Tenancy\Events\DatabaseDeleted; use Stancl\Tenancy\Events\DatabaseMigrated; +use Stancl\Tenancy\Events\DatabaseRolledBack; use Stancl\Tenancy\Events\DatabaseSeeded; -use Stancl\Tenancy\Events\Listeners\JobPipeline; +use Stancl\Tenancy\Events\DomainCreated; +use Stancl\Tenancy\Events\DomainDeleted; +use Stancl\Tenancy\Events\DomainSaved; +use Stancl\Tenancy\Events\DomainUpdated; +use Stancl\Tenancy\Events\RevertedToCentralContext; +use Stancl\Tenancy\Events\TenancyBootstrapped; +use Stancl\Tenancy\Events\TenancyEnded; +use Stancl\Tenancy\Events\TenancyInitialized; +use Stancl\Tenancy\Listeners\JobPipeline; use Stancl\Tenancy\Events\TenantCreated; use Stancl\Tenancy\Events\TenantDeleted; +use Stancl\Tenancy\Events\TenantSaved; +use Stancl\Tenancy\Events\TenantUpdated; use Stancl\Tenancy\Jobs\CreateDatabase; use Stancl\Tenancy\Jobs\DeleteDatabase; use Stancl\Tenancy\Jobs\MigrateDatabase; use Stancl\Tenancy\Jobs\SeedDatabase; +use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Listeners\RevertToCentralContext; +use Stancl\Tenancy\Tenancy; class TenancyServiceProvider extends ServiceProvider { @@ -25,35 +41,82 @@ class TenancyServiceProvider extends ServiceProvider TenantCreated::class => [ JobPipeline::make([ CreateDatabase::class, - MigrateDatabase::class, // triggers DatabaseMigrated event + MigrateDatabase::class, SeedDatabase::class, + + // Your own jobs to prepare the tenant. + // Provision API keys, create S3 buckets, anything you want! + ])->send(function (TenantCreated $event) { return $event->tenant; - })->queue(true), + })->queue(false), // `false` by default, but you probably want to make this `true` for production. ], - DatabaseCreated::class => [], - DatabaseMigrated::class => [], - DatabaseSeeded::class => [], + TenantSaved::class => [], + TenantUpdated::class => [], TenantDeleted::class => [ JobPipeline::make([ DeleteDatabase::class, ])->send(function (TenantDeleted $event) { return $event->tenant; - })->queue(true), - // DeleteStorage::class, + })->queue(false), // `false` by default, but you probably want to make this `true` for production. ], + + DomainCreated::class => [], + DomainSaved::class => [], + DomainUpdated::class => [], + DomainDeleted::class => [], + + + DatabaseCreated::class => [], + DatabaseMigrated::class => [], + DatabaseSeeded::class => [], + DatabaseRolledBack::class => [], DatabaseDeleted::class => [], + + TenancyInitialized::class => [ + BootstrapTenancy::class, + ], + TenancyEnded::class => [ + RevertToCentralContext::class, + ], + + TenancyBootstrapped::class => [], + RevertedToCentralContext::class => [], ]; - } + } public function register() { - // + // Make sure Tenancy is stateful. + $this->app->singleton(Tenancy::class); + + // Make sure features are bootstrapped as soon as Tenancy is instantiated. + $this->app->extend(Tenancy::class, function (Tenancy $tenancy) { + foreach ($this->app['config']['tenancy.features'] as $feature) { + $this->app[$feature]->bootstrap($tenancy); + } + + return $tenancy; + }); + + // Make it possible to inject the current tenant by typehinting the Tenant contract. + $this->app->bind(Tenant::class, function ($app) { + return $app[Tenancy::class]->tenant; + }); + + // Make sure bootstrappers are stateful (singletons). + foreach ($this->app['config']['tenancy.bootstrappers'] as $bootstrapper) { + $this->app->singleton($bootstrapper); + } + + // Bind the class in the tenancy.id_generator config to the UniqueIdentifierGenerator abstract. + $this->app->bind(UniqueIdentifierGenerator::class, $this->app['config']['tenancy.id_generator']); } public function boot() { $this->bootEvents(); + $this->mapRoutes(); // } @@ -70,4 +133,15 @@ class TenancyServiceProvider extends ServiceProvider } } } -} \ No newline at end of file + + protected function mapRoutes() + { + $this->app->booted(function () { + if (file_exists(base_path('routes/tenant.php'))) { + Route::middleware(['web']) + ->namespace($this->app['config']['tenancy.tenant_route_namespace'] ?? 'App\Http\Controllers') + ->group(base_path('routes/tenant.php')); + } + }); + } +} diff --git a/assets/config.php b/assets/config.php index e5712767..ab5bf868 100644 --- a/assets/config.php +++ b/assets/config.php @@ -24,23 +24,6 @@ return [ 'localhost', ], - - 'storage' => [ - 'data_column' => 'data', - 'custom_columns' => [ - // 'plan', - ], - - /** - * Here you can enable the Cached Tenant Lookup. - * - * You can specify what cache store should be used to cache the tenant resolution. - * Set to string with a specific cache store name, or to null to disable cache. - */ - 'cache_store' => null, // env('CACHE_DRIVER') - 'cache_ttl' => 3600, // seconds - ], - /** * Controller namespace used by routes in routes/tenant.php. */ @@ -76,7 +59,6 @@ return [ */ 'prefix' => 'tenant', 'suffix' => '', - // todo get rid of this stuff, just set the closure instead ], /** @@ -194,18 +176,11 @@ return [ * See the documentation page for each class to * understand which ones you want to enable. */ - 'features' => [ // todo test features - // Stancl\Tenancy\Features\Timestamps::class, // https://tenancy.samuelstancl.me/docs/v2/features/timestamps/ + 'features' => [ // Stancl\Tenancy\Features\TenantConfig::class, // https://tenancy.samuelstancl.me/docs/v2/features/tenant-config/ - // Stancl\Tenancy\Features\TelescopeTags::class, // https://tenancy.samuelstancl.me/docs/v2/telescope/ // Stancl\Tenancy\Features\CrossDomainRedirect::class, // https://tenancy.samuelstancl.me/docs/v2/features/tenant-redirect/ ], - /** - * The URL to which users will be redirected when they try to acceess a central route on a tenant domain. - */ - 'home_url' => '/app', // todo move this to static - 'migration_parameters' => [ '--force' => true, // Set this to true to be able to run migrations in production '--path' => [database_path('migrations/tenant')], diff --git a/assets/tenant_routes.php.stub b/assets/tenant_routes.php.stub index a51c3f1c..022c8827 100644 --- a/assets/tenant_routes.php.stub +++ b/assets/tenant_routes.php.stub @@ -7,10 +7,17 @@ | | Here you can register the tenant routes for your application. | These routes are loaded by the TenantRouteServiceProvider -| with the tenancy and web middleware groups. Good luck! +| with the namespace configured in your tenancy config. +| +| Feel free to customize them however you want. Good luck! | */ -Route::get('/app', function () { - return 'This is your multi-tenant application. The id of the current tenant is ' . tenant('id'); -}); \ No newline at end of file +Route::group([ + 'middleware' => InitializeTenancyByDomain::class, + 'prefix' => '/app', +], function () { + Route::get('/', function () { + return 'This is your multi-tenant application. The id of the current tenant is ' . tenant('id'); + }); +}); diff --git a/src/Commands/Rollback.php b/src/Commands/Rollback.php index c614fa4a..344a95c7 100644 --- a/src/Commands/Rollback.php +++ b/src/Commands/Rollback.php @@ -9,6 +9,7 @@ use Illuminate\Database\Console\Migrations\RollbackCommand; use Illuminate\Database\Migrations\Migrator; use Stancl\Tenancy\Contracts\TenantWithDatabase; use Stancl\Tenancy\DatabaseManager; +use Stancl\Tenancy\Events\DatabaseRolledBack; use Stancl\Tenancy\Traits\DealsWithMigrations; use Stancl\Tenancy\Traits\HasATenantsOption; @@ -62,7 +63,7 @@ class Rollback extends RollbackCommand // Rollback parent::handle(); - // todo DatabaseRolledBack event + event(new DatabaseRolledBack($tenant)); }); } } diff --git a/src/Contracts/Feature.php b/src/Contracts/Feature.php index 02c3f931..74289981 100644 --- a/src/Contracts/Feature.php +++ b/src/Contracts/Feature.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace Stancl\Tenancy\Contracts; -use Stancl\Tenancy\Facades\Tenancy; +use Stancl\Tenancy\Tenancy; /** Additional features, like Telescope tags and tenant redirects. */ interface Feature diff --git a/src/Contracts/Future/CanDeleteKeys.php b/src/Contracts/Future/CanDeleteKeys.php deleted file mode 100644 index 25f2f5f6..00000000 --- a/src/Contracts/Future/CanDeleteKeys.php +++ /dev/null @@ -1,21 +0,0 @@ -bound(UniqueIdentifierGenerator::class); + } } diff --git a/src/Database/Models/Concerns/HasADataColumn.php b/src/Database/Concerns/HasADataColumn.php similarity index 91% rename from src/Database/Models/Concerns/HasADataColumn.php rename to src/Database/Concerns/HasADataColumn.php index a7b3eb75..7895def4 100644 --- a/src/Database/Models/Concerns/HasADataColumn.php +++ b/src/Database/Concerns/HasADataColumn.php @@ -1,9 +1,7 @@ dataEncodingStatus = 'decoded'; }; - static::registerPriorityListener('retrieved', $decode); + static::registerPriorityListener('retrieved', function ($model) use ($decode) { + // We always decode after model retrieval. + $model->dataEncodingStatus = 'encoded'; + + $decode($model); + }); static::registerPriorityListener('saving', $encode); static::registerPriorityListener('creating', $encode); static::registerPriorityListener('updating', $encode); + static::registerPriorityListener('saved', $decode); static::registerPriorityListener('created', $decode); static::registerPriorityListener('updated', $decode); diff --git a/src/Database/Concerns/HasDomains.php b/src/Database/Concerns/HasDomains.php new file mode 100644 index 00000000..b8e70f09 --- /dev/null +++ b/src/Database/Concerns/HasDomains.php @@ -0,0 +1,16 @@ +hasMany(config('tenancy.domain_model'), 'tenant_id'); + } +} \ No newline at end of file diff --git a/src/Database/Models/Concerns/PrimaryDomain.php b/src/Database/Concerns/PrimaryDomain.php similarity index 89% rename from src/Database/Models/Concerns/PrimaryDomain.php rename to src/Database/Concerns/PrimaryDomain.php index aa965484..f9b0021f 100644 --- a/src/Database/Models/Concerns/PrimaryDomain.php +++ b/src/Database/Concerns/PrimaryDomain.php @@ -1,6 +1,6 @@ hasMany(config('tenancy.domain_model')); - } -} \ No newline at end of file diff --git a/src/Database/Models/Tenant.php b/src/Database/Models/Tenant.php index 4792b30d..fcadb111 100644 --- a/src/Database/Models/Tenant.php +++ b/src/Database/Models/Tenant.php @@ -2,18 +2,30 @@ namespace Stancl\Tenancy\Database\Models; +use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; use Stancl\Tenancy\DatabaseConfig; use Stancl\Tenancy\Events; use Stancl\Tenancy\Contracts; +use Stancl\Tenancy\Database\Concerns; -// todo @property -class Tenant extends Model implements Contracts\TenantWithDatabase +/** + * @property string|int $id + * @property Carbon $created_at + * @property Carbon $updated_at + * @property array $data + */ +class Tenant extends Model implements Contracts\TenantWithDatabase // todo base model that isn't TenantWithDatabase & domains { - use Concerns\CentralConnection, Concerns\HasADataColumn, Concerns\GeneratesIds, Concerns\HasADataColumn { + use Concerns\CentralConnection, + Concerns\HasADataColumn, + Concerns\GeneratesIds, + Concerns\HasADataColumn, + Concerns\HasDomains { Concerns\HasADataColumn::getCasts as dataColumnCasts; } + protected $table = 'tenants'; public $primaryKey = 'id'; public $guarded = []; @@ -34,11 +46,6 @@ class Tenant extends Model implements Contracts\TenantWithDatabase ]); } - public function getIncrementing() - { - return config('tenancy.id_generator') === null; - } - public static function internalPrefix(): string { return config('tenancy.internal_prefix'); diff --git a/src/DatabaseConfig.php b/src/DatabaseConfig.php index ea581b2f..a6c716e7 100644 --- a/src/DatabaseConfig.php +++ b/src/DatabaseConfig.php @@ -6,9 +6,7 @@ namespace Stancl\Tenancy; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Str; -use Stancl\Tenancy\Contracts\Future\CanSetConnection; use Stancl\Tenancy\Contracts\ManagesDatabaseUsers; -use Stancl\Tenancy\Contracts\ModifiesDatabaseNameForConnection; use Stancl\Tenancy\Contracts\TenantDatabaseManager; use Stancl\Tenancy\Database\Models\Tenant; use Stancl\Tenancy\Exceptions\DatabaseManagerNotRegisteredException; @@ -79,6 +77,11 @@ class DatabaseConfig return $this->tenant->getInternal('db_password') ?? null; } + /** + * Generate DB name, username & password and write them to the tenant model. + * + * @return void + */ public function makeCredentials(): void { $this->tenant->setInternal('db_name', $this->getName() ?? (static::$databaseNameGenerator)($this->tenant)); @@ -151,9 +154,7 @@ class DatabaseConfig /** @var TenantDatabaseManager $databaseManager */ $databaseManager = app($databaseManagers[$driver]); - if ($databaseManager instanceof CanSetConnection) { - $databaseManager->setConnection($this->getTemplateConnectionName()); - } + $databaseManager->setConnection($this->getTemplateConnectionName()); return $databaseManager; } diff --git a/src/Events/DatabaseRolledBack.php b/src/Events/DatabaseRolledBack.php new file mode 100644 index 00000000..910c662c --- /dev/null +++ b/src/Events/DatabaseRolledBack.php @@ -0,0 +1,6 @@ +tenancy = $tenancy; + } +} diff --git a/src/Events/TenancyBootstrapped.php b/src/Events/TenancyBootstrapped.php new file mode 100644 index 00000000..5855f271 --- /dev/null +++ b/src/Events/TenancyBootstrapped.php @@ -0,0 +1,16 @@ +tenancy = $tenancy; + } +} diff --git a/src/Facades/Tenancy.php b/src/Facades/Tenancy.php index 58fef2ac..1395ba63 100644 --- a/src/Facades/Tenancy.php +++ b/src/Facades/Tenancy.php @@ -5,12 +5,11 @@ declare(strict_types=1); namespace Stancl\Tenancy\Facades; use Illuminate\Support\Facades\Facade; -use Stancl\Tenancy\TenantManager; class Tenancy extends Facade { protected static function getFacadeAccessor() { - return TenantManager::class; + return \Stancl\Tenancy\Tenancy::class; } } diff --git a/src/Features/TelescopeTags.php b/src/Features/TelescopeTags.php deleted file mode 100644 index cd87160d..00000000 --- a/src/Features/TelescopeTags.php +++ /dev/null @@ -1,63 +0,0 @@ -callback = function ($entry) { - return []; - }; - } - - public function bootstrap(Tenancy $tenancy): void - { - if (! class_exists(Telescope::class)) { - return; - } - - Telescope::tag(function (IncomingEntry $entry) { - $tags = $this->getTags($entry); - - if (! request()->route()) { - return $tags; - } - - // todo lines below - $tenantRoute = PreventAccessFromTenantDomains::routeHasMiddleware(request()->route(), 'tenancy') - || PreventAccessFromTenantDomains::routeHasMiddleware(request()->route(), 'universal'); - - // Don't do anything if we're visiting a universal route on a central domain - if ($tenantRoute && tenancy()->initialized) { - $tags = array_merge($tags, [ - 'tenant:' . tenant('id'), - ]); - } - - return $tags; - }); - } - - public function getTags(IncomingEntry $entry): array - { - return ($this->callback)($entry); - } - - public function setCallback(callable $callback) - { - $this->callback = $callback; - } -} diff --git a/src/Features/TenantConfig.php b/src/Features/TenantConfig.php index f181bb6c..8c9e727d 100644 --- a/src/Features/TenantConfig.php +++ b/src/Features/TenantConfig.php @@ -5,12 +5,13 @@ declare(strict_types=1); namespace Stancl\Tenancy\Features; use Illuminate\Contracts\Config\Repository; +use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Contracts\Feature; +use Stancl\Tenancy\Events\RevertedToCentralContext; +use Stancl\Tenancy\Events\TenancyBootstrapped; use Stancl\Tenancy\Tenancy; -use Stancl\Tenancy\Tenant; -use Stancl\Tenancy\TenantManager; +use Stancl\Tenancy\Contracts\Tenant; -// todo rewrite this class TenantConfig implements Feature { /** @var Repository */ @@ -27,26 +28,26 @@ class TenantConfig implements Feature { $this->config = $config; - foreach ($this->getStorageToConfigMap() as $configKey) { + foreach (static::$storageToConfigMap as $configKey) { $this->originalConfig[$configKey] = $this->config[$configKey]; } } public function bootstrap(Tenancy $tenancy): void { - $tenantManager->eventListener('bootstrapped', function (TenantManager $manager) { - $this->setTenantConfig($manager->getTenant()); + Event::listen(TenancyBootstrapped::class, function (TenancyBootstrapped $event) { + $this->setTenantConfig($event->tenancy->tenant); }); - $tenantManager->eventListener('ended', function () { + Event::listen(RevertedToCentralContext::class, function () { $this->unsetTenantConfig(); }); } public function setTenantConfig(Tenant $tenant): void { - foreach ($this->getStorageToConfigMap() as $storageKey => $configKey) { - $override = $tenant->data[$storageKey] ?? null; + foreach (static::$storageToConfigMap as $storageKey => $configKey) { + $override = $tenant->$storageKey ?? null; if (! is_null($override)) { $this->config[$configKey] = $override; } @@ -55,13 +56,8 @@ class TenantConfig implements Feature public function unsetTenantConfig(): void { - foreach ($this->getStorageToConfigMap() as $configKey) { + foreach (static::$storageToConfigMap as $configKey) { $this->config[$configKey] = $this->originalConfig[$configKey]; } } - - public function getStorageToConfigMap(): array - { - return static::$storageToConfigMap; - } } diff --git a/src/Features/Timestamps.php b/src/Features/Timestamps.php deleted file mode 100644 index b40542ef..00000000 --- a/src/Features/Timestamps.php +++ /dev/null @@ -1,46 +0,0 @@ -config = $config; - } - - public function bootstrap(TenantManager $tenantManager): void - { - $tenantManager->hook('tenant.creating', function ($tm, Tenant $tenant) { - $tenant->with('created_at', $this->now()); - $tenant->with('updated_at', $this->now()); - }); - - $tenantManager->hook('tenant.updating', function ($tm, Tenant $tenant) { - $tenant->with('updated_at', $this->now()); - }); - - $tenantManager->hook('tenant.softDeleting', function ($tm, Tenant $tenant) { - $tenant->with('deleted_at', $this->now()); - }); - } - - public function now(): string - { - return Date::now()->format(static::$format); - } -} diff --git a/src/Jobs/CreateDatabase.php b/src/Jobs/CreateDatabase.php index 68d9cc09..f873765c 100644 --- a/src/Jobs/CreateDatabase.php +++ b/src/Jobs/CreateDatabase.php @@ -12,6 +12,7 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Stancl\Tenancy\Contracts\TenantWithDatabase; use Stancl\Tenancy\Contracts\Tenant; +use Stancl\Tenancy\Events\DatabaseCreated; class CreateDatabase implements ShouldQueue { @@ -30,6 +31,8 @@ class CreateDatabase implements ShouldQueue if ($this->tenant->getInternal('create_database') !== false) { $this->tenant->database()->makeCredentials(); $this->tenant->database()->manager()->createDatabase($this->tenant); + + event(new DatabaseCreated($this->tenant)); } } } diff --git a/src/Jobs/DeleteDatabase.php b/src/Jobs/DeleteDatabase.php index b897bc5c..3fa7b47e 100644 --- a/src/Jobs/DeleteDatabase.php +++ b/src/Jobs/DeleteDatabase.php @@ -11,6 +11,7 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Stancl\Tenancy\Contracts\TenantDatabaseManager; use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Events\DatabaseDeleted; class DeleteDatabase implements ShouldQueue { @@ -27,5 +28,7 @@ class DeleteDatabase implements ShouldQueue public function handle() { $this->tenant->database()->manager()->deleteDatabase($this->tenant); + + event(new DatabaseDeleted($this->tenant)); } } diff --git a/src/Jobs/MigrateDatabase.php b/src/Jobs/MigrateDatabase.php index ea3834c6..5fdd0ede 100644 --- a/src/Jobs/MigrateDatabase.php +++ b/src/Jobs/MigrateDatabase.php @@ -31,12 +31,8 @@ class MigrateDatabase implements ShouldQueue */ public function handle() { - $migrationParameters = [ - // todo ... - ]; - Artisan::call('tenants:migrate', [ '--tenants' => [$this->tenant->id], - ] + $migrationParameters); + ]); } } diff --git a/src/Events/Listeners/BootstrapTenancy.php b/src/Listeners/BootstrapTenancy.php similarity index 53% rename from src/Events/Listeners/BootstrapTenancy.php rename to src/Listeners/BootstrapTenancy.php index 865bc700..b459e7f5 100644 --- a/src/Events/Listeners/BootstrapTenancy.php +++ b/src/Listeners/BootstrapTenancy.php @@ -1,7 +1,8 @@ tenancy->getBootstrappers() as $bootstrapper) { - $bootstrapper->start($event->tenancy->tenant); + $bootstrapper->bootstrap($event->tenancy->tenant); } + + event(new TenancyBootstrapped($event->tenancy)); } } diff --git a/src/Events/Listeners/JobPipeline.php b/src/Listeners/JobPipeline.php similarity index 82% rename from src/Events/Listeners/JobPipeline.php rename to src/Listeners/JobPipeline.php index fff58473..e90595e9 100644 --- a/src/Events/Listeners/JobPipeline.php +++ b/src/Listeners/JobPipeline.php @@ -1,6 +1,6 @@ jobs = $jobs; $this->send = $send ?? function ($event) { // If no $send callback is set, we'll just pass the event through the jobs. return $event; }; - $this->shouldBeQueued = $shouldBeQueued ?? static::$shouldBeQueuedByDefault; + $this->queue = $queue ?? static::$queueByDefault; } /** @param callable[]|string[] $jobs */ @@ -47,9 +47,9 @@ class JobPipeline implements ShouldQueue return $this; } - public function shouldBeQueued(bool $shouldBeQueued) + public function queue(bool $queue) { - $this->shouldBeQueued = $shouldBeQueued; + $this->queue = $queue; return $this; } @@ -69,7 +69,7 @@ class JobPipeline implements ShouldQueue return function (...$args) { $executable = $this->executable($args); - if ($this->shouldBeQueued) { + if ($this->queue) { dispatch($executable); } else { dispatch_now($executable); diff --git a/src/Events/Listeners/QueueableListener.php b/src/Listeners/QueueableListener.php similarity index 92% rename from src/Events/Listeners/QueueableListener.php rename to src/Listeners/QueueableListener.php index b2e40e09..962e27c7 100644 --- a/src/Events/Listeners/QueueableListener.php +++ b/src/Listeners/QueueableListener.php @@ -1,6 +1,6 @@ tenancy->getBootstrappers() as $bootstrapper) { - $bootstrapper->end(); + $bootstrapper->revert(); } + + event(new RevertedToCentralContext($event->tenancy)); } } diff --git a/src/Events/Listeners/UpdateSyncedResource.php b/src/Listeners/UpdateSyncedResource.php similarity index 99% rename from src/Events/Listeners/UpdateSyncedResource.php rename to src/Listeners/UpdateSyncedResource.php index 6bae909a..67de9fe6 100644 --- a/src/Events/Listeners/UpdateSyncedResource.php +++ b/src/Listeners/UpdateSyncedResource.php @@ -1,6 +1,6 @@ app = $app; } - public function start(Tenant $tenant) + public function bootstrap(Tenant $tenant) { $this->resetFacadeCache(); @@ -34,7 +34,7 @@ class CacheTenancyBootstrapper implements TenancyBootstrapper }); } - public function end() + public function revert() { $this->resetFacadeCache(); diff --git a/src/TenancyBootstrappers/DatabaseTenancyBootstrapper.php b/src/TenancyBootstrappers/DatabaseTenancyBootstrapper.php index de70a146..9836ec36 100644 --- a/src/TenancyBootstrappers/DatabaseTenancyBootstrapper.php +++ b/src/TenancyBootstrappers/DatabaseTenancyBootstrapper.php @@ -20,7 +20,7 @@ class DatabaseTenancyBootstrapper implements TenancyBootstrapper $this->database = $database; } - public function start(Tenant $tenant) + public function bootstrap(Tenant $tenant) { /** @var TenantWithDatabase $tenant */ @@ -32,7 +32,7 @@ class DatabaseTenancyBootstrapper implements TenancyBootstrapper $this->database->connectToTenant($tenant); } - public function end() + public function revert() { $this->database->reconnectToCentral(); } diff --git a/src/TenancyBootstrappers/FilesystemTenancyBootstrapper.php b/src/TenancyBootstrappers/FilesystemTenancyBootstrapper.php index 1e458dcd..101c9b7c 100644 --- a/src/TenancyBootstrappers/FilesystemTenancyBootstrapper.php +++ b/src/TenancyBootstrappers/FilesystemTenancyBootstrapper.php @@ -34,7 +34,7 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper }); } - public function start(Tenant $tenant) + public function bootstrap(Tenant $tenant) { $suffix = $this->app['config']['tenancy.filesystem.suffix_base'] . $tenant->getTenantKey(); @@ -69,7 +69,7 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper } } - public function end() + public function revert() { // storage_path() $this->app->useStoragePath($this->originalPaths['storage']); diff --git a/src/TenancyBootstrappers/QueueTenancyBootstrapper.php b/src/TenancyBootstrappers/QueueTenancyBootstrapper.php index 96d9c5a3..dc35e0cf 100644 --- a/src/TenancyBootstrappers/QueueTenancyBootstrapper.php +++ b/src/TenancyBootstrappers/QueueTenancyBootstrapper.php @@ -67,12 +67,12 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper } } - public function start(Tenant $tenant) + public function bootstrap(Tenant $tenant) { $this->tenancyInitialized = true; } - public function end() + public function revert() { $this->tenancyInitialized = false; } diff --git a/src/TenancyBootstrappers/RedisTenancyBootstrapper.php b/src/TenancyBootstrappers/RedisTenancyBootstrapper.php index f80d0033..6e155efa 100644 --- a/src/TenancyBootstrappers/RedisTenancyBootstrapper.php +++ b/src/TenancyBootstrappers/RedisTenancyBootstrapper.php @@ -22,7 +22,7 @@ class RedisTenancyBootstrapper implements TenancyBootstrapper $this->config = $config; } - public function start(Tenant $tenant) + public function bootstrap(Tenant $tenant) { foreach ($this->prefixedConnections() as $connection) { $prefix = $this->config['tenancy.redis.prefix_base'] . $tenant->getTenantKey(); @@ -33,7 +33,7 @@ class RedisTenancyBootstrapper implements TenancyBootstrapper } } - public function end() + public function revert() { foreach ($this->prefixedConnections() as $connection) { $client = Redis::connection($connection)->client(); diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index 450493c0..17cfed14 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -21,23 +21,7 @@ class TenancyServiceProvider extends ServiceProvider { $this->mergeConfigFrom(__DIR__ . '/../assets/config.php', 'tenancy'); - $this->app->bind(Contracts\UniqueIdentifierGenerator::class, $this->app['config']['tenancy.id_generator']); $this->app->singleton(DatabaseManager::class); - $this->app->singleton(Tenancy::class); - $this->app->extend(Tenancy::class, function (Tenancy $tenancy) { - foreach ($this->app['config']['tenancy.features'] as $feature) { - $this->app[$feature]->bootstrap($tenancy); - } - - return $tenancy; - }); - $this->app->bind(Tenant::class, function ($app) { - return $app[Tenancy::class]->tenant; - }); - - foreach ($this->app['config']['tenancy.bootstrappers'] as $bootstrapper) { - $this->app->singleton($bootstrapper); - } $this->app->singleton(Commands\Migrate::class, function ($app) { return new Commands\Migrate($app['migrator'], $app[DatabaseManager::class]); @@ -52,8 +36,6 @@ class TenancyServiceProvider extends ServiceProvider $this->app->bind('globalCache', function ($app) { return new CacheManager($app); }); - - $this->app->register(TenantRouteServiceProvider::class); } /** diff --git a/src/TenantDatabaseManagers/MySQLDatabaseManager.php b/src/TenantDatabaseManagers/MySQLDatabaseManager.php index ea32be63..3ce200ab 100644 --- a/src/TenantDatabaseManagers/MySQLDatabaseManager.php +++ b/src/TenantDatabaseManagers/MySQLDatabaseManager.php @@ -7,11 +7,10 @@ namespace Stancl\Tenancy\TenantDatabaseManagers; use Illuminate\Contracts\Config\Repository; use Illuminate\Database\Connection; use Illuminate\Support\Facades\DB; -use Stancl\Tenancy\Contracts\Future\CanSetConnection; use Stancl\Tenancy\Contracts\TenantDatabaseManager; use Stancl\Tenancy\Contracts\TenantWithDatabase; -class MySQLDatabaseManager implements TenantDatabaseManager, CanSetConnection +class MySQLDatabaseManager implements TenantDatabaseManager { /** @var string */ protected $connection; diff --git a/src/TenantDatabaseManagers/PostgreSQLDatabaseManager.php b/src/TenantDatabaseManagers/PostgreSQLDatabaseManager.php index e17aae9b..08c7d1e7 100644 --- a/src/TenantDatabaseManagers/PostgreSQLDatabaseManager.php +++ b/src/TenantDatabaseManagers/PostgreSQLDatabaseManager.php @@ -7,11 +7,10 @@ namespace Stancl\Tenancy\TenantDatabaseManagers; use Illuminate\Contracts\Config\Repository; use Illuminate\Database\Connection; use Illuminate\Support\Facades\DB; -use Stancl\Tenancy\Contracts\Future\CanSetConnection; use Stancl\Tenancy\Contracts\TenantDatabaseManager; use Stancl\Tenancy\Contracts\TenantWithDatabase; -class PostgreSQLDatabaseManager implements TenantDatabaseManager, CanSetConnection +class PostgreSQLDatabaseManager implements TenantDatabaseManager { /** @var string */ protected $connection; diff --git a/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php b/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php index 6077b6dc..d1b40a99 100644 --- a/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php +++ b/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php @@ -7,11 +7,10 @@ namespace Stancl\Tenancy\TenantDatabaseManagers; use Illuminate\Contracts\Config\Repository; use Illuminate\Database\Connection; use Illuminate\Support\Facades\DB; -use Stancl\Tenancy\Contracts\Future\CanSetConnection; use Stancl\Tenancy\Contracts\TenantDatabaseManager; use Stancl\Tenancy\Contracts\TenantWithDatabase; -class PostgreSQLSchemaManager implements TenantDatabaseManager, CanSetConnection +class PostgreSQLSchemaManager implements TenantDatabaseManager { /** @var string */ protected $connection; diff --git a/src/TenantDatabaseManagers/SQLiteDatabaseManager.php b/src/TenantDatabaseManagers/SQLiteDatabaseManager.php index 562a54be..7101f5e6 100644 --- a/src/TenantDatabaseManagers/SQLiteDatabaseManager.php +++ b/src/TenantDatabaseManagers/SQLiteDatabaseManager.php @@ -38,4 +38,9 @@ class SQLiteDatabaseManager implements TenantDatabaseManager return $baseConfig; } + + public function setConnection(string $connection): void + { + // + } } diff --git a/src/TenantRouteServiceProvider.php b/src/TenantRouteServiceProvider.php deleted file mode 100644 index 531fe153..00000000 --- a/src/TenantRouteServiceProvider.php +++ /dev/null @@ -1,22 +0,0 @@ -app->booted(function () { - if (file_exists(base_path('routes/tenant.php'))) { - Route::middleware(['web']) - ->namespace($this->app['config']['tenancy.tenant_route_namespace'] ?? 'App\Http\Controllers') - ->group(base_path('routes/tenant.php')); - } - }); - } -} diff --git a/src/Traits/TenantAwareCommand.php b/src/Traits/TenantAwareCommand.php index 57690356..d0f3ae81 100644 --- a/src/Traits/TenantAwareCommand.php +++ b/src/Traits/TenantAwareCommand.php @@ -4,9 +4,9 @@ declare(strict_types=1); namespace Stancl\Tenancy\Traits; -use Stancl\Tenancy\Tenant; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Stancl\Tenancy\Contracts\Tenant; trait TenantAwareCommand { diff --git a/tests/AutomaticModeTest.php b/tests/AutomaticModeTest.php index 9f5967bd..a4d94c80 100644 --- a/tests/AutomaticModeTest.php +++ b/tests/AutomaticModeTest.php @@ -1,12 +1,12 @@ Tenant::class]); + config(['tenancy.tenant_model' => CombinedTenant::class]); } /** @test */ @@ -30,7 +30,7 @@ class CombinedDomainAndSubdomainIdentificationTest extends TestCase { config(['tenancy.central_domains' => ['localhost']]); - $tenant = Tenant::create([ + $tenant = CombinedTenant::create([ 'id' => 'acme', ]); @@ -53,7 +53,7 @@ class CombinedDomainAndSubdomainIdentificationTest extends TestCase { config(['tenancy.central_domains' => []]); - $tenant = Tenant::create([ + $tenant = CombinedTenant::create([ 'id' => 'acme', ]); @@ -72,7 +72,7 @@ class CombinedDomainAndSubdomainIdentificationTest extends TestCase } } -class Tenant extends Models\Tenant +class CombinedTenant extends Models\Tenant { use HasDomains; } diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php index b7349c11..97846dad 100644 --- a/tests/CommandsTest.php +++ b/tests/CommandsTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Stancl\Tenancy\Tests\v3; +namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\DB; @@ -10,9 +10,9 @@ use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Schema; use Stancl\Tenancy\Tests\Etc\ExampleSeeder; use Stancl\Tenancy\Database\Models\Tenant; -use Stancl\Tenancy\Events\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Events\Listeners\JobPipeline; -use Stancl\Tenancy\Events\Listeners\RevertToCentralContext; +use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Listeners\JobPipeline; +use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Events\TenancyEnded; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Events\TenantCreated; diff --git a/tests/DatabasePreparationTest.php b/tests/DatabasePreparationTest.php index 053fa9dd..02a06016 100644 --- a/tests/DatabasePreparationTest.php +++ b/tests/DatabasePreparationTest.php @@ -1,6 +1,6 @@ MySQLDatabaseManager::class, 'tenancy.database.suffix' => '', - 'tenancy.database.template_connection' => 'mysql', + 'tenancy.template_tenant_connection' => 'mysql', + 'tenancy.bootstrappers' => [ + DatabaseTenancyBootstrapper::class, + ], ]); + Event::listen(TenancyInitialized::class, BootstrapTenancy::class); + $tenant = Tenant::create([ 'id' => 'foo' . Str::random(10), ]); $this->assertTrue($tenant->database()->manager() instanceof MySQLDatabaseManager); - $tenant = Tenant::create([ - 'id' => 'foo' . Str::random(10), - ]); - tenancy()->initialize($tenant); // check if everything works tenancy()->end(); diff --git a/tests/DomainTest.php b/tests/DomainTest.php index 898f7be5..b7c15128 100644 --- a/tests/DomainTest.php +++ b/tests/DomainTest.php @@ -1,10 +1,10 @@ Tenant::class]); + config(['tenancy.tenant_model' => DomainTenant::class]); } /** @test */ public function tenant_can_be_identified_using_hostname() { - $tenant = Tenant::create(); + $tenant = DomainTenant::create(); $id = $tenant->id; @@ -48,13 +48,13 @@ class DomainTest extends TestCase /** @test */ public function a_domain_can_belong_to_only_one_tenant() { - $tenant = Tenant::create(); + $tenant = DomainTenant::create(); $tenant->domains()->create([ 'domain' => 'foo.localhost', ]); - $tenant2 = Tenant::create(); + $tenant2 = DomainTenant::create(); $this->expectException(DomainOccupiedByOtherTenantException::class); $tenant2->domains()->create([ @@ -73,7 +73,7 @@ class DomainTest extends TestCase /** @test */ public function tenant_can_be_identified_by_domain() { - $tenant = Tenant::create([ + $tenant = DomainTenant::create([ 'id' => 'acme', ]); @@ -104,7 +104,7 @@ class DomainTest extends TestCase } } -class Tenant extends Models\Tenant +class DomainTenant extends Models\Tenant { use HasDomains; } diff --git a/tests/Etc/synced_resource_migrations/users/2020_05_11_000001_create_users_table.php b/tests/Etc/synced_resource_migrations/users/2020_05_11_000001_test_create_users_table.php similarity index 93% rename from tests/Etc/synced_resource_migrations/users/2020_05_11_000001_create_users_table.php rename to tests/Etc/synced_resource_migrations/users/2020_05_11_000001_test_create_users_table.php index 38234e41..0274597f 100644 --- a/tests/Etc/synced_resource_migrations/users/2020_05_11_000001_create_users_table.php +++ b/tests/Etc/synced_resource_migrations/users/2020_05_11_000001_test_create_users_table.php @@ -6,7 +6,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateUsersTable extends Migration +class TestCreateUsersTable extends Migration { /** * Run the migrations. diff --git a/tests/Etc/tmp/jobpipelinetest.json b/tests/Etc/tmp/jobpipelinetest.json deleted file mode 100644 index 9f5dd4e3..00000000 --- a/tests/Etc/tmp/jobpipelinetest.json +++ /dev/null @@ -1 +0,0 @@ -{"foo":"bar"} \ No newline at end of file diff --git a/tests/EventListenerTest.php b/tests/EventListenerTest.php index 9da703d9..6836d990 100644 --- a/tests/EventListenerTest.php +++ b/tests/EventListenerTest.php @@ -1,12 +1,12 @@ assertFalse(app()->bound('foo')); } - - // todo test that the way the published SP registers events works } class FooListener extends QueueableListener diff --git a/tests/Features/TenantConfigTest.php b/tests/Features/TenantConfigTest.php index d6594f98..22d7d168 100644 --- a/tests/Features/TenantConfigTest.php +++ b/tests/Features/TenantConfigTest.php @@ -4,32 +4,39 @@ declare(strict_types=1); namespace Stancl\Tenancy\Tests\Features; +use Illuminate\Support\Facades\Event; +use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Events\TenancyEnded; +use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Features\TenantConfig; +use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Tests\TestCase; class TenantConfigTest extends TestCase { - public $autoInitTenancy = false; - public $autoCreateTenant = false; - /** @test */ public function config_is_merged_and_removed() { $this->assertSame(null, config('services.paypal')); config([ 'tenancy.features' => [TenantConfig::class], + 'tenancy.bootstrappers' => [], ]); + Event::listen(TenancyInitialized::class, BootstrapTenancy::class); + Event::listen(TenancyEnded::class, RevertToCentralContext::class); + TenantConfig::$storageToConfigMap = [ 'paypal_api_public' => 'services.paypal.public', 'paypal_api_private' => 'services.paypal.private', ]; - tenancy()->create('foo.localhost', [ + $tenant = Tenant::create([ 'paypal_api_public' => 'foo', 'paypal_api_private' => 'bar', ]); - tenancy()->init('foo.localhost'); + tenancy()->initialize($tenant); $this->assertSame(['public' => 'foo', 'private' => 'bar'], config('services.paypal')); tenancy()->end(); diff --git a/tests/Features/TimestampTest.php b/tests/Features/TimestampTest.php deleted file mode 100644 index 25cb1017..00000000 --- a/tests/Features/TimestampTest.php +++ /dev/null @@ -1,56 +0,0 @@ - [ - Timestamps::class, - ]]); - } - - /** @test */ - public function create_and_update_timestamps_are_added_on_create() - { - $tenant = Tenant::new()->save(); - $this->assertArrayHasKey('created_at', $tenant->data); - $this->assertArrayHasKey('updated_at', $tenant->data); - } - - /** @test */ - public function update_timestamps_are_added() - { - $tenant = Tenant::new()->save(); - $this->assertSame($tenant->created_at, $tenant->updated_at); - $this->assertSame('string', gettype($tenant->created_at)); - - sleep(1); - - $tenant->put('abc', 'def'); - - $this->assertTrue($tenant->updated_at > $tenant->created_at); - } - - /** @test */ - public function softdelete_timestamps_are_added() - { - $tenant = Tenant::new()->save(); - $this->assertNull($tenant->deleted_at); - - $tenant->softDelete(); - $this->assertNotNull($tenant->deleted_at); - } -} diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index e5d86c92..b8b815d3 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Stancl\Tenancy\Tests\v3; +namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Facades\GlobalCache; use Stancl\Tenancy\Database\Models\Tenant; -use Stancl\Tenancy\Events\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\TenancyBootstrappers\CacheTenancyBootstrapper; use Stancl\Tenancy\Tests\TestCase; diff --git a/tests/JobPipelineTest.php b/tests/JobPipelineTest.php index 23eca4e0..ce910b36 100644 --- a/tests/JobPipelineTest.php +++ b/tests/JobPipelineTest.php @@ -1,12 +1,12 @@ 'redis']); - $this->valuestore = Valuestore::make(__DIR__ . '/../Etc/tmp/jobpipelinetest.json')->flush(); + $this->valuestore = Valuestore::make(__DIR__ . '/Etc/tmp/jobpipelinetest.json')->flush(); } /** @test */ @@ -51,7 +51,7 @@ class JobPipelineTest extends TestCase FooJob::class, ])->send(function () { return $this->valuestore; - })->shouldBeQueued(true)->toListener()); + })->queue(true)->toListener()); Queue::assertNothingPushed(); @@ -70,7 +70,7 @@ class JobPipelineTest extends TestCase FooJob::class, ])->send(function () { return $this->valuestore; - })->shouldBeQueued(true)->toListener()); + })->queue(true)->toListener()); $this->assertFalse($this->valuestore->has('foo')); Tenant::create(); diff --git a/tests/PathIdentificationTest.php b/tests/PathIdentificationTest.php index 587059fe..5ecc8fa9 100644 --- a/tests/PathIdentificationTest.php +++ b/tests/PathIdentificationTest.php @@ -1,6 +1,6 @@ valuestore = Valuestore::make(__DIR__ . '/../Etc/tmp/queuetest.json')->flush(); + $this->valuestore = Valuestore::make(__DIR__ . '/Etc/tmp/queuetest.json')->flush(); } /** @test */ public function tenant_id_is_passed_to_tenant_queues() { + config(['queue.default' => 'sync']); + $tenant = Tenant::create(); tenancy()->initialize($tenant); - Event::fake(); + Event::fake([JobProcessing::class]); dispatch(new TestJob($this->valuestore)); diff --git a/tests/RequestDataIdentificationTest.php b/tests/RequestDataIdentificationTest.php index 86402b66..7128c3b4 100644 --- a/tests/RequestDataIdentificationTest.php +++ b/tests/RequestDataIdentificationTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Stancl\Tenancy\Tests\v3; +namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Route; use Stancl\Tenancy\Database\Models\Tenant; diff --git a/tests/ResourceSyncingTest.php b/tests/ResourceSyncingTest.php index 8f202c50..9ccc3122 100644 --- a/tests/ResourceSyncingTest.php +++ b/tests/ResourceSyncingTest.php @@ -9,14 +9,14 @@ use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Queue; use Stancl\Tenancy\Contracts\Syncable; use Stancl\Tenancy\Contracts\SyncMaster; -use Stancl\Tenancy\Database\Models\Concerns\CentralConnection; -use Stancl\Tenancy\Database\Models\Concerns\ResourceSyncing; +use Stancl\Tenancy\Database\Concerns\CentralConnection; +use Stancl\Tenancy\Database\Concerns\ResourceSyncing; use Stancl\Tenancy\Database\Models; use Stancl\Tenancy\Database\Models\TenantPivot; -use Stancl\Tenancy\Events\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Events\Listeners\JobPipeline; -use Stancl\Tenancy\Events\Listeners\RevertToCentralContext; -use Stancl\Tenancy\Events\Listeners\UpdateSyncedResource; +use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Listeners\JobPipeline; +use Stancl\Tenancy\Listeners\RevertToCentralContext; +use Stancl\Tenancy\Listeners\UpdateSyncedResource; use Stancl\Tenancy\Events\SyncedResourceChangedInForeignDatabase; use Stancl\Tenancy\Events\SyncedResourceSaved; use Stancl\Tenancy\Events\TenancyEnded; @@ -49,8 +49,8 @@ class ResourceSyncingTest extends TestCase $this->artisan('migrate', [ '--path' => [ - __DIR__ . '/../Etc/synced_resource_migrations', - __DIR__ . '/../Etc/synced_resource_migrations/users' + __DIR__ . '/Etc/synced_resource_migrations', + __DIR__ . '/Etc/synced_resource_migrations/users' ], '--realpath' => true, ])->assertExitCode(0); @@ -59,7 +59,7 @@ class ResourceSyncingTest extends TestCase protected function migrateTenants() { $this->artisan('tenants:migrate', [ - '--path' => __DIR__ . '/../Etc/synced_resource_migrations/users', + '--path' => __DIR__ . '/Etc/synced_resource_migrations/users', '--realpath' => true, ])->assertExitCode(0); } @@ -69,7 +69,7 @@ class ResourceSyncingTest extends TestCase { Event::fake([SyncedResourceSaved::class]); - $user = User::create([ + $user = ResourceUser::create([ 'name' => 'Foo', 'email' => 'foo@email.com', 'password' => 'secret', @@ -94,13 +94,13 @@ class ResourceSyncingTest extends TestCase 'role' => 'superadmin', // unsynced ]); - $tenant = Tenant::create(); + $tenant = ResourceTenant::create(); $this->migrateTenants(); tenancy()->initialize($tenant); // Create the same user in tenant DB - $user = User::create([ + $user = ResourceUser::create([ 'global_id' => 'acme', 'name' => 'John Doe', 'email' => 'john@localhost', @@ -135,22 +135,22 @@ class ResourceSyncingTest extends TestCase 'email' => 'john@foreignhost', // synced 'password' => 'secret', // no changes 'role' => 'superadmin', // unsynced - ], User::first()->getAttributes()); + ], ResourceUser::first()->getAttributes()); } /** @test */ public function creating_the_resource_in_tenant_database_creates_it_in_central_database_and_creates_the_mapping() { // Assert no user in central DB - $this->assertCount(0, User::all()); + $this->assertCount(0, ResourceUser::all()); - $tenant = Tenant::create(); + $tenant = ResourceTenant::create(); $this->migrateTenants(); tenancy()->initialize($tenant); // Create the same user in tenant DB - User::create([ + ResourceUser::create([ 'global_id' => 'acme', 'name' => 'John Doe', 'email' => 'john@localhost', @@ -170,7 +170,7 @@ class ResourceSyncingTest extends TestCase // Assert role change doesn't cascade CentralUser::first()->update(['role' => 'central superadmin']); tenancy()->initialize($tenant); - $this->assertSame('commenter', User::first()->role); + $this->assertSame('commenter', ResourceUser::first()->role); } /** @test */ @@ -182,7 +182,7 @@ class ResourceSyncingTest extends TestCase $this->assertFalse(tenancy()->initialized); $this->expectException(ModelNotSyncMaster::class); - User::first()->update(['role' => 'foobar']); + ResourceUser::first()->update(['role' => 'foobar']); } /** @test */ @@ -196,19 +196,19 @@ class ResourceSyncingTest extends TestCase 'role' => 'commenter', // unsynced ]); - $tenant = Tenant::create([ + $tenant = ResourceTenant::create([ 'id' => 't1', ]); $this->migrateTenants(); $tenant->run(function () { - $this->assertCount(0, User::all()); + $this->assertCount(0, ResourceUser::all()); }); $centralUser->tenants()->attach('t1'); $tenant->run(function () { - $this->assertCount(1, User::all()); + $this->assertCount(1, ResourceUser::all()); }); } @@ -223,13 +223,13 @@ class ResourceSyncingTest extends TestCase 'role' => 'commenter', // unsynced ]); - $tenant = Tenant::create([ + $tenant = ResourceTenant::create([ 'id' => 't1', ]); $this->migrateTenants(); $tenant->run(function () { - $this->assertCount(0, User::all()); + $this->assertCount(0, ResourceUser::all()); }); // The child model is inaccessible in the Pivot Model, so we can't fire any events. @@ -237,7 +237,7 @@ class ResourceSyncingTest extends TestCase $tenant->run(function () { // Still zero - $this->assertCount(0, User::all()); + $this->assertCount(0, ResourceUser::all()); }); } @@ -252,15 +252,15 @@ class ResourceSyncingTest extends TestCase 'role' => 'commenter', // unsynced ]); - $t1 = Tenant::create([ + $t1 = ResourceTenant::create([ 'id' => 't1', ]); - $t2 = Tenant::create([ + $t2 = ResourceTenant::create([ 'id' => 't2', ]); - $t3 = Tenant::create([ + $t3 = ResourceTenant::create([ 'id' => 't3', ]); $this->migrateTenants(); @@ -271,17 +271,17 @@ class ResourceSyncingTest extends TestCase $t1->run(function () { // assert user exists - $this->assertCount(1, User::all()); + $this->assertCount(1, ResourceUser::all()); }); $t2->run(function () { // assert user exists - $this->assertCount(1, User::all()); + $this->assertCount(1, ResourceUser::all()); }); $t3->run(function () { // assert user does NOT exist - $this->assertCount(0, User::all()); + $this->assertCount(0, ResourceUser::all()); }); } @@ -297,10 +297,10 @@ class ResourceSyncingTest extends TestCase 'role' => 'commenter', // unsynced ]); - $t1 = Tenant::create([ + $t1 = ResourceTenant::create([ 'id' => 't1', ]); - $t2 = Tenant::create([ + $t2 = ResourceTenant::create([ 'id' => 't2', ]); $this->migrateTenants(); @@ -310,7 +310,7 @@ class ResourceSyncingTest extends TestCase $t2->run(function () { // Create user with the same global ID in t2 database - User::create([ + ResourceUser::create([ 'global_id' => 'acme', 'name' => 'John Foo', // changed 'email' => 'john@foo', // changed @@ -325,7 +325,7 @@ class ResourceSyncingTest extends TestCase $this->assertSame('commenter', $centralUser->role); // role didn't change $t1->run(function () { - $user = User::first(); + $user = ResourceUser::first(); $this->assertSame('John Foo', $user->name); // name changed $this->assertSame('john@foo', $user->email); // email changed $this->assertSame('commenter', $user->role); // role didn't change, i.e. is the same as from the original copy from central @@ -344,13 +344,13 @@ class ResourceSyncingTest extends TestCase 'role' => 'commenter', // unsynced ]); - $t1 = Tenant::create([ + $t1 = ResourceTenant::create([ 'id' => 't1', ]); - $t2 = Tenant::create([ + $t2 = ResourceTenant::create([ 'id' => 't2', ]); - $t3 = Tenant::create([ + $t3 = ResourceTenant::create([ 'id' => 't3', ]); $this->migrateTenants(); @@ -361,17 +361,17 @@ class ResourceSyncingTest extends TestCase $centralUser->tenants()->attach('t3'); $t3->run(function () { - User::first()->update([ + ResourceUser::first()->update([ 'name' => 'John 3', 'role' => 'employee', // unsynced ]); - $this->assertSame('employee', User::first()->role); + $this->assertSame('employee', ResourceUser::first()->role); }); // Check that change was cascaded to other tenants $t1->run($check = function () { - $user = User::first(); + $user = ResourceUser::first(); $this->assertSame('John 3', $user->name); // synced $this->assertSame('commenter', $user->role); // unsynced @@ -408,7 +408,7 @@ class ResourceSyncingTest extends TestCase 'role' => 'employee', ]); - $t1 = Tenant::create([ + $t1 = ResourceTenant::create([ 'id' => 't1', ]); @@ -417,21 +417,21 @@ class ResourceSyncingTest extends TestCase $centralUser->tenants()->attach('t1'); $t1->run(function () { - $this->assertSame('employee', User::first()->role); + $this->assertSame('employee', ResourceUser::first()->role); }); } /** @test */ public function when_the_resource_doesnt_exist_in_the_central_db_non_synced_columns_will_bubble_up_too() { - $t1 = Tenant::create([ + $t1 = ResourceTenant::create([ 'id' => 't1', ]); $this->migrateTenants(); $t1->run(function () { - User::create([ + ResourceUser::create([ 'name' => 'John Doe', 'email' => 'john@doe', 'password' => 'secret', @@ -448,7 +448,7 @@ class ResourceSyncingTest extends TestCase Queue::fake(); UpdateSyncedResource::$shouldQueue = true; - $t1 = Tenant::create([ + $t1 = ResourceTenant::create([ 'id' => 't1', ]); @@ -457,7 +457,7 @@ class ResourceSyncingTest extends TestCase Queue::assertNothingPushed(); $t1->run(function () { - User::create([ + ResourceUser::create([ 'name' => 'John Doe', 'email' => 'john@doe', 'password' => 'secret', @@ -484,13 +484,13 @@ class ResourceSyncingTest extends TestCase 'role' => 'commenter', // unsynced ]); - $t1 = Tenant::create([ + $t1 = ResourceTenant::create([ 'id' => 't1', ]); - $t2 = Tenant::create([ + $t2 = ResourceTenant::create([ 'id' => 't2', ]); - $t3 = Tenant::create([ + $t3 = ResourceTenant::create([ 'id' => 't3', ]); $this->migrateTenants(); @@ -520,12 +520,12 @@ class ResourceSyncingTest extends TestCase Event::fake([SyncedResourceChangedInForeignDatabase::class]); $t3->run(function () { - User::first()->update([ + ResourceUser::first()->update([ 'name' => 'John 3', 'role' => 'employee', // unsynced ]); - $this->assertSame('employee', User::first()->role); + $this->assertSame('employee', ResourceUser::first()->role); }); Event::assertDispatched(SyncedResourceChangedInForeignDatabase::class, function (SyncedResourceChangedInForeignDatabase $event) { @@ -545,11 +545,30 @@ class ResourceSyncingTest extends TestCase return $event->tenant === null; }); - // todo update in global + // Flush + Event::fake([SyncedResourceChangedInForeignDatabase::class]); + + $centralUser->update([ + 'name' => 'John Central', + ]); + + Event::assertDispatched(SyncedResourceChangedInForeignDatabase::class, function (SyncedResourceChangedInForeignDatabase $event) { + return optional($event->tenant)->getTenantKey() === 't1'; + }); + Event::assertDispatched(SyncedResourceChangedInForeignDatabase::class, function (SyncedResourceChangedInForeignDatabase $event) { + return optional($event->tenant)->getTenantKey() === 't2'; + }); + Event::assertDispatched(SyncedResourceChangedInForeignDatabase::class, function (SyncedResourceChangedInForeignDatabase $event) { + return optional($event->tenant)->getTenantKey() === 't3'; + }); + // Assert NOT dispatched in central + Event::assertNotDispatched(SyncedResourceChangedInForeignDatabase::class, function (SyncedResourceChangedInForeignDatabase $event) { + return $event->tenant === null; + }); } } -class Tenant extends Models\Tenant +class ResourceTenant extends Models\Tenant { public function users() { @@ -568,13 +587,13 @@ class CentralUser extends Model implements SyncMaster public function tenants(): BelongsToMany { - return $this->belongsToMany(Tenant::class, 'tenant_users', 'global_user_id', 'tenant_id') + return $this->belongsToMany(ResourceTenant::class, 'tenant_users', 'global_user_id', 'tenant_id') ->using(TenantPivot::class); } public function getTenantModelName(): string { - return User::class; + return ResourceUser::class; } public function getTenantIdColumnInMapTable(): string @@ -607,10 +626,11 @@ class CentralUser extends Model implements SyncMaster } } -class User extends Model implements Syncable +class ResourceUser extends Model implements Syncable { use ResourceSyncing; + protected $table = 'users'; protected $guarded = []; public $timestamps = false; diff --git a/tests/SubdomainTest.php b/tests/SubdomainTest.php index ba483a66..bae8f8ca 100644 --- a/tests/SubdomainTest.php +++ b/tests/SubdomainTest.php @@ -1,10 +1,10 @@ Tenant::class]); + config(['tenancy.tenant_model' => SubdomainTenant::class]); } /** @test */ public function tenant_can_be_identified_by_subdomain() { - $tenant = Tenant::create([ + $tenant = SubdomainTenant::create([ 'id' => 'acme', ]); @@ -105,7 +105,7 @@ class SubdomainTest extends TestCase // not 'localhost' ]]); - $tenant = Tenant::create([ + $tenant = SubdomainTenant::create([ 'id' => 'acme', ]); @@ -121,7 +121,7 @@ class SubdomainTest extends TestCase } } -class Tenant extends Models\Tenant +class SubdomainTenant extends Models\Tenant { use HasDomains; } diff --git a/tests/TenantAssetTest.php b/tests/TenantAssetTest.php index a8b57c15..8f876834 100644 --- a/tests/TenantAssetTest.php +++ b/tests/TenantAssetTest.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Stancl\Tenancy\Tests\v3; +namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Storage; use Stancl\Tenancy\Controllers\TenantAssetsController; use Stancl\Tenancy\Database\Models\Tenant; -use Stancl\Tenancy\Events\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Middleware\InitializeTenancyByDomain; use Stancl\Tenancy\Middleware\InitializeTenancyByRequestData; diff --git a/tests/TenantAwareCommandTest.php b/tests/TenantAwareCommandTest.php index cfda289d..c36fee96 100644 --- a/tests/TenantAwareCommandTest.php +++ b/tests/TenantAwareCommandTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Stancl\Tenancy\Tests\v3; +namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\DB; diff --git a/tests/TenantDatabaseManagerTest.php b/tests/TenantDatabaseManagerTest.php index c078b231..742ce4c4 100644 --- a/tests/TenantDatabaseManagerTest.php +++ b/tests/TenantDatabaseManagerTest.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Stancl\Tenancy\Tests\v3; +namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Database\Models\Tenant; use Stancl\Tenancy\DatabaseManager; -use Stancl\Tenancy\Events\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Events\Listeners\JobPipeline; +use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Listeners\JobPipeline; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Events\TenantCreated; use Stancl\Tenancy\Jobs\CreateDatabase; diff --git a/tests/TenantModelTest.php b/tests/TenantModelTest.php index e99b8337..33383070 100644 --- a/tests/TenantModelTest.php +++ b/tests/TenantModelTest.php @@ -1,6 +1,6 @@ end(); - $this->assertSame(null, app(Tenant::class)); + $this->assertSame(null, app(Contracts\Tenant::class)); } /** @test */ @@ -53,7 +53,7 @@ class TenantModelTest extends TestCase $this->assertSame('bar', $tenant->foo); $this->assertSame(null, $tenant->data); - // Low level test to test database structure + // Low level test to assert database structure $this->assertSame(json_encode(['foo' => 'bar']), DB::table('tenants')->where('id', $tenant->id)->first()->data); $this->assertSame(null, DB::table('tenants')->where('id', $tenant->id)->first()->foo ?? null); @@ -103,8 +103,8 @@ class TenantModelTest extends TestCase unset(app()[UniqueIdentifierGenerator::class]); - $tenant1 = MyTenant::create(); - $tenant2 = MyTenant::create(); + $tenant1 = Tenant::create(); + $tenant2 = Tenant::create(); $this->assertSame(1, $tenant1->id); $this->assertSame(2, $tenant2->id); @@ -138,7 +138,6 @@ class TenantModelTest extends TestCase class MyTenant extends Tenant { protected $table = 'tenants'; - public $increments = true; } class AnotherTenant extends Model implements Contracts\Tenant