mirror of
https://github.com/archtechx/tenancy.git
synced 2026-03-22 17:54:03 +00:00
Merge branch 'archtechx:3.x' into 3.x
This commit is contained in:
commit
32e3b375ca
10 changed files with 114 additions and 19 deletions
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
|
|
@ -16,12 +16,13 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- laravel: 9
|
|
||||||
php: "8.0"
|
|
||||||
- laravel: 10
|
- laravel: 10
|
||||||
php: "8.1"
|
php: "8.1"
|
||||||
- laravel: 11
|
- laravel: 11
|
||||||
php: "8.3"
|
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:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
|
||||||
35
.github/workflows/queue.yml
vendored
Normal file
35
.github/workflows/queue.yml
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
name: Queue tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
- push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
queue:
|
||||||
|
name: Queue application tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Prepare composer version constraint prefix
|
||||||
|
run: |
|
||||||
|
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
|
||||||
|
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
|
||||||
|
run: git clone https://github.com/archtechx/tenancy-queue-tester
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
cd tenancy-queue-tester
|
||||||
|
TENANCY_VERSION=${VERSION_PREFIX}#${GITHUB_SHA} ./setup.sh
|
||||||
|
TENANCY_VERSION=${VERSION_PREFIX}#${GITHUB_SHA} ./test.sh
|
||||||
|
|
@ -194,6 +194,6 @@ return [
|
||||||
*/
|
*/
|
||||||
'seeder_parameters' => [
|
'seeder_parameters' => [
|
||||||
'--class' => 'DatabaseSeeder', // root seeder class
|
'--class' => 'DatabaseSeeder', // root seeder class
|
||||||
// '--force' => true,
|
// '--force' => true, // This needs to be true to seed tenant databases in production
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,15 @@
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.0",
|
"php": "^8.0",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"illuminate/support": "^9.0|^10.0|^11.0",
|
"illuminate/support": "^10.0|^11.0|^12.0",
|
||||||
"facade/ignition-contracts": "^1.0.2",
|
"facade/ignition-contracts": "^1.0.2",
|
||||||
"ramsey/uuid": "^4.7.3",
|
"ramsey/uuid": "^4.7.3",
|
||||||
"stancl/jobpipeline": "^1.6.2",
|
"stancl/jobpipeline": "^1.8.0",
|
||||||
"stancl/virtualcolumn": "^1.3.1"
|
"stancl/virtualcolumn": "^1.5.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"laravel/framework": "^9.0|^10.0|^11.0",
|
"laravel/framework": "^10.0|^11.0|^12.0",
|
||||||
"orchestra/testbench": "^7.0|^8.0|^9.0",
|
"orchestra/testbench": "^8.0|^9.0|^10.0",
|
||||||
"league/flysystem-aws-s3-v3": "^3.12.2",
|
"league/flysystem-aws-s3-v3": "^3.12.2",
|
||||||
"doctrine/dbal": "^3.6.0",
|
"doctrine/dbal": "^3.6.0",
|
||||||
"spatie/valuestore": "^1.3.2"
|
"spatie/valuestore": "^1.3.2"
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,16 @@ trait InvalidatesResolverCache
|
||||||
|
|
||||||
public static function bootInvalidatesResolverCache()
|
public static function bootInvalidatesResolverCache()
|
||||||
{
|
{
|
||||||
static::saved(function (Tenant $tenant) {
|
$invalidateCache = static function (Tenant $tenant) {
|
||||||
foreach (static::$resolvers as $resolver) {
|
foreach (static::$resolvers as $resolver) {
|
||||||
/** @var CachedTenantResolver $resolver */
|
/** @var CachedTenantResolver $resolver */
|
||||||
$resolver = app($resolver);
|
$resolver = app($resolver);
|
||||||
|
|
||||||
$resolver->invalidateCache($tenant);
|
$resolver->invalidateCache($tenant);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
static::saved($invalidateCache);
|
||||||
|
static::deleting($invalidateCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,16 @@ trait InvalidatesTenantsResolverCache
|
||||||
|
|
||||||
public static function bootInvalidatesTenantsResolverCache()
|
public static function bootInvalidatesTenantsResolverCache()
|
||||||
{
|
{
|
||||||
static::saved(function (Model $model) {
|
$invalidateCache = static function (Model $model) {
|
||||||
foreach (static::$resolvers as $resolver) {
|
foreach (static::$resolvers as $resolver) {
|
||||||
/** @var CachedTenantResolver $resolver */
|
/** @var CachedTenantResolver $resolver */
|
||||||
$resolver = app($resolver);
|
$resolver = app($resolver);
|
||||||
|
|
||||||
$resolver->invalidateCache($model->tenant);
|
$resolver->invalidateCache($model->tenant);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
static::saved($invalidateCache);
|
||||||
|
static::deleting($invalidateCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,6 @@ class ModelNotSyncMasterException extends Exception
|
||||||
{
|
{
|
||||||
public function __construct(string $class)
|
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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class UserImpersonation implements Feature
|
||||||
|
|
||||||
public function bootstrap(Tenancy $tenancy): void
|
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([
|
return ImpersonationToken::create([
|
||||||
'tenant_id' => $tenant->getTenantKey(),
|
'tenant_id' => $tenant->getTenantKey(),
|
||||||
'user_id' => $userId,
|
'user_id' => $userId,
|
||||||
|
|
@ -32,10 +32,10 @@ class UserImpersonation implements Feature
|
||||||
* Impersonate a user and get an HTTP redirect response.
|
* Impersonate a user and get an HTTP redirect response.
|
||||||
*
|
*
|
||||||
* @param string|ImpersonationToken $token
|
* @param string|ImpersonationToken $token
|
||||||
* @param int $ttl
|
* @param int|null $ttl
|
||||||
* @return RedirectResponse
|
* @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);
|
$token = $token instanceof ImpersonationToken ? $token : ImpersonationToken::findOrFail($token);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,8 @@ class InitializeTenancyByPath extends IdentificationMiddleware
|
||||||
return $this->initializeTenancy(
|
return $this->initializeTenancy(
|
||||||
$request, $next, $route
|
$request, $next, $route
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
throw new RouteIsMissingTenantParameterException;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $next($request);
|
throw new RouteIsMissingTenantParameterException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||||
namespace Stancl\Tenancy\Tests;
|
namespace Stancl\Tenancy\Tests;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedOnDomainException;
|
||||||
use Stancl\Tenancy\Resolvers\DomainTenantResolver;
|
use Stancl\Tenancy\Resolvers\DomainTenantResolver;
|
||||||
use Stancl\Tenancy\Tests\Etc\Tenant;
|
use Stancl\Tenancy\Tests\Etc\Tenant;
|
||||||
|
|
||||||
|
|
@ -80,6 +81,33 @@ class CachedTenantResolverTest extends TestCase
|
||||||
$this->assertNotEmpty(DB::getQueryLog()); // not empty
|
$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 */
|
/** @test */
|
||||||
public function cache_is_invalidated_when_a_tenants_domain_is_changed()
|
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->assertTrue($tenant->is(app(DomainTenantResolver::class)->resolve('bar')));
|
||||||
$this->assertNotEmpty(DB::getQueryLog()); // not empty
|
$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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue