From 30cdc9461e1a120834e8cdee39aef7a9ced9f863 Mon Sep 17 00:00:00 2001 From: coreyhn Date: Wed, 2 Oct 2024 15:44:08 -0600 Subject: [PATCH 1/9] Fix ModelNotSyncMasterException message (#1257) --- src/Exceptions/ModelNotSyncMasterException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Exceptions/ModelNotSyncMasterException.php b/src/Exceptions/ModelNotSyncMasterException.php index ee5feb9a..09cabb06 100644 --- a/src/Exceptions/ModelNotSyncMasterException.php +++ b/src/Exceptions/ModelNotSyncMasterException.php @@ -10,6 +10,6 @@ class ModelNotSyncMasterException extends Exception { public function __construct(string $class) { - parent::__construct("Model of $class class is not an SyncMaster model. Make sure you're using the central model to make changes to synced resources when you're in the central context"); + parent::__construct("Model of $class class is not a SyncMaster model. Make sure you're using the central model to make changes to synced resources when you're in the central context."); } } From e91ca111233efcd5190386a0ba8b339e8bb394cb Mon Sep 17 00:00:00 2001 From: Mohammad Javad Asna Ashari Date: Sun, 29 Dec 2024 23:58:29 +0330 Subject: [PATCH 2/9] Refactor: Remove unreachable code after exception (#1271) --- src/Middleware/InitializeTenancyByPath.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Middleware/InitializeTenancyByPath.php b/src/Middleware/InitializeTenancyByPath.php index 6289199b..3b691259 100644 --- a/src/Middleware/InitializeTenancyByPath.php +++ b/src/Middleware/InitializeTenancyByPath.php @@ -40,10 +40,8 @@ class InitializeTenancyByPath extends IdentificationMiddleware return $this->initializeTenancy( $request, $next, $route ); - } else { - throw new RouteIsMissingTenantParameterException; } - return $next($request); + throw new RouteIsMissingTenantParameterException; } } From 72579999ac6d97f51fdf1eadf31359b3d8e1d4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 31 Dec 2024 07:23:47 +0100 Subject: [PATCH 3/9] add queue.yml CI workflow --- .github/workflows/queue.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/queue.yml diff --git a/.github/workflows/queue.yml b/.github/workflows/queue.yml new file mode 100644 index 00000000..08472412 --- /dev/null +++ b/.github/workflows/queue.yml @@ -0,0 +1,27 @@ +name: Queue tests + +on: + - push + +jobs: + queue: + name: Queue application tests + runs-on: ubuntu-latest + steps: + - name: Prepare composer version constraint prefix + run: | + BRANCH=${GITHUB_REF#refs/heads/} + if [[ $BRANCH =~ ^[0-9] ]]; then + echo "VERSION_PREFIX=${BRANCH}-dev" >> $GITHUB_ENV + else + echo "VERSION_PREFIX=dev-${BRANCH}" >> $GITHUB_ENV + fi + + - name: Clone test suite + run: git clone https://github.com/archtechx/tenancy-queue-tester + + - name: Run tests + run: | + cd tenancy-queue-tester + ./setup.sh + TENANCY_VERSION=${VERSION_PREFIX}#${GITHUB_SHA} ./test.sh From 22dcb8b0693cfb0dbbf91a3e515ad9a9e2d5e95b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 31 Dec 2024 07:33:50 +0100 Subject: [PATCH 4/9] queue ci: set TENANCY_VERSION for setup.sh --- .github/workflows/queue.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/queue.yml b/.github/workflows/queue.yml index 08472412..07994bbb 100644 --- a/.github/workflows/queue.yml +++ b/.github/workflows/queue.yml @@ -23,5 +23,5 @@ jobs: - name: Run tests run: | cd tenancy-queue-tester - ./setup.sh + TENANCY_VERSION=${VERSION_PREFIX}#${GITHUB_SHA} ./setup.sh TENANCY_VERSION=${VERSION_PREFIX}#${GITHUB_SHA} ./test.sh From e930251db5efabd88166b8d2559eac6ff8473cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 25 Feb 2025 14:36:29 +0100 Subject: [PATCH 5/9] [3.x] Laravel 12 support (#1322) * Laravel 12 support * Drop Laravel 9 support, update CI matrix * run tests on PHP 8.3 --- .github/workflows/ci.yml | 5 +++-- composer.json | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9e2ff55..ef9a9b29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,12 +16,13 @@ jobs: strategy: matrix: include: - - laravel: 9 - php: "8.0" - laravel: 10 php: "8.1" - laravel: 11 php: "8.3" + - laravel: 12 + php: "8.3" + # Ideally we'd run at least one of these on PHP 8.4, however the Dockerfile seems to require some changes for that steps: - uses: actions/checkout@v2 diff --git a/composer.json b/composer.json index 21c0744e..b3070565 100644 --- a/composer.json +++ b/composer.json @@ -12,15 +12,15 @@ "require": { "php": "^8.0", "ext-json": "*", - "illuminate/support": "^9.0|^10.0|^11.0", + "illuminate/support": "^10.0|^11.0|^12.0", "facade/ignition-contracts": "^1.0.2", "ramsey/uuid": "^4.7.3", - "stancl/jobpipeline": "^1.6.2", - "stancl/virtualcolumn": "^1.3.1" + "stancl/jobpipeline": "^1.8.0", + "stancl/virtualcolumn": "^1.5.0" }, "require-dev": { - "laravel/framework": "^9.0|^10.0|^11.0", - "orchestra/testbench": "^7.0|^8.0|^9.0", + "laravel/framework": "^10.0|^11.0|^12.0", + "orchestra/testbench": "^8.0|^9.0|^10.0", "league/flysystem-aws-s3-v3": "^3.12.2", "doctrine/dbal": "^3.6.0", "spatie/valuestore": "^1.3.2" From 19bc316cf67479d5902553aca825347184547f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 25 Feb 2025 15:56:44 +0100 Subject: [PATCH 6/9] Fix git tag support in queue.yml --- .github/workflows/queue.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/queue.yml b/.github/workflows/queue.yml index 07994bbb..2b7fd4d4 100644 --- a/.github/workflows/queue.yml +++ b/.github/workflows/queue.yml @@ -10,11 +10,19 @@ jobs: steps: - name: Prepare composer version constraint prefix run: | - BRANCH=${GITHUB_REF#refs/heads/} - if [[ $BRANCH =~ ^[0-9] ]]; then - echo "VERSION_PREFIX=${BRANCH}-dev" >> $GITHUB_ENV + if [[ $GITHUB_REF == refs/tags/* ]]; then + # For refs like "refs/tags/v3.9.0", remove "refs/tags/v" prefix to get just "3.9.0" + VERSION=${GITHUB_REF#refs/tags/v} + echo "VERSION_PREFIX=${VERSION}" >> $GITHUB_ENV else - echo "VERSION_PREFIX=dev-${BRANCH}" >> $GITHUB_ENV + BRANCH=${GITHUB_REF#refs/heads/} + if [[ $BRANCH =~ ^[0-9]\.x$ ]]; then + # Branches starting with %d.x need to use -dev suffix + echo "VERSION_PREFIX=${BRANCH}-dev" >> $GITHUB_ENV + else + # All other branches use dev-${branch} prefix + echo "VERSION_PREFIX=dev-${BRANCH}" >> $GITHUB_ENV + fi fi - name: Clone test suite From 3f9935784d316db3130273596b9b4d2c70ae054b Mon Sep 17 00:00:00 2001 From: MuHanz <44943686+mu-hanz@users.noreply.github.com> Date: Thu, 13 Mar 2025 23:00:05 +0700 Subject: [PATCH 7/9] fix: add explicit nullable type declarations for UserImpersonation parameters (#1324) --- src/Features/UserImpersonation.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Features/UserImpersonation.php b/src/Features/UserImpersonation.php index 48d65bb9..5413375b 100644 --- a/src/Features/UserImpersonation.php +++ b/src/Features/UserImpersonation.php @@ -18,7 +18,7 @@ class UserImpersonation implements Feature public function bootstrap(Tenancy $tenancy): void { - $tenancy->macro('impersonate', function (Tenant $tenant, string $userId, string $redirectUrl, string $authGuard = null): ImpersonationToken { + $tenancy->macro('impersonate', function (Tenant $tenant, string $userId, string $redirectUrl, ?string $authGuard = null): ImpersonationToken { return ImpersonationToken::create([ 'tenant_id' => $tenant->getTenantKey(), 'user_id' => $userId, @@ -32,10 +32,10 @@ class UserImpersonation implements Feature * Impersonate a user and get an HTTP redirect response. * * @param string|ImpersonationToken $token - * @param int $ttl + * @param int|null $ttl * @return RedirectResponse */ - public static function makeResponse($token, int $ttl = null): RedirectResponse + public static function makeResponse($token, ?int $ttl = null): RedirectResponse { $token = $token instanceof ImpersonationToken ? $token : ImpersonationToken::findOrFail($token); From e46355fb9d09a7f6eeef2c8c4d0ac064f2be4340 Mon Sep 17 00:00:00 2001 From: Johannes Date: Thu, 13 Mar 2025 17:01:51 +0100 Subject: [PATCH 8/9] [3.x] Add comment to config file explaining --force with seeding in production (#1326) * add comment in seed config for clarification * test tenant creation seeding also in production environments (with force) * revert changes in DatabasePreparationTest --- assets/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/config.php b/assets/config.php index a10ad33c..a9fd2b92 100644 --- a/assets/config.php +++ b/assets/config.php @@ -194,6 +194,6 @@ return [ */ 'seeder_parameters' => [ '--class' => 'DatabaseSeeder', // root seeder class - // '--force' => true, + // '--force' => true, // This needs to be true to seed tenant databases in production ], ]; From d98a170fbd2e114604bfec3bc6267a3d6e02dec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Thu, 13 Mar 2025 17:02:11 +0100 Subject: [PATCH 9/9] Invalidate resolver cache on delete (#1328) --- .../Concerns/InvalidatesResolverCache.php | 7 ++- .../InvalidatesTenantsResolverCache.php | 7 ++- tests/CachedTenantResolverTest.php | 55 +++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/Database/Concerns/InvalidatesResolverCache.php b/src/Database/Concerns/InvalidatesResolverCache.php index 7dff35ad..2da00e52 100644 --- a/src/Database/Concerns/InvalidatesResolverCache.php +++ b/src/Database/Concerns/InvalidatesResolverCache.php @@ -18,13 +18,16 @@ trait InvalidatesResolverCache public static function bootInvalidatesResolverCache() { - static::saved(function (Tenant $tenant) { + $invalidateCache = static function (Tenant $tenant) { foreach (static::$resolvers as $resolver) { /** @var CachedTenantResolver $resolver */ $resolver = app($resolver); $resolver->invalidateCache($tenant); } - }); + }; + + static::saved($invalidateCache); + static::deleting($invalidateCache); } } diff --git a/src/Database/Concerns/InvalidatesTenantsResolverCache.php b/src/Database/Concerns/InvalidatesTenantsResolverCache.php index 555aceeb..4101faa7 100644 --- a/src/Database/Concerns/InvalidatesTenantsResolverCache.php +++ b/src/Database/Concerns/InvalidatesTenantsResolverCache.php @@ -21,13 +21,16 @@ trait InvalidatesTenantsResolverCache public static function bootInvalidatesTenantsResolverCache() { - static::saved(function (Model $model) { + $invalidateCache = static function (Model $model) { foreach (static::$resolvers as $resolver) { /** @var CachedTenantResolver $resolver */ $resolver = app($resolver); $resolver->invalidateCache($model->tenant); } - }); + }; + + static::saved($invalidateCache); + static::deleting($invalidateCache); } } diff --git a/tests/CachedTenantResolverTest.php b/tests/CachedTenantResolverTest.php index e7eb52d3..940c950f 100644 --- a/tests/CachedTenantResolverTest.php +++ b/tests/CachedTenantResolverTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\DB; +use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedOnDomainException; use Stancl\Tenancy\Resolvers\DomainTenantResolver; use Stancl\Tenancy\Tests\Etc\Tenant; @@ -80,6 +81,33 @@ class CachedTenantResolverTest extends TestCase $this->assertNotEmpty(DB::getQueryLog()); // not empty } + /** @test */ + public function cache_is_invalidated_when_the_tenant_is_deleted() + { + $tenant = Tenant::create(); + $tenant->createDomain([ + 'domain' => 'acme', + ]); + + DB::enableQueryLog(); + + DomainTenantResolver::$shouldCache = true; + + $this->assertTrue($tenant->is(app(DomainTenantResolver::class)->resolve('acme'))); + DB::flushQueryLog(); + $this->assertTrue($tenant->is(app(DomainTenantResolver::class)->resolve('acme'))); + $this->assertEmpty(DB::getQueryLog()); // empty + + $tenant->delete(); + DB::flushQueryLog(); + + $this->assertThrows(function () { + app(DomainTenantResolver::class)->resolve('acme'); + }, TenantCouldNotBeIdentifiedOnDomainException::class); + + $this->assertNotEmpty(DB::getQueryLog()); // not empty - cache cleared so the DB was queried + } + /** @test */ public function cache_is_invalidated_when_a_tenants_domain_is_changed() { @@ -109,4 +137,31 @@ class CachedTenantResolverTest extends TestCase $this->assertTrue($tenant->is(app(DomainTenantResolver::class)->resolve('bar'))); $this->assertNotEmpty(DB::getQueryLog()); // not empty } + + /** @test */ + public function cache_is_invalidated_when_a_tenants_domain_is_deleted() + { + $tenant = Tenant::create(); + $tenant->createDomain([ + 'domain' => 'acme', + ]); + + DB::enableQueryLog(); + + DomainTenantResolver::$shouldCache = true; + + $this->assertTrue($tenant->is(app(DomainTenantResolver::class)->resolve('acme'))); + DB::flushQueryLog(); + $this->assertTrue($tenant->is(app(DomainTenantResolver::class)->resolve('acme'))); + $this->assertEmpty(DB::getQueryLog()); // empty + + $tenant->domains->first()->delete(); + DB::flushQueryLog(); + + $this->assertThrows(function () { + app(DomainTenantResolver::class)->resolve('acme'); + }, TenantCouldNotBeIdentifiedOnDomainException::class); + + $this->assertNotEmpty(DB::getQueryLog()); // not empty - cache cleared so the DB was queried + } }