From 79e3d53b06f33aa6e30ee4454177e1d798918704 Mon Sep 17 00:00:00 2001
From: Erik Gaal
Date: Tue, 8 Mar 2022 01:50:25 +0100
Subject: [PATCH 01/13] [3.x] Compatibility with Laravel 9 (#802)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Test on Laravel 9
* Don't extend final Kernel class
* Make FilesystemTenancyBootstrapper compatible with Flysystem v3
Co-authored-by: George
* Update tenant maintenance mode te be in line with Laravel
* Exclude PHP 7.4 <> L9 combination from testing
* add root_override-related assertions
* getPrefix -> getPathPrefix
* handle / inconsistency in s3 prefix
* Refactor Storage facade changes
Co-authored-by: George
Co-authored-by: Samuel Ć tancl
---
.github/workflows/ci.yml | 5 +-
composer.json | 8 +--
.../FilesystemTenancyBootstrapper.php | 31 ++++-----
.../CheckTenantForMaintenanceMode.php | 9 ++-
tests/BootstrapperTest.php | 69 +++++++++++--------
tests/Etc/ConsoleKernel.php | 2 +-
tests/MaintenanceModeTest.php | 4 +-
tests/TestCase.php | 1 +
8 files changed, 74 insertions(+), 55 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f7b64d2d..1303061a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,10 @@ jobs:
strategy:
matrix:
php: ["7.4", "8.0"]
- laravel: ["^6.0", "^8.0"]
+ laravel: ["^6.0", "^8.0", "^9.0"]
+ exclude:
+ - laravel: "^9.0"
+ php: "7.4"
steps:
- uses: actions/checkout@v2
diff --git a/composer.json b/composer.json
index bf66e1f2..88bfea29 100644
--- a/composer.json
+++ b/composer.json
@@ -11,16 +11,16 @@
],
"require": {
"ext-json": "*",
- "illuminate/support": "^6.0|^7.0|^8.0",
+ "illuminate/support": "^6.0|^7.0|^8.0|^9.0",
"facade/ignition-contracts": "^1.0",
"ramsey/uuid": "^3.7|^4.0",
"stancl/jobpipeline": "^1.0",
"stancl/virtualcolumn": "^1.0"
},
"require-dev": {
- "laravel/framework": "^6.0|^7.0|^8.0",
- "orchestra/testbench-browser-kit": "^4.0|^5.0|^6.0",
- "league/flysystem-aws-s3-v3": "~1.0",
+ "laravel/framework": "^6.0|^7.0|^8.0|^9.0",
+ "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0",
+ "league/flysystem-aws-s3-v3": "^1.0|^3.0",
"doctrine/dbal": "^2.10",
"spatie/valuestore": "^1.2.5"
},
diff --git a/src/Bootstrappers/FilesystemTenancyBootstrapper.php b/src/Bootstrappers/FilesystemTenancyBootstrapper.php
index d5ae2d50..418be93f 100644
--- a/src/Bootstrappers/FilesystemTenancyBootstrapper.php
+++ b/src/Bootstrappers/FilesystemTenancyBootstrapper.php
@@ -54,20 +54,20 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
}
// Storage facade
- foreach ($this->app['config']['tenancy.filesystem.disks'] as $disk) {
- /** @var FilesystemAdapter $filesystemDisk */
- $filesystemDisk = Storage::disk($disk);
- $this->originalPaths['disks'][$disk] = $filesystemDisk->getAdapter()->getPathPrefix();
+ Storage::forgetDisk($this->app['config']['tenancy.filesystem.disks']);
- if ($root = str_replace(
+ foreach ($this->app['config']['tenancy.filesystem.disks'] as $disk) {
+ $originalRoot = $this->app['config']["filesystems.disks.{$disk}.root"];
+ $this->originalPaths['disks'][$disk] = $originalRoot;
+
+ $finalPrefix = str_replace(
'%storage_path%',
storage_path(),
- $this->app['config']["tenancy.filesystem.root_override.{$disk}"] ?? ''
- )) {
- $filesystemDisk->getAdapter()->setPathPrefix($finalPrefix = $root);
- } else {
- $root = $this->app['config']["filesystems.disks.{$disk}.root"];
- $filesystemDisk->getAdapter()->setPathPrefix($finalPrefix = $root . "/{$suffix}");
+ $this->app['config']["tenancy.filesystem.root_override.{$disk}"] ?? '',
+ );
+
+ if (! $finalPrefix) {
+ $finalPrefix = $originalRoot . '/'. $suffix;
}
$this->app['config']["filesystems.disks.{$disk}.root"] = $finalPrefix;
@@ -84,14 +84,9 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
$this->app['url']->setAssetRoot($this->app['config']['app.asset_url']);
// Storage facade
+ Storage::forgetDisk($this->app['config']['tenancy.filesystem.disks']);
foreach ($this->app['config']['tenancy.filesystem.disks'] as $disk) {
- /** @var FilesystemAdapter $filesystemDisk */
- $filesystemDisk = Storage::disk($disk);
-
- $root = $this->originalPaths['disks'][$disk];
-
- $filesystemDisk->getAdapter()->setPathPrefix($root);
- $this->app['config']["filesystems.disks.{$disk}.root"] = $root;
+ $this->app['config']["filesystems.disks.{$disk}.root"] = $this->originalPaths['disks'][$disk];
}
}
}
diff --git a/src/Middleware/CheckTenantForMaintenanceMode.php b/src/Middleware/CheckTenantForMaintenanceMode.php
index 5554663f..8e29a31e 100644
--- a/src/Middleware/CheckTenantForMaintenanceMode.php
+++ b/src/Middleware/CheckTenantForMaintenanceMode.php
@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Middleware;
use Closure;
-use Illuminate\Foundation\Http\Exceptions\MaintenanceModeException;
+use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
use Stancl\Tenancy\Exceptions\TenancyNotInitializedException;
use Symfony\Component\HttpFoundation\IpUtils;
@@ -29,7 +29,12 @@ class CheckTenantForMaintenanceMode extends CheckForMaintenanceMode
return $next($request);
}
- throw new MaintenanceModeException($data['time'], $data['retry'], $data['message']);
+ throw new HttpException(
+ 503,
+ 'Service Unavailable',
+ null,
+ isset($data['retry']) ? ['Retry-After' => $data['retry']] : []
+ );
}
return $next($request);
diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php
index 1b0c880d..29aa7dc9 100644
--- a/tests/BootstrapperTest.php
+++ b/tests/BootstrapperTest.php
@@ -4,23 +4,27 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Tests;
-use Illuminate\Support\Facades\Cache;
+use Illuminate\Filesystem\FilesystemAdapter;
+use ReflectionObject;
+use ReflectionProperty;
+use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
+use Stancl\JobPipeline\JobPipeline;
+use Stancl\Tenancy\Tests\Etc\Tenant;
+use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
-use Stancl\JobPipeline\JobPipeline;
-use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper;
-use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
-use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper;
-use Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper;
use Stancl\Tenancy\Events\TenancyEnded;
-use Stancl\Tenancy\Events\TenancyInitialized;
-use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Jobs\CreateDatabase;
+use Stancl\Tenancy\Events\TenantCreated;
+use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Listeners\BootstrapTenancy;
use Stancl\Tenancy\Listeners\RevertToCentralContext;
-use Stancl\Tenancy\Tests\Etc\Tenant;
+use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper;
+use Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper;
+use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
+use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper;
class BootstrapperTest extends TestCase
{
@@ -165,6 +169,7 @@ class BootstrapperTest extends TestCase
$tenant2 = Tenant::create();
tenancy()->initialize($tenant1);
+
Storage::disk('public')->put('foo', 'bar');
$this->assertSame('bar', Storage::disk('public')->get('foo'));
@@ -184,30 +189,38 @@ class BootstrapperTest extends TestCase
$this->assertFalse(Storage::disk('public')->exists('foo'));
$this->assertFalse(Storage::disk('public')->exists('abc'));
+ $expected_storage_path = $old_storage_path . '/tenant' . tenant('id'); // /tenant = suffix base
+
+ // Check that disk prefixes respect the root_override logic
+ $this->assertSame($expected_storage_path . '/app/', $this->getDiskPrefix('local'));
+ $this->assertSame($expected_storage_path . '/app/public/', $this->getDiskPrefix('public'));
+ $this->assertSame('tenant' . tenant('id') . '/', ltrim($this->getDiskPrefix('s3'), '/'));
+
// Check suffixing logic
$new_storage_path = storage_path();
- $this->assertEquals($old_storage_path . '/' . config('tenancy.filesystem.suffix_base') . tenant('id'), $new_storage_path);
+ $this->assertEquals($expected_storage_path, $new_storage_path);
+ }
- foreach (config('tenancy.filesystem.disks') as $disk) {
- $suffix = config('tenancy.filesystem.suffix_base') . tenant('id');
+ protected function getDiskPrefix(string $disk): string
+ {
+ /** @var FilesystemAdapter $disk */
+ $disk = Storage::disk($disk);
+ $adapter = $disk->getAdapter();
- /** @var FilesystemAdapter $filesystemDisk */
- $filesystemDisk = Storage::disk($disk);
-
- $current_path_prefix = $filesystemDisk->getAdapter()->getPathPrefix();
-
- if ($override = config("tenancy.filesystem.root_override.{$disk}")) {
- $correct_path_prefix = str_replace('%storage_path%', storage_path(), $override);
- } else {
- if ($base = $old_storage_facade_roots[$disk]) {
- $correct_path_prefix = $base . "/$suffix/";
- } else {
- $correct_path_prefix = "$suffix/";
- }
- }
-
- $this->assertSame($correct_path_prefix, $current_path_prefix);
+ if (! Str::startsWith(app()->version(), '9.')) {
+ return $adapter->getPathPrefix();
}
+
+ $prefixer = (new ReflectionObject($adapter))->getProperty('prefixer');
+ $prefixer->setAccessible(true);
+
+ // reflection -> instance
+ $prefixer = $prefixer->getValue($adapter);
+
+ $prefix = (new ReflectionProperty($prefixer, 'prefix'));
+ $prefix->setAccessible(true);
+
+ return $prefix->getValue($prefixer);
}
// for queues see QueueTest
diff --git a/tests/Etc/ConsoleKernel.php b/tests/Etc/ConsoleKernel.php
index 1bc66365..9d37d3c6 100644
--- a/tests/Etc/ConsoleKernel.php
+++ b/tests/Etc/ConsoleKernel.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Tests\Etc;
-use Orchestra\Testbench\Console\Kernel;
+use Orchestra\Testbench\Foundation\Console\Kernel;
class ConsoleKernel extends Kernel
{
diff --git a/tests/MaintenanceModeTest.php b/tests/MaintenanceModeTest.php
index a8ecb064..4a8d8d0c 100644
--- a/tests/MaintenanceModeTest.php
+++ b/tests/MaintenanceModeTest.php
@@ -4,12 +4,14 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Tests;
+use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Foundation\Http\Exceptions\MaintenanceModeException;
use Illuminate\Support\Facades\Route;
use Stancl\Tenancy\Database\Concerns\MaintenanceMode;
use Stancl\Tenancy\Middleware\CheckTenantForMaintenanceMode;
use Stancl\Tenancy\Middleware\InitializeTenancyByDomain;
use Stancl\Tenancy\Tests\Etc\Tenant;
+use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
class MaintenanceModeTest extends TestCase
{
@@ -32,7 +34,7 @@ class MaintenanceModeTest extends TestCase
$tenant->putDownForMaintenance();
- $this->expectException(MaintenanceModeException::class);
+ $this->expectException(HttpException::class);
$this->withoutExceptionHandling()
->get('http://acme.localhost/foo');
}
diff --git a/tests/TestCase.php b/tests/TestCase.php
index d3e42ea1..cea669a1 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -87,6 +87,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
'public',
's3',
],
+ 'filesystems.disks.s3.bucket' => 'foo',
'tenancy.redis.tenancy' => env('TENANCY_TEST_REDIS_TENANCY', true),
'database.redis.client' => env('TENANCY_TEST_REDIS_CLIENT', 'phpredis'),
'tenancy.redis.prefixed_connections' => ['default'],
From eb1a2ebe32a3dd9e5941c81602d55aab2268db06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Thu, 17 Mar 2022 12:24:57 +0100
Subject: [PATCH 02/13] Use 7.2 instead of 7.4
---
.github/workflows/ci.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1303061a..3d1698b4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -15,11 +15,11 @@ jobs:
strategy:
matrix:
- php: ["7.4", "8.0"]
+ php: ["7.2", "8.0"]
laravel: ["^6.0", "^8.0", "^9.0"]
exclude:
- laravel: "^9.0"
- php: "7.4"
+ php: "7.2"
steps:
- uses: actions/checkout@v2
From fa2a61fcd74126587312567d5e07e273c8ea43b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Thu, 17 Mar 2022 12:30:14 +0100
Subject: [PATCH 03/13] Use PHP 7.3 instead of 7.2
---
.github/workflows/ci.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3d1698b4..cc8ad985 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -15,11 +15,11 @@ jobs:
strategy:
matrix:
- php: ["7.2", "8.0"]
+ php: ["7.3", "8.0"]
laravel: ["^6.0", "^8.0", "^9.0"]
exclude:
- laravel: "^9.0"
- php: "7.2"
+ php: "7.3"
steps:
- uses: actions/checkout@v2
From 49ebb75f007d649465fc3f847ddc76f6396b0337 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Thu, 17 Mar 2022 12:46:49 +0100
Subject: [PATCH 04/13] Fixes #827
---
src/Bootstrappers/QueueTenancyBootstrapper.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/Bootstrappers/QueueTenancyBootstrapper.php b/src/Bootstrappers/QueueTenancyBootstrapper.php
index 6a88f701..666e29ed 100644
--- a/src/Bootstrappers/QueueTenancyBootstrapper.php
+++ b/src/Bootstrappers/QueueTenancyBootstrapper.php
@@ -30,8 +30,10 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper
*
* This is useful when you're changing the tenant's state (e.g. properties in the `data` column) and want the next job to initialize tenancy again
* with the new data. Features like the Tenant Config are only executed when tenancy is initialized, so the re-initialization is needed in some cases.
+ *
+ * @var bool
*/
- public static bool $forceRefresh = false;
+ public static $forceRefresh = false;
/**
* The normal constructor is only executed after tenancy is bootstrapped.
From 5026f54a6d4482226951d3a8196218ea41434db4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 23 Mar 2022 20:48:55 +0100
Subject: [PATCH 05/13] fix path prefixing
---
CONTRIBUTING.md | 13 +++++++++++++
Dockerfile | 2 +-
docker-compose.override.yml | 5 +++++
src/Bootstrappers/FilesystemTenancyBootstrapper.php | 4 +++-
tests/BootstrapperTest.php | 2 +-
tests/Etc/tmp/queuetest.json | 0
6 files changed, 23 insertions(+), 3 deletions(-)
create mode 100644 docker-compose.override.yml
delete mode 100644 tests/Etc/tmp/queuetest.json
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7dce1b82..a5a6ec3f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -9,3 +9,16 @@ StyleCI will flag code style violations in your pull requests.
Run `docker-compose up -d` to start the containers. Then run `./test` to run the tests.
When you're done testing, run `docker-compose down` to shut down the containers.
+
+### Docker on M1
+
+You can add:
+```yaml
+services:
+ mysql:
+ platform: linux/amd64
+ mysql2:
+ platform: linux/amd64
+```
+
+to `docker-compose.override.yml` to make `docker-compose up-d` work on M1.
diff --git a/Dockerfile b/Dockerfile
index 06d97aea..36f52d6a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -30,7 +30,7 @@ RUN docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
# && if [ "${PHP_VERSION}" = "7.4" ]; then docker-php-ext-configure gd --with-freetype --with-jpeg; else docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/; fi \
&& docker-php-ext-install -j$(nproc) gd pdo pdo_mysql pdo_pgsql pdo_sqlite pgsql zip gmp bcmath pcntl ldap sysvmsg exif \
# install the redis php extension
- && pecl install redis-5.3.2 \
+ && pecl install redis-5.3.7 \
&& docker-php-ext-enable redis \
# install the pcov extention
&& pecl install pcov \
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
new file mode 100644
index 00000000..29e9fb37
--- /dev/null
+++ b/docker-compose.override.yml
@@ -0,0 +1,5 @@
+services:
+ mysql:
+ platform: linux/amd64
+ mysql2:
+ platform: linux/amd64
diff --git a/src/Bootstrappers/FilesystemTenancyBootstrapper.php b/src/Bootstrappers/FilesystemTenancyBootstrapper.php
index 418be93f..dcd7299e 100644
--- a/src/Bootstrappers/FilesystemTenancyBootstrapper.php
+++ b/src/Bootstrappers/FilesystemTenancyBootstrapper.php
@@ -67,7 +67,9 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
);
if (! $finalPrefix) {
- $finalPrefix = $originalRoot . '/'. $suffix;
+ $finalPrefix = $originalRoot
+ ? $originalRoot . '/'. $suffix
+ : $suffix;
}
$this->app['config']["filesystems.disks.{$disk}.root"] = $finalPrefix;
diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php
index 29aa7dc9..588fadd8 100644
--- a/tests/BootstrapperTest.php
+++ b/tests/BootstrapperTest.php
@@ -194,7 +194,7 @@ class BootstrapperTest extends TestCase
// Check that disk prefixes respect the root_override logic
$this->assertSame($expected_storage_path . '/app/', $this->getDiskPrefix('local'));
$this->assertSame($expected_storage_path . '/app/public/', $this->getDiskPrefix('public'));
- $this->assertSame('tenant' . tenant('id') . '/', ltrim($this->getDiskPrefix('s3'), '/'));
+ $this->assertSame('tenant' . tenant('id') . '/', $this->getDiskPrefix('s3'), '/');
// Check suffixing logic
$new_storage_path = storage_path();
diff --git a/tests/Etc/tmp/queuetest.json b/tests/Etc/tmp/queuetest.json
deleted file mode 100644
index e69de29b..00000000
From 600bb823de185ef02c3ff5aeba0c75f41409bafa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 23 Mar 2022 20:49:25 +0100
Subject: [PATCH 06/13] avoid double // in prefix
---
src/Bootstrappers/FilesystemTenancyBootstrapper.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Bootstrappers/FilesystemTenancyBootstrapper.php b/src/Bootstrappers/FilesystemTenancyBootstrapper.php
index dcd7299e..da1e5e2a 100644
--- a/src/Bootstrappers/FilesystemTenancyBootstrapper.php
+++ b/src/Bootstrappers/FilesystemTenancyBootstrapper.php
@@ -68,7 +68,7 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
if (! $finalPrefix) {
$finalPrefix = $originalRoot
- ? $originalRoot . '/'. $suffix
+ ? rtrim($originalRoot, '/') . '/'. $suffix
: $suffix;
}
From e1ae6f4380bf2062adfb44bc1acb83e603b95ed9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 23 Mar 2022 20:57:15 +0100
Subject: [PATCH 07/13] re-add queuetest.json
---
.gitignore | 1 -
tests/Etc/tmp/queuetest.json | 0
2 files changed, 1 deletion(-)
create mode 100644 tests/Etc/tmp/queuetest.json
diff --git a/.gitignore b/.gitignore
index b3223156..1d03dbec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,3 @@ psysh
phpunit_var_*.xml
coverage/
clover.xml
-tests/Etc/tmp/queuetest.json
diff --git a/tests/Etc/tmp/queuetest.json b/tests/Etc/tmp/queuetest.json
new file mode 100644
index 00000000..e69de29b
From 4e717236f9c1aa5d4e4aa588bace783d4d7bcde2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 23 Mar 2022 20:57:32 +0100
Subject: [PATCH 08/13] revert gitignore
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 1d03dbec..b3223156 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ psysh
phpunit_var_*.xml
coverage/
clover.xml
+tests/Etc/tmp/queuetest.json
From 4f196097979653fa7b7522ac339116d88b5baae4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 23 Mar 2022 20:58:47 +0100
Subject: [PATCH 09/13] remove docker-compose.override.yml
---
.gitignore | 1 +
docker-compose.override.yml | 5 -----
2 files changed, 1 insertion(+), 5 deletions(-)
delete mode 100644 docker-compose.override.yml
diff --git a/.gitignore b/.gitignore
index b3223156..f470ba75 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ phpunit_var_*.xml
coverage/
clover.xml
tests/Etc/tmp/queuetest.json
+docker-compose.override.yml
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
deleted file mode 100644
index 29e9fb37..00000000
--- a/docker-compose.override.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-services:
- mysql:
- platform: linux/amd64
- mysql2:
- platform: linux/amd64
From 349125c02ebe71216bfbbb4ea0c3b955e03ba474 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 30 Mar 2022 18:00:55 +0200
Subject: [PATCH 10/13] Merge hotfix branch (#834)
* try specifying the signature in __construct
* constructor doesn't work since Reflection is used, try specifying getDefaultName() instead
* Fixed: make migration commands compatible
* Fix failing tests
* Fix username generation
* Re-create tmp dir as well if needed
* wip
---
src/Commands/Migrate.php | 20 ++++++----------
src/Commands/MigrateFresh.php | 2 +-
src/Commands/Rollback.php | 11 ++++++---
src/Concerns/ExtendsLaravelCommand.php | 23 +++++++++++++++++++
src/Database/DatabaseManager.php | 10 +++++++-
src/Jobs/CreateDatabase.php | 2 +-
...rmissionControlledMySQLDatabaseManager.php | 5 ----
tests/DatabaseUsersTest.php | 9 ++++++--
tests/Etc/tmp/queuetest.json | 0
tests/QueueTest.php | 20 +++++++++++++++-
10 files changed, 75 insertions(+), 27 deletions(-)
create mode 100644 src/Concerns/ExtendsLaravelCommand.php
delete mode 100644 tests/Etc/tmp/queuetest.json
diff --git a/src/Commands/Migrate.php b/src/Commands/Migrate.php
index bf92dfcd..c67d3598 100644
--- a/src/Commands/Migrate.php
+++ b/src/Commands/Migrate.php
@@ -8,32 +8,26 @@ use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\Console\Migrations\MigrateCommand;
use Illuminate\Database\Migrations\Migrator;
use Stancl\Tenancy\Concerns\DealsWithMigrations;
+use Stancl\Tenancy\Concerns\ExtendsLaravelCommand;
use Stancl\Tenancy\Concerns\HasATenantsOption;
use Stancl\Tenancy\Events\DatabaseMigrated;
use Stancl\Tenancy\Events\MigratingDatabase;
class Migrate extends MigrateCommand
{
- use HasATenantsOption, DealsWithMigrations;
+ use HasATenantsOption, DealsWithMigrations, ExtendsLaravelCommand;
- /**
- * The console command description.
- *
- * @var string
- */
protected $description = 'Run migrations for tenant(s)';
- /**
- * Create a new command instance.
- *
- * @param Migrator $migrator
- * @param Dispatcher $dispatcher
- */
+ protected static function getTenantCommandName(): string
+ {
+ return 'tenants:migrate';
+ }
+
public function __construct(Migrator $migrator, Dispatcher $dispatcher)
{
parent::__construct($migrator, $dispatcher);
- $this->setName('tenants:migrate');
$this->specifyParameters();
}
diff --git a/src/Commands/MigrateFresh.php b/src/Commands/MigrateFresh.php
index 4d003db0..283d70b0 100644
--- a/src/Commands/MigrateFresh.php
+++ b/src/Commands/MigrateFresh.php
@@ -23,7 +23,7 @@ final class MigrateFresh extends Command
public function __construct()
{
parent::__construct();
-
+
$this->addOption('--drop-views', null, InputOption::VALUE_NONE, 'Drop views along with tenant tables.', null);
$this->setName('tenants:migrate-fresh');
diff --git a/src/Commands/Rollback.php b/src/Commands/Rollback.php
index 081872c8..e60d974b 100644
--- a/src/Commands/Rollback.php
+++ b/src/Commands/Rollback.php
@@ -7,13 +7,19 @@ namespace Stancl\Tenancy\Commands;
use Illuminate\Database\Console\Migrations\RollbackCommand;
use Illuminate\Database\Migrations\Migrator;
use Stancl\Tenancy\Concerns\DealsWithMigrations;
+use Stancl\Tenancy\Concerns\ExtendsLaravelCommand;
use Stancl\Tenancy\Concerns\HasATenantsOption;
use Stancl\Tenancy\Events\DatabaseRolledBack;
use Stancl\Tenancy\Events\RollingBackDatabase;
class Rollback extends RollbackCommand
{
- use HasATenantsOption, DealsWithMigrations;
+ use HasATenantsOption, DealsWithMigrations, ExtendsLaravelCommand;
+
+ protected static function getTenantCommandName(): string
+ {
+ return 'tenants:rollback';
+ }
/**
* The console command description.
@@ -31,8 +37,7 @@ class Rollback extends RollbackCommand
{
parent::__construct($migrator);
- $this->setName('tenants:rollback');
- $this->specifyParameters();
+ $this->specifyTenantSignature();
}
/**
diff --git a/src/Concerns/ExtendsLaravelCommand.php b/src/Concerns/ExtendsLaravelCommand.php
new file mode 100644
index 00000000..bdafc8f7
--- /dev/null
+++ b/src/Concerns/ExtendsLaravelCommand.php
@@ -0,0 +1,23 @@
+specifyParameters();
+ }
+
+ public function getName(): ?string
+ {
+ return static::getTenantCommandName();
+ }
+
+ public static function getDefaultName(): ?string
+ {
+ return static::getTenantCommandName();
+ }
+
+ abstract protected static function getTenantCommandName(): string;
+}
diff --git a/src/Database/DatabaseManager.php b/src/Database/DatabaseManager.php
index e85fd659..6242ffa9 100644
--- a/src/Database/DatabaseManager.php
+++ b/src/Database/DatabaseManager.php
@@ -7,10 +7,12 @@ namespace Stancl\Tenancy\Database;
use Illuminate\Config\Repository;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Database\DatabaseManager as BaseDatabaseManager;
+use Stancl\Tenancy\Contracts\ManagesDatabaseUsers;
use Stancl\Tenancy\Contracts\TenantCannotBeCreatedException;
use Stancl\Tenancy\Contracts\TenantWithDatabase;
use Stancl\Tenancy\Exceptions\DatabaseManagerNotRegisteredException;
use Stancl\Tenancy\Exceptions\TenantDatabaseAlreadyExistsException;
+use Stancl\Tenancy\Exceptions\TenantDatabaseUserAlreadyExistsException;
/**
* @internal Class is subject to breaking changes in minor and patch versions.
@@ -90,8 +92,14 @@ class DatabaseManager
*/
public function ensureTenantCanBeCreated(TenantWithDatabase $tenant): void
{
- if ($tenant->database()->manager()->databaseExists($database = $tenant->database()->getName())) {
+ $manager = $tenant->database()->manager();
+
+ if ($manager->databaseExists($database = $tenant->database()->getName())) {
throw new TenantDatabaseAlreadyExistsException($database);
}
+
+ if ($manager instanceof ManagesDatabaseUsers && $manager->userExists($username = $tenant->database()->getUsername())) {
+ throw new TenantDatabaseUserAlreadyExistsException($username);
+ }
}
}
diff --git a/src/Jobs/CreateDatabase.php b/src/Jobs/CreateDatabase.php
index 3a74534d..3cb2a6b4 100644
--- a/src/Jobs/CreateDatabase.php
+++ b/src/Jobs/CreateDatabase.php
@@ -36,8 +36,8 @@ class CreateDatabase implements ShouldQueue
return false;
}
- $databaseManager->ensureTenantCanBeCreated($this->tenant);
$this->tenant->database()->makeCredentials();
+ $databaseManager->ensureTenantCanBeCreated($this->tenant);
$this->tenant->database()->manager()->createDatabase($this->tenant);
event(new DatabaseCreated($this->tenant));
diff --git a/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php b/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
index f8bedc97..918601a8 100644
--- a/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
+++ b/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
@@ -7,7 +7,6 @@ namespace Stancl\Tenancy\TenantDatabaseManagers;
use Stancl\Tenancy\Concerns\CreatesDatabaseUsers;
use Stancl\Tenancy\Contracts\ManagesDatabaseUsers;
use Stancl\Tenancy\DatabaseConfig;
-use Stancl\Tenancy\Exceptions\TenantDatabaseUserAlreadyExistsException;
class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager implements ManagesDatabaseUsers
{
@@ -26,10 +25,6 @@ class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager impl
$hostname = $databaseConfig->connection()['host'];
$password = $databaseConfig->getPassword();
- if ($this->userExists($username)) {
- throw new TenantDatabaseUserAlreadyExistsException($username);
- }
-
$this->database()->statement("CREATE USER `{$username}`@`%` IDENTIFIED BY '{$password}'");
$grants = implode(', ', static::$grants);
diff --git a/tests/DatabaseUsersTest.php b/tests/DatabaseUsersTest.php
index 0b095024..344239d1 100644
--- a/tests/DatabaseUsersTest.php
+++ b/tests/DatabaseUsersTest.php
@@ -10,6 +10,7 @@ use Illuminate\Support\Str;
use Stancl\JobPipeline\JobPipeline;
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
use Stancl\Tenancy\Contracts\ManagesDatabaseUsers;
+use Stancl\Tenancy\Events\DatabaseCreated;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Exceptions\TenantDatabaseUserAlreadyExistsException;
@@ -67,14 +68,18 @@ class DatabaseUsersTest extends TestCase
$this->assertTrue($manager->databaseExists($tenant->database()->getName()));
$this->expectException(TenantDatabaseUserAlreadyExistsException::class);
+ Event::fake([DatabaseCreated::class]);
+
$tenant2 = Tenant::create([
'tenancy_db_username' => $username,
]);
/** @var ManagesDatabaseUsers $manager */
- $manager = $tenant2->database()->manager();
+ $manager2 = $tenant2->database()->manager();
+
// database was not created because of DB transaction
- $this->assertFalse($manager->databaseExists($tenant2->database()->getName()));
+ $this->assertFalse($manager2->databaseExists($tenant2->database()->getName()));
+ Event::assertNotDispatched(DatabaseCreated::class);
}
/** @test */
diff --git a/tests/Etc/tmp/queuetest.json b/tests/Etc/tmp/queuetest.json
deleted file mode 100644
index e69de29b..00000000
diff --git a/tests/QueueTest.php b/tests/QueueTest.php
index afe64fea..a3df9cd7 100644
--- a/tests/QueueTest.php
+++ b/tests/QueueTest.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Tests;
+use Closure;
use Exception;
use Illuminate\Support\Str;
use Illuminate\Bus\Queueable;
@@ -24,6 +25,7 @@ use Illuminate\Queue\Events\JobProcessed;
use Illuminate\Queue\Events\JobProcessing;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
+use PDO;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Listeners\BootstrapTenancy;
use Stancl\Tenancy\Listeners\RevertToCentralContext;
@@ -52,7 +54,7 @@ class QueueTest extends TestCase
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
Event::listen(TenancyEnded::class, RevertToCentralContext::class);
- $this->valuestore = Valuestore::make(__DIR__ . '/Etc/tmp/queuetest.json')->flush();
+ $this->createValueStore();
}
public function tearDown(): void
@@ -60,6 +62,22 @@ class QueueTest extends TestCase
$this->valuestore->flush();
}
+ protected function createValueStore(): void
+ {
+ $valueStorePath = __DIR__ . '/Etc/tmp/queuetest.json';
+
+ if (! file_exists($valueStorePath)) {
+ // The directory sometimes goes missing as well when the file is deleted in git
+ if (! is_dir(__DIR__ . '/Etc/tmp')) {
+ mkdir(__DIR__ . '/Etc/tmp');
+ }
+
+ file_put_contents($valueStorePath, '');
+ }
+
+ $this->valuestore = Valuestore::make($valueStorePath)->flush();
+ }
+
protected function withFailedJobs()
{
Schema::connection('central')->create('failed_jobs', function (Blueprint $table) {
From f065ea60b0e56c6a22cd75c476ca448649f8ffe2 Mon Sep 17 00:00:00 2001
From: Roy de Vos Burchart
Date: Fri, 1 Apr 2022 22:53:09 +0200
Subject: [PATCH 11/13] Update QueueTenancyBootstrapper.php (#836)
---
src/Bootstrappers/QueueTenancyBootstrapper.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Bootstrappers/QueueTenancyBootstrapper.php b/src/Bootstrappers/QueueTenancyBootstrapper.php
index 666e29ed..790e1344 100644
--- a/src/Bootstrappers/QueueTenancyBootstrapper.php
+++ b/src/Bootstrappers/QueueTenancyBootstrapper.php
@@ -63,8 +63,8 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper
static::initializeTenancyForQueue($event->job->payload()['tenant_id'] ?? null);
});
- if (Str::startsWith(app()->version(), '8')) {
- // JobRetryRequested only exists since Laravel 8
+ if (version_compare(app()->version(), '8.64', '>=')) {
+ // JobRetryRequested only exists since Laravel 8.64
$dispatcher->listen(JobRetryRequested::class, function ($event) use (&$previousTenant) {
$previousTenant = tenant();
From 40bf576e0087f3350fa5f91c2c73962a7dcdff50 Mon Sep 17 00:00:00 2001
From: Nathan Dunn
Date: Fri, 8 Apr 2022 02:13:29 +0100
Subject: [PATCH 12/13] [3.x] Update PostgreSQLSchemaManager to set correct
config key value (#840)
* Update PostgreSQLSchemaManager to set correct config key value
* Update to use version_compare
* Update TenantDatabaseManagerTest
* Improve TenantDatabaseManagerTest
* Update TenantDatabaseManager
---
src/TenantDatabaseManagers/PostgreSQLSchemaManager.php | 6 +++++-
tests/TenantDatabaseManagerTest.php | 6 +++++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php b/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php
index 9d815b25..55f049d0 100644
--- a/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php
+++ b/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php
@@ -46,7 +46,11 @@ class PostgreSQLSchemaManager implements TenantDatabaseManager
public function makeConnectionConfig(array $baseConfig, string $databaseName): array
{
- $baseConfig['schema'] = $databaseName;
+ if (version_compare(app()->version(), '9.0', '>=')) {
+ $baseConfig['search_path'] = $databaseName;
+ } else {
+ $baseConfig['schema'] = $databaseName;
+ }
return $baseConfig;
}
diff --git a/tests/TenantDatabaseManagerTest.php b/tests/TenantDatabaseManagerTest.php
index f64770b1..3d45d96f 100644
--- a/tests/TenantDatabaseManagerTest.php
+++ b/tests/TenantDatabaseManagerTest.php
@@ -194,7 +194,11 @@ class TenantDatabaseManagerTest extends TestCase
]);
tenancy()->initialize($tenant);
- $this->assertSame($tenant->database()->getName(), config('database.connections.' . config('database.default') . '.schema'));
+ $schemaConfig = version_compare(app()->version(), '9.0', '>=') ?
+ config('database.connections.' . config('database.default') . '.search_path') :
+ config('database.connections.' . config('database.default') . '.schema');
+
+ $this->assertSame($tenant->database()->getName(), $schemaConfig);
$this->assertSame($originalDatabaseName, config(['database.connections.pgsql.database']));
}
From 0569bf5a3495a194079540f8c7096ab6aac68117 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Sun, 1 May 2022 12:56:25 +0200
Subject: [PATCH 13/13] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f4d28288..95fb7c60 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
-
+