From db9480f54e98b33ca967bbe3f791c314e772386b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 1 Jun 2022 15:35:39 +0200
Subject: [PATCH 01/46] exclude master from CI
---
.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 cc8ad985..ed8ff9ac 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,9 +5,9 @@ env:
on:
push:
- branches: [ 3.x, 2.x, master ]
+ branches: [ 3.x, 2.x ]
pull_request:
- branches: [ 3.x, 2.x, master ]
+ branches: [ 3.x, 2.x ]
jobs:
tests:
From ba928100e6431ea0e5b770ba781d3eabbf240c9c Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Tue, 19 Jul 2022 16:11:47 +0200
Subject: [PATCH 02/46] Add space after 'up' in 'docker-compose up-d' (#900)
---
CONTRIBUTING.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a5a6ec3f..b4c862c1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -21,4 +21,4 @@ services:
platform: linux/amd64
```
-to `docker-compose.override.yml` to make `docker-compose up-d` work on M1.
+to `docker-compose.override.yml` to make `docker-compose up -d` work on M1.
From 747c192979aa03907824e5481edb6b152edc3462 Mon Sep 17 00:00:00 2001
From: Bram Wubs
Date: Wed, 20 Jul 2022 21:35:33 +0200
Subject: [PATCH 03/46] Fix ArgumentCountError on the TenantAssetsController
(#894)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Fix ArgumentCount exception on the TenantAssetsController when no `$path` is provided
* CS
* CS
* Handle null case explicitly
* code style
Co-authored-by: Bram Wubs
Co-authored-by: Samuel Štancl
---
src/Controllers/TenantAssetsController.php | 7 +++++--
tests/TenantAssetTest.php | 15 +++++++++++++++
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/src/Controllers/TenantAssetsController.php b/src/Controllers/TenantAssetsController.php
index 67478cf9..5549da0d 100644
--- a/src/Controllers/TenantAssetsController.php
+++ b/src/Controllers/TenantAssetsController.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Controllers;
use Illuminate\Routing\Controller;
+use Throwable;
class TenantAssetsController extends Controller
{
@@ -15,11 +16,13 @@ class TenantAssetsController extends Controller
$this->middleware(static::$tenancyMiddleware);
}
- public function asset($path)
+ public function asset($path = null)
{
+ abort_if($path === null, 404);
+
try {
return response()->file(storage_path("app/public/$path"));
- } catch (\Throwable $th) {
+ } catch (Throwable $th) {
abort(404);
}
}
diff --git a/tests/TenantAssetTest.php b/tests/TenantAssetTest.php
index 77a130b4..703ac65e 100644
--- a/tests/TenantAssetTest.php
+++ b/tests/TenantAssetTest.php
@@ -126,4 +126,19 @@ class TenantAssetTest extends TestCase
$this->assertSame($original, asset('foo'));
}
+
+ public function test_asset_controller_returns_a_404_when_no_path_is_provided()
+ {
+ TenantAssetsController::$tenancyMiddleware = InitializeTenancyByRequestData::class;
+
+ $tenant = Tenant::create();
+
+ tenancy()->initialize($tenant);
+ $response = $this->get(tenant_asset(null), [
+ 'X-Tenant' => $tenant->id,
+ ]);
+
+ $response->assertNotFound();
+ }
+
}
From 1ea3cefa1d1499211e8659a0b2e050b05ff0c4fe Mon Sep 17 00:00:00 2001
From: George Bishop
Date: Sun, 21 Aug 2022 15:43:01 +0100
Subject: [PATCH 04/46] Add support for nested tenant config override (#920)
* feat: add support for nested tenant config override
* test: ensure nested tenant values are mapped
---
src/Features/TenantConfig.php | 3 ++-
tests/Features/TenantConfigTest.php | 24 ++++++++++++++++++++++++
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/src/Features/TenantConfig.php b/src/Features/TenantConfig.php
index fb09a871..95691f0d 100644
--- a/src/Features/TenantConfig.php
+++ b/src/Features/TenantConfig.php
@@ -6,6 +6,7 @@ namespace Stancl\Tenancy\Features;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Event;
use Stancl\Tenancy\Contracts\Feature;
use Stancl\Tenancy\Contracts\Tenant;
@@ -45,7 +46,7 @@ class TenantConfig implements Feature
{
/** @var Tenant|Model $tenant */
foreach (static::$storageToConfigMap as $storageKey => $configKey) {
- $override = $tenant->getAttribute($storageKey);
+ $override = Arr::get($tenant, $storageKey);
if (! is_null($override)) {
if (is_array($configKey)) {
diff --git a/tests/Features/TenantConfigTest.php b/tests/Features/TenantConfigTest.php
index 37e26198..904e420b 100644
--- a/tests/Features/TenantConfigTest.php
+++ b/tests/Features/TenantConfigTest.php
@@ -22,6 +22,30 @@ class TenantConfigTest extends TestCase
parent::tearDown();
}
+ /** @test */
+ public function nested_tenant_values_are_merged()
+ {
+ $this->assertSame(null, config('whitelabel.theme'));
+ config([
+ 'tenancy.features' => [TenantConfig::class],
+ 'tenancy.bootstrappers' => [],
+ ]);
+ Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
+ Event::listen(TenancyEnded::class, RevertToCentralContext::class);
+
+ TenantConfig::$storageToConfigMap = [
+ 'whitelabel.config.theme' => 'whitelabel.theme',
+ ];
+
+ $tenant = Tenant::create([
+ 'whitelabel' => ['config' => ['theme' => 'dark']],
+ ]);
+
+ tenancy()->initialize($tenant);
+ $this->assertSame('dark', config('whitelabel.theme'));
+ tenancy()->end();
+ }
+
/** @test */
public function config_is_merged_and_removed()
{
From 38fc706c97291bccaa4619a8480ab69173f13c37 Mon Sep 17 00:00:00 2001
From: Anbuselvan Rocky <15264938+anburocky3@users.noreply.github.com>
Date: Thu, 22 Sep 2022 21:54:01 +0530
Subject: [PATCH 05/46] fix: typo mistake (#954)
---
assets/config.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assets/config.php b/assets/config.php
index 85592d14..891bc64c 100644
--- a/assets/config.php
+++ b/assets/config.php
@@ -139,7 +139,7 @@ return [
],
/**
- * Redis tenancy config. Used by RedisTenancyBoostrapper.
+ * Redis tenancy config. Used by RedisTenancyBootstrapper.
*
* Note: You need phpredis to use Redis tenancy.
*
From d093c1387d5d189ebae1d6a68e88108bbc0110e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Wilsen=20Hern=C3=A1ndez?=
<13445515+wilsenhc@users.noreply.github.com>
Date: Tue, 27 Sep 2022 22:28:30 -0400
Subject: [PATCH 06/46] [3.x] Add Vite helper for tenancy (#956)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add Vite helper for tenancy
* Move Vite bundler to an Optional Feature
* Rename to foundation vite
* Add ViteBundlerTest
* Add missing end of file
* Update tests
* remove unnecessary end() call
Co-authored-by: Samuel Štancl
---
assets/config.php | 1 +
src/Features/ViteBundler.php | 21 ++++++++++++++++++++
src/TenancyServiceProvider.php | 1 +
src/Vite.php | 20 +++++++++++++++++++
tests/Features/ViteBundlerTest.php | 32 ++++++++++++++++++++++++++++++
5 files changed, 75 insertions(+)
create mode 100644 src/Features/ViteBundler.php
create mode 100644 src/Vite.php
create mode 100644 tests/Features/ViteBundlerTest.php
diff --git a/assets/config.php b/assets/config.php
index 891bc64c..b12cd6c4 100644
--- a/assets/config.php
+++ b/assets/config.php
@@ -168,6 +168,7 @@ return [
// Stancl\Tenancy\Features\UniversalRoutes::class,
// Stancl\Tenancy\Features\TenantConfig::class, // https://tenancyforlaravel.com/docs/v3/features/tenant-config
// Stancl\Tenancy\Features\CrossDomainRedirect::class, // https://tenancyforlaravel.com/docs/v3/features/cross-domain-redirect
+ // Stancl\Tenancy\Features\ViteBundler::class,
],
/**
diff --git a/src/Features/ViteBundler.php b/src/Features/ViteBundler.php
new file mode 100644
index 00000000..76b96a48
--- /dev/null
+++ b/src/Features/ViteBundler.php
@@ -0,0 +1,21 @@
+app->singleton(FoundationVite::class, StanclVite::class);
+ }
+}
diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php
index 4faaccf3..dec8c72e 100644
--- a/src/TenancyServiceProvider.php
+++ b/src/TenancyServiceProvider.php
@@ -65,6 +65,7 @@ class TenancyServiceProvider extends ServiceProvider
$this->app->singleton(Commands\Rollback::class, function ($app) {
return new Commands\Rollback($app['migrator']);
});
+
$this->app->singleton(Commands\Seed::class, function ($app) {
return new Commands\Seed($app['db']);
});
diff --git a/src/Vite.php b/src/Vite.php
new file mode 100644
index 00000000..2598a2e4
--- /dev/null
+++ b/src/Vite.php
@@ -0,0 +1,20 @@
+toBeInstanceOf(FoundationVite::class);
+
+ expect($vite)->not->toBeInstanceOf(StanclVite::class);
+
+ config([
+ 'tenancy.features' => [ViteBundler::class],
+ ]);
+
+ $tenant = Tenant::create();
+
+ tenancy()->initialize($tenant);
+
+ app()->forgetInstance(\Illuminate\Foundation\Vite::class);
+
+ $vite = app(\Illuminate\Foundation\Vite::class);
+
+ expect($vite)->toBeInstanceOf(StanclVite::class);
+});
From ab2af5b38847de3ed79f16b2165d5e48512309ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 28 Sep 2022 16:43:20 +0200
Subject: [PATCH 07/46] rewrite ViteBundlerTest to phpunit syntax
---
tests/Features/ViteBundlerTest.php | 35 ++++++++++++++++--------------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/tests/Features/ViteBundlerTest.php b/tests/Features/ViteBundlerTest.php
index 8d9ba61d..6b9208be 100644
--- a/tests/Features/ViteBundlerTest.php
+++ b/tests/Features/ViteBundlerTest.php
@@ -3,30 +3,33 @@
declare(strict_types=1);
use Illuminate\Foundation\Vite as FoundationVite;
-use Illuminate\Support\Facades\App;
use Stancl\Tenancy\Features\ViteBundler;
use Stancl\Tenancy\Tests\Etc\Tenant;
+use Stancl\Tenancy\Tests\TestCase;
use Stancl\Tenancy\Vite as StanclVite;
+class ViteBundlerTest extends TestCase
+{
+ /** @test */
+ public function the_vite_helper_uses_our_custom_class()
+ {
+ $vite = app(\Illuminate\Foundation\Vite::class);
-test('replaces the vite helper instance with custom class', function () {
- $vite = app(\Illuminate\Foundation\Vite::class);
+ $this->assertInstanceOf(FoundationVite::class, $vite);
+ $this->assertNotInstanceOf(StanclVite::class, $vite);
- expect($vite)->toBeInstanceOf(FoundationVite::class);
+ config([
+ 'tenancy.features' => [ViteBundler::class],
+ ]);
- expect($vite)->not->toBeInstanceOf(StanclVite::class);
+ $tenant = Tenant::create();
- config([
- 'tenancy.features' => [ViteBundler::class],
- ]);
+ tenancy()->initialize($tenant);
- $tenant = Tenant::create();
+ app()->forgetInstance(\Illuminate\Foundation\Vite::class);
- tenancy()->initialize($tenant);
+ $vite = app(\Illuminate\Foundation\Vite::class);
- app()->forgetInstance(\Illuminate\Foundation\Vite::class);
-
- $vite = app(\Illuminate\Foundation\Vite::class);
-
- expect($vite)->toBeInstanceOf(StanclVite::class);
-});
+ $this->assertInstanceOf(StanclVite::class, $vite);
+ }
+}
From 8ecdb49531741e831bb34aa4305b81cd3de0d414 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 28 Sep 2022 16:49:41 +0200
Subject: [PATCH 08/46] skip vite test in Laravel < 9
---
tests/Features/ViteBundlerTest.php | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tests/Features/ViteBundlerTest.php b/tests/Features/ViteBundlerTest.php
index 6b9208be..90e06d78 100644
--- a/tests/Features/ViteBundlerTest.php
+++ b/tests/Features/ViteBundlerTest.php
@@ -13,6 +13,10 @@ class ViteBundlerTest extends TestCase
/** @test */
public function the_vite_helper_uses_our_custom_class()
{
+ if (version_compare(app()->version(), '9.0', '<')) {
+ $this->markTestSkipped('Vite is only used in Laravel 9+');
+ }
+
$vite = app(\Illuminate\Foundation\Vite::class);
$this->assertInstanceOf(FoundationVite::class, $vite);
From 6d599de0672a1bab6ad739111ac286abb0b1b15b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 28 Sep 2022 17:06:05 +0200
Subject: [PATCH 09/46] convert ViteBundler to PHP 7 syntax
---
src/Features/ViteBundler.php | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/Features/ViteBundler.php b/src/Features/ViteBundler.php
index 76b96a48..928de8f5 100644
--- a/src/Features/ViteBundler.php
+++ b/src/Features/ViteBundler.php
@@ -12,7 +12,12 @@ use Stancl\Tenancy\Vite as StanclVite;
class ViteBundler implements Feature
{
- public function __construct(protected Application $app) { }
+ protected Application $app;
+
+ public function __construct(Application $app)
+ {
+ $this->app = $app;
+ }
public function bootstrap(Tenancy $tenancy): void
{
From d31a319cc7fc29fc1c92e5beccb951c3ae8ce51a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 28 Sep 2022 17:11:35 +0200
Subject: [PATCH 10/46] remove import of nonexistent class in older Laravel
versions
---
src/Features/ViteBundler.php | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/Features/ViteBundler.php b/src/Features/ViteBundler.php
index 928de8f5..f50510e4 100644
--- a/src/Features/ViteBundler.php
+++ b/src/Features/ViteBundler.php
@@ -5,10 +5,9 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Features;
use Illuminate\Foundation\Application;
-use Illuminate\Foundation\Vite as FoundationVite;
use Stancl\Tenancy\Contracts\Feature;
use Stancl\Tenancy\Tenancy;
-use Stancl\Tenancy\Vite as StanclVite;
+use Stancl\Tenancy\Vite;
class ViteBundler implements Feature
{
@@ -21,6 +20,6 @@ class ViteBundler implements Feature
public function bootstrap(Tenancy $tenancy): void
{
- $this->app->singleton(FoundationVite::class, StanclVite::class);
+ $this->app->singleton(\Illuminate\Foundation\Vite::class, Vite::class);
}
}
From 596c47329a14533ff48a84afbed16d98fcf7296f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 28 Sep 2022 17:17:21 +0200
Subject: [PATCH 11/46] remove import of Foundation\Vite in tests
---
tests/Features/ViteBundlerTest.php | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tests/Features/ViteBundlerTest.php b/tests/Features/ViteBundlerTest.php
index 90e06d78..b544bcac 100644
--- a/tests/Features/ViteBundlerTest.php
+++ b/tests/Features/ViteBundlerTest.php
@@ -2,7 +2,6 @@
declare(strict_types=1);
-use Illuminate\Foundation\Vite as FoundationVite;
use Stancl\Tenancy\Features\ViteBundler;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Stancl\Tenancy\Tests\TestCase;
@@ -19,7 +18,7 @@ class ViteBundlerTest extends TestCase
$vite = app(\Illuminate\Foundation\Vite::class);
- $this->assertInstanceOf(FoundationVite::class, $vite);
+ $this->assertInstanceOf(\Illuminate\Foundation\Vite::class, $vite);
$this->assertNotInstanceOf(StanclVite::class, $vite);
config([
From a2c53b58ba8ed15b6710f85f8c57d010da462257 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 28 Sep 2022 18:43:39 +0200
Subject: [PATCH 12/46] try to exclude Vite.php from coverage report
---
phpunit.xml | 3 ++-
src/Vite.php | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/phpunit.xml b/phpunit.xml
index 28fc8a08..934fd431 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -18,6 +18,7 @@
./src
./src/routes.php
+ ./src/Vite.php
@@ -35,4 +36,4 @@
-
\ No newline at end of file
+
diff --git a/src/Vite.php b/src/Vite.php
index 2598a2e4..1887361a 100644
--- a/src/Vite.php
+++ b/src/Vite.php
@@ -4,7 +4,7 @@ namespace Stancl\Tenancy;
use Illuminate\Foundation\Vite as BaseVite;
-class Vite extends BaseVite
+class Vite extends BaseVite // todo move to a different directory in v4
{
/**
* Generate an asset path for the application.
From 437a8ed05ceeb00f886202f1b04dd8f9757175ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Wed, 28 Sep 2022 18:50:09 +0200
Subject: [PATCH 13/46] remove typehint
---
src/Features/ViteBundler.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/Features/ViteBundler.php b/src/Features/ViteBundler.php
index f50510e4..e3fee2fa 100644
--- a/src/Features/ViteBundler.php
+++ b/src/Features/ViteBundler.php
@@ -11,7 +11,8 @@ use Stancl\Tenancy\Vite;
class ViteBundler implements Feature
{
- protected Application $app;
+ /** @var Application */
+ protected $app;
public function __construct(Application $app)
{
From 84a32877994bfd2ed303240f9e24709c74c809e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Thu, 29 Sep 2022 16:49:12 +0200
Subject: [PATCH 14/46] update channel name
---
SUPPORT.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SUPPORT.md b/SUPPORT.md
index b7caaa5c..f85a21a9 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -1,5 +1,5 @@
# Get Support
-If you need help with implementing the package, you can join our community [Discord server](https://discord.gg/7cpgPxv) and ask in `#help`.
+If you need help with implementing the package, you can join our community [Discord server](https://archte.ch/discord) and ask in `#tenancy-help`.
If you're interested in paid consulting from the maintainer, see the [contact page](https://tenancyforlaravel.com/contact/) on our website.
From 26b856976132ecbeff8b2d84c90f8acba7a874c0 Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Fri, 27 Jan 2023 08:17:14 +0100
Subject: [PATCH 15/46] Cache crash fix (#1048)
---
src/Resolvers/Contracts/CachedTenantResolver.php | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/Resolvers/Contracts/CachedTenantResolver.php b/src/Resolvers/Contracts/CachedTenantResolver.php
index 968ac794..feb9609c 100644
--- a/src/Resolvers/Contracts/CachedTenantResolver.php
+++ b/src/Resolvers/Contracts/CachedTenantResolver.php
@@ -36,9 +36,7 @@ abstract class CachedTenantResolver implements TenantResolver
$key = $this->getCacheKey(...$args);
- if ($this->cache->has($key)) {
- $tenant = $this->cache->get($key);
-
+ if ($tenant = $this->cache->get($key)) {
$this->resolved($tenant, ...$args);
return $tenant;
From 7d59ff180fbac386774829f3f2d887889250a4f6 Mon Sep 17 00:00:00 2001
From: Joel Stein
Date: Tue, 31 Jan 2023 23:24:53 -0600
Subject: [PATCH 16/46] Don't prevent accessing missing Tenant attributes.
(#1045)
---
src/Database/Models/Tenant.php | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/Database/Models/Tenant.php b/src/Database/Models/Tenant.php
index 4ec685b7..ecc5dbc4 100644
--- a/src/Database/Models/Tenant.php
+++ b/src/Database/Models/Tenant.php
@@ -28,6 +28,8 @@ class Tenant extends Model implements Contracts\Tenant
Concerns\TenantRun,
Concerns\InvalidatesResolverCache;
+ protected static $modelsShouldPreventAccessingMissingAttributes = false;
+
protected $table = 'tenants';
protected $primaryKey = 'id';
protected $guarded = [];
From d4a99011e602cde65e708b67046d4c4cb13749b6 Mon Sep 17 00:00:00 2001
From: Guilherme Saade
Date: Thu, 16 Feb 2023 13:21:06 -0300
Subject: [PATCH 17/46] [3.x] L10 compatibility (#1065)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Bump dependencies for Laravel 10
* Update GitHub Actions for Laravel 10
* ci: do not test L10 using PHP 7.3
* drop < L9 support
* use `dispatch_sync` instead of `dispatch_now`
* migrate phpunit configuration
* Update ci.yml
* drop laravel < 9 support
* misc L10 fixes, new docker image
* specify odbc version
* wip
* properly list php versions as strings
* minor changes
* Add `getValue($queryGrammar)` to raw query
* Clean up `isVersion8` code
* rewrite hasFailed assertion
* phpunit schema update
* Upgrade `doctrine/dbal`
---------
Co-authored-by: Samuel Štancl
Co-authored-by: Samuel Štancl
Co-authored-by: lukinovec
---
.github/workflows/ci.yml | 16 ++---
Dockerfile | 68 ++++++++-----------
composer.json | 28 +++++---
docker-compose-m1.override.yml | 7 ++
phpunit.xml | 67 ++++++++----------
.../QueueTenancyBootstrapper.php | 11 ++-
src/Database/Models/ImpersonationToken.php | 4 +-
...rmissionControlledMySQLDatabaseManager.php | 3 +-
.../PostgreSQLSchemaManager.php | 6 +-
test | 1 +
tests/BootstrapperTest.php | 4 --
tests/EventListenerTest.php | 7 +-
tests/Features/ViteBundlerTest.php | 4 --
tests/QueueTest.php | 4 --
tests/TenantDatabaseManagerTest.php | 6 +-
15 files changed, 108 insertions(+), 128 deletions(-)
create mode 100644 docker-compose-m1.override.yml
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ed8ff9ac..0272d86c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,9 +5,9 @@ env:
on:
push:
- branches: [ 3.x, 2.x ]
+ branches: [ 3.x ]
pull_request:
- branches: [ 3.x, 2.x ]
+ branches: [ 3.x ]
jobs:
tests:
@@ -15,17 +15,17 @@ jobs:
strategy:
matrix:
- php: ["7.3", "8.0"]
- laravel: ["^6.0", "^8.0", "^9.0"]
- exclude:
- - laravel: "^9.0"
- php: "7.3"
+ include:
+ - laravel: 9
+ php: "8.0"
+ - laravel: 10
+ php: "8.1"
steps:
- uses: actions/checkout@v2
- name: Start docker containers
run: PHP_VERSION=${{ matrix.php }} docker-compose up -d
- name: Install dependencies
- run: docker-compose exec -T test composer require --no-interaction "laravel/framework:${{ matrix.laravel }}"
+ run: docker-compose exec -T test composer require --no-interaction "laravel/framework:^${{ matrix.laravel }}.0"
- name: Run tests
run: ./test
diff --git a/Dockerfile b/Dockerfile
index 36f52d6a..6a66bde2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,50 +1,42 @@
-ARG PHP_VERSION=7.4
-ARG PHP_TARGET=php:${PHP_VERSION}-cli
+# add amd64 platform to support Mac M1
+FROM --platform=linux/amd64 shivammathur/node:latest-amd64
-FROM ${PHP_TARGET}
-
-ARG COMPOSER_TARGET=2.0.3
+ARG PHP_VERSION=8.1
WORKDIR /var/www/html
-LABEL org.opencontainers.image.source=https://github.com/stancl/tenancy \
- org.opencontainers.image.vendor="Samuel Štancl" \
- org.opencontainers.image.licenses="MIT" \
- org.opencontainers.image.title="PHP ${PHP_VERSION} with modules for laravel support" \
- org.opencontainers.image.description="PHP ${PHP_VERSION} with a set of php/os packages suitable for running Laravel apps"
-
# our default timezone and langauge
ENV TZ=Europe/London
ENV LANG=en_GB.UTF-8
-# Note: we only install reliable/core 1st-party php extensions here.
-# If your app needs custom ones install them in the apps own
-# Dockerfile _and pin the versions_! Eg:
-# RUN pecl install memcached-2.2.0 && docker-php-ext-enable memcached
+# install MYSSQL ODBC Driver
+RUN apt-get update \
+ && apt-get install -y gnupg2 \
+ && curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - \
+ && curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > /etc/apt/sources.list.d/mssql-release.list \
+ && apt-get update \
+ && ACCEPT_EULA=Y apt-get install -y unixodbc-dev=2.3.7 unixodbc=2.3.7 odbcinst1debian2=2.3.7 odbcinst=2.3.7 msodbcsql17
+
+# set PHP version
+RUN update-alternatives --set php /usr/bin/php$PHP_VERSION \
+ && update-alternatives --set phar /usr/bin/phar$PHP_VERSION \
+ && update-alternatives --set phar.phar /usr/bin/phar.phar$PHP_VERSION \
+ && update-alternatives --set phpize /usr/bin/phpize$PHP_VERSION \
+ && update-alternatives --set php-config /usr/bin/php-config$PHP_VERSION
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends libhiredis0.14 libjemalloc2 liblua5.1-0 lua-bitop lua-cjson redis redis-server redis-tools
+
+RUN pecl install redis-5.3.7 sqlsrv pdo_sqlsrv pcov \
+ && printf "; priority=20\nextension=redis.so\n" > /etc/php/$PHP_VERSION/mods-available/redis.ini \
+ && printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/$PHP_VERSION/mods-available/sqlsrv.ini \
+ && printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/$PHP_VERSION/mods-available/pdo_sqlsrv.ini \
+ && printf "; priority=40\nextension=pcov.so\n" > /etc/php/$PHP_VERSION/mods-available/pcov.ini \
+ && phpenmod -v $PHP_VERSION redis sqlsrv pdo_sqlsrv pcov
+
+# install composer
+COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
-# install some OS packages we need
-RUN apt-get update
-RUN apt-get install -y --no-install-recommends libfreetype6-dev libjpeg62-turbo-dev libpng-dev libgmp-dev libldap2-dev netcat curl sqlite3 libsqlite3-dev libpq-dev libzip-dev unzip vim-tiny gosu git
- # install php extensions
-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.7 \
- && docker-php-ext-enable redis \
- # install the pcov extention
- && pecl install pcov \
- && docker-php-ext-enable pcov \
- && echo "pcov.enabled = 1" > /usr/local/etc/php/conf.d/pcov.ini
-# clear the apt cache
-RUN rm -rf /var/lib/apt/lists/* \
- && rm -rf /var/lib/apt/lists/* \
- # install composer
- && curl -o /tmp/composer-setup.php https://getcomposer.org/installer \
- && curl -o /tmp/composer-setup.sig https://composer.github.io/installer.sig \
- && php -r "if (hash('SHA384', file_get_contents('/tmp/composer-setup.php')) !== trim(file_get_contents('/tmp/composer-setup.sig'))) { unlink('/tmp/composer-setup.php'); echo 'Invalid installer' . PHP_EOL; exit(1); }" \
- && php /tmp/composer-setup.php --version=${COMPOSER_TARGET} --no-ansi --install-dir=/usr/local/bin --filename=composer --snapshot \
- && rm -f /tmp/composer-setup.*
# set the system timezone
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone
diff --git a/composer.json b/composer.json
index 88bfea29..66dceafe 100644
--- a/composer.json
+++ b/composer.json
@@ -10,19 +10,20 @@
}
],
"require": {
+ "php": "^8.0",
"ext-json": "*",
- "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"
+ "illuminate/support": "^9.0|^10.0",
+ "facade/ignition-contracts": "^1.0.2",
+ "ramsey/uuid": "^4.7.3",
+ "stancl/jobpipeline": "^1.6.2",
+ "stancl/virtualcolumn": "^1.3.1"
},
"require-dev": {
- "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"
+ "laravel/framework": "^9.0|^10.0",
+ "orchestra/testbench": "^7.0|^8.0",
+ "league/flysystem-aws-s3-v3": "^3.12.2",
+ "doctrine/dbal": "^3.6.0",
+ "spatie/valuestore": "^1.3.2"
},
"autoload": {
"psr-4": {
@@ -49,5 +50,10 @@
}
},
"minimum-stability": "dev",
- "prefer-stable": true
+ "prefer-stable": true,
+ "config": {
+ "allow-plugins": {
+ "pestphp/pest-plugin": true
+ }
+ }
}
diff --git a/docker-compose-m1.override.yml b/docker-compose-m1.override.yml
new file mode 100644
index 00000000..32e163e6
--- /dev/null
+++ b/docker-compose-m1.override.yml
@@ -0,0 +1,7 @@
+services:
+ mysql:
+ platform: linux/amd64
+ mysql2:
+ platform: linux/amd64
+ mssql:
+ image: mcr.microsoft.com/azure-sql-edge
diff --git a/phpunit.xml b/phpunit.xml
index 934fd431..19989e03 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,39 +1,32 @@
-
-
-
- ./tests
-
-
-
-
- ./src
-
- ./src/routes.php
- ./src/Vite.php
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ ./src
+
+
+ ./src/routes.php
+ ./src/Vite.php
+
+
+
+
+
+
+
+
+ ./tests
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Bootstrappers/QueueTenancyBootstrapper.php b/src/Bootstrappers/QueueTenancyBootstrapper.php
index 790e1344..f747faea 100644
--- a/src/Bootstrappers/QueueTenancyBootstrapper.php
+++ b/src/Bootstrappers/QueueTenancyBootstrapper.php
@@ -63,14 +63,11 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper
static::initializeTenancyForQueue($event->job->payload()['tenant_id'] ?? null);
});
- if (version_compare(app()->version(), '8.64', '>=')) {
- // JobRetryRequested only exists since Laravel 8.64
- $dispatcher->listen(JobRetryRequested::class, function ($event) use (&$previousTenant) {
- $previousTenant = tenant();
+ $dispatcher->listen(JobRetryRequested::class, function ($event) use (&$previousTenant) {
+ $previousTenant = tenant();
- static::initializeTenancyForQueue($event->payload()['tenant_id'] ?? null);
- });
- }
+ static::initializeTenancyForQueue($event->payload()['tenant_id'] ?? null);
+ });
// If we're running tests, we make sure to clean up after any artisan('queue:work') calls
$revertToPreviousState = function ($event) use (&$previousTenant, $runningTests) {
diff --git a/src/Database/Models/ImpersonationToken.php b/src/Database/Models/ImpersonationToken.php
index 4aa63252..0de48060 100644
--- a/src/Database/Models/ImpersonationToken.php
+++ b/src/Database/Models/ImpersonationToken.php
@@ -26,8 +26,8 @@ class ImpersonationToken extends Model
protected $primaryKey = 'token';
public $incrementing = false;
protected $table = 'tenant_user_impersonation_tokens';
- protected $dates = [
- 'created_at',
+ protected $casts = [
+ 'created_at' => 'datetime',
];
public static function boot()
diff --git a/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php b/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
index 918601a8..df23ed1f 100644
--- a/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
+++ b/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
@@ -40,7 +40,8 @@ class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager impl
protected function isVersion8(): bool
{
- $version = $this->database()->select($this->database()->raw('select version()'))[0]->{'version()'};
+ $versionSelect = $this->database()->raw('select version()')->getValue($this->database()->getQueryGrammar());
+ $version = $this->database()->select($versionSelect)[0]->{'version()'};
return version_compare($version, '8.0.0') >= 0;
}
diff --git a/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php b/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php
index 55f049d0..53607bdb 100644
--- a/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php
+++ b/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php
@@ -46,11 +46,7 @@ class PostgreSQLSchemaManager implements TenantDatabaseManager
public function makeConnectionConfig(array $baseConfig, string $databaseName): array
{
- if (version_compare(app()->version(), '9.0', '>=')) {
- $baseConfig['search_path'] = $databaseName;
- } else {
- $baseConfig['schema'] = $databaseName;
- }
+ $baseConfig['search_path'] = $databaseName;
return $baseConfig;
}
diff --git a/test b/test
index 49535a7a..e064bbfe 100755
--- a/test
+++ b/test
@@ -1,3 +1,4 @@
#!/bin/bash
+cat vendor/laravel/framework/src/Illuminate/Foundation/Application.php | grep 'const VERSION'
docker-compose exec -T test vendor/bin/phpunit "$@"
diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php
index 588fadd8..6f9cc493 100644
--- a/tests/BootstrapperTest.php
+++ b/tests/BootstrapperTest.php
@@ -207,10 +207,6 @@ class BootstrapperTest extends TestCase
$disk = Storage::disk($disk);
$adapter = $disk->getAdapter();
- if (! Str::startsWith(app()->version(), '9.')) {
- return $adapter->getPathPrefix();
- }
-
$prefixer = (new ReflectionObject($adapter))->getProperty('prefixer');
$prefixer->setAccessible(true);
diff --git a/tests/EventListenerTest.php b/tests/EventListenerTest.php
index 4a45205c..759e330c 100644
--- a/tests/EventListenerTest.php
+++ b/tests/EventListenerTest.php
@@ -94,7 +94,7 @@ class EventListenerTest extends TestCase
});
$tenant = Tenant::create();
- dispatch_now(new CreateDatabase($tenant));
+ dispatch_sync(new CreateDatabase($tenant));
$this->assertFalse($tenant->database()->manager()->databaseExists(
$tenant->database()->getName()
@@ -192,12 +192,13 @@ class EventListenerTest extends TestCase
})->toListener()
);
- Tenant::create([
+ $tenant = Tenant::create([
'tenancy_create_database' => false,
'tenancy_db_name' => 'already_created',
]);
- $this->assertFalse($this->hasFailed());
+ // assert test didn't fail
+ $this->assertTrue($tenant->exists());
}
}
diff --git a/tests/Features/ViteBundlerTest.php b/tests/Features/ViteBundlerTest.php
index b544bcac..23cf164d 100644
--- a/tests/Features/ViteBundlerTest.php
+++ b/tests/Features/ViteBundlerTest.php
@@ -12,10 +12,6 @@ class ViteBundlerTest extends TestCase
/** @test */
public function the_vite_helper_uses_our_custom_class()
{
- if (version_compare(app()->version(), '9.0', '<')) {
- $this->markTestSkipped('Vite is only used in Laravel 9+');
- }
-
$vite = app(\Illuminate\Foundation\Vite::class);
$this->assertInstanceOf(\Illuminate\Foundation\Vite::class, $vite);
diff --git a/tests/QueueTest.php b/tests/QueueTest.php
index a3df9cd7..373e54a4 100644
--- a/tests/QueueTest.php
+++ b/tests/QueueTest.php
@@ -197,10 +197,6 @@ class QueueTest extends TestCase
*/
public function tenancy_is_initialized_when_retrying_jobs(bool $shouldEndTenancy)
{
- if (! Str::startsWith(app()->version(), '8')) {
- $this->markTestSkipped('queue:retry tenancy is only supported in Laravel 8');
- }
-
$this->withFailedJobs();
$this->withTenantDatabases();
diff --git a/tests/TenantDatabaseManagerTest.php b/tests/TenantDatabaseManagerTest.php
index 3d45d96f..6051ee12 100644
--- a/tests/TenantDatabaseManagerTest.php
+++ b/tests/TenantDatabaseManagerTest.php
@@ -95,7 +95,7 @@ class TenantDatabaseManagerTest extends TestCase
$this->assertTrue($postgresManager->databaseExists($database));
}
- public function database_manager_provider()
+ public static function database_manager_provider()
{
return [
['mysql', MySQLDatabaseManager::class],
@@ -194,9 +194,7 @@ class TenantDatabaseManagerTest extends TestCase
]);
tenancy()->initialize($tenant);
- $schemaConfig = version_compare(app()->version(), '9.0', '>=') ?
- config('database.connections.' . config('database.default') . '.search_path') :
- config('database.connections.' . config('database.default') . '.schema');
+ $schemaConfig = config('database.connections.' . config('database.default') . '.search_path');
$this->assertSame($tenant->database()->getName(), $schemaConfig);
$this->assertSame($originalDatabaseName, config(['database.connections.pgsql.database']));
From 4aa0feaa432493e52a8ceccc973ddfc52cce54b1 Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Mon, 20 Feb 2023 09:27:26 +0100
Subject: [PATCH 18/46] Update ci.yml
---
.github/workflows/ci.yml | 109 +++++++++++++++++++++++++++++++++++----
1 file changed, 100 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 744bb91e..3f46ce64 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,16 +16,107 @@ jobs:
strategy:
matrix:
include:
- - laravel: 9
+ - laravel: "9.0"
php: "8.0"
- - laravel: 10
+ - laravel: "10.0"
php: "8.1"
steps:
- - uses: actions/checkout@v2
- - name: Start docker containers
- run: PHP_VERSION=${{ matrix.php }} docker-compose up -d
- - name: Install dependencies
- run: docker-compose exec -T test composer require --no-interaction "laravel/framework:^${{ matrix.laravel }}.0"
- - name: Run tests
- run: ./test
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Install Composer dependencies
+ run: |
+ composer require "laravel/framework:^${{ matrix.laravel }}" --no-interaction --no-update
+ composer update --prefer-dist --no-interaction
+ - name: Run tests
+ run: ./vendor/bin/pest
+ env:
+ DB_PASSWORD: password
+ DB_USERNAME: root
+ DB_DATABASE: main
+ TENANCY_TEST_MYSQL_HOST: mysql
+ TENANCY_TEST_PGSQL_HOST: postgres
+ TENANCY_TEST_REDIS_HOST: redis
+ TENANCY_TEST_SQLSRV_HOST: mssql
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v2
+ with:
+ token: 24382d15-84e7-4a55-bea4-c4df96a24a9b
+
+ services:
+ postgres:
+ image: postgres:latest
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: root
+ POSTGRES_DB: main
+ ports:
+ - 5432/tcp
+ options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3
+
+ mysql:
+ image: mysql:5.7
+ env:
+ MYSQL_ALLOW_EMPTY_PASSWORD: false
+ MYSQL_ROOT_PASSWORD: password
+ MYSQL_DATABASE: main
+ ports:
+ - 3306/tcp
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
+
+ mysql2:
+ image: mysql:5.7
+ env:
+ MYSQL_ALLOW_EMPTY_PASSWORD: false
+ MYSQL_ROOT_PASSWORD: password
+ MYSQL_DATABASE: main
+ ports:
+ - 3306/tcp
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
+
+ mssql:
+ image: mcr.microsoft.com/mssql/server:2019-latest
+ ports:
+ - 1433/tcp
+ env:
+ ACCEPT_EULA: Y
+ SA_PASSWORD: P@ssword
+ options: --health-cmd "echo quit | /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -l 1 -U sa -P P@ssword"
+
+ redis:
+ image: redis
+ ports:
+ - 6379/tcp
+ options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
+
+ php-cs-fixer:
+ name: Code style (php-cs-fixer)
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install php-cs-fixer
+ run: composer global require friendsofphp/php-cs-fixer
+ - name: Run php-cs-fixer
+ run: $HOME/.composer/vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php
+ - name: Commit changes from php-cs-fixer
+ uses: EndBug/add-and-commit@v5
+ with:
+ author_name: "PHP CS Fixer"
+ author_email: "phpcsfixer@example.com"
+ message: Fix code style (php-cs-fixer)
+
+ phpstan:
+ name: Static analysis (PHPStan)
+ runs-on: ubuntu-latest
+ steps:
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.2'
+ - uses: actions/checkout@v2
+ - name: Install composer dependencies
+ run: composer install
+ - name: Run phpstan
+ run: vendor/bin/phpstan analyse
From a88863bf251d47389d0cdc70b1f6e75119e13f13 Mon Sep 17 00:00:00 2001
From: PHP CS Fixer
Date: Mon, 20 Feb 2023 08:28:03 +0000
Subject: [PATCH 19/46] Fix code style (php-cs-fixer)
---
src/Vite.php | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/Vite.php b/src/Vite.php
index 1887361a..ca47fcc3 100644
--- a/src/Vite.php
+++ b/src/Vite.php
@@ -1,5 +1,7 @@
Date: Mon, 20 Feb 2023 09:39:32 +0100
Subject: [PATCH 20/46] Update dependencies
---
composer.json | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/composer.json b/composer.json
index bb11040e..6e1fa2eb 100644
--- a/composer.json
+++ b/composer.json
@@ -17,22 +17,23 @@
"require": {
"php": "^8.2",
"ext-json": "*",
- "illuminate/support": "^9.38",
+ "illuminate/support": "^9.38|^10.0",
+ "facade/ignition-contracts": "^1.0.2",
"spatie/ignition": "^1.4",
- "ramsey/uuid": "^4.0",
- "stancl/jobpipeline": "^1.0",
- "stancl/virtualcolumn": "^1.3",
+ "ramsey/uuid": "^4.7.3",
+ "stancl/jobpipeline": "^1.6.2",
+ "stancl/virtualcolumn": "^1.3.1",
"spatie/invade": "^1.1"
},
"require-dev": {
- "laravel/framework": "^9.38",
- "orchestra/testbench": "^7.0",
- "league/flysystem-aws-s3-v3": "^3.0",
- "doctrine/dbal": "^2.10",
+ "laravel/framework": "^9.38|^10.0",
+ "orchestra/testbench": "^7.0|^8.0",
+ "league/flysystem-aws-s3-v3": "^3.12.2",
+ "doctrine/dbal": "^3.6.0",
"spatie/valuestore": "^1.2.5",
"pestphp/pest": "^1.21",
"nunomaduro/larastan": "^2.4",
- "spatie/invade": "^1.1"
+ "spatie/invade": "^1.3.2"
},
"autoload": {
"psr-4": {
From 8cb5d0bc0c40550b121ffd7529f7f336449733dc Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Mon, 20 Feb 2023 09:47:59 +0100
Subject: [PATCH 21/46] Change invade version
---
composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 6e1fa2eb..b5734c1b 100644
--- a/composer.json
+++ b/composer.json
@@ -33,7 +33,7 @@
"spatie/valuestore": "^1.2.5",
"pestphp/pest": "^1.21",
"nunomaduro/larastan": "^2.4",
- "spatie/invade": "^1.3.2"
+ "spatie/invade": "^1.1"
},
"autoload": {
"psr-4": {
From 4c7fff73ecf88a6471e5a812ff8cc02a538fda60 Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Mon, 20 Feb 2023 09:55:36 +0100
Subject: [PATCH 22/46] Delete ViteBundlerTest
---
tests/Features/ViteBundlerTest.php | 34 ------------------------------
1 file changed, 34 deletions(-)
delete mode 100644 tests/Features/ViteBundlerTest.php
diff --git a/tests/Features/ViteBundlerTest.php b/tests/Features/ViteBundlerTest.php
deleted file mode 100644
index 23cf164d..00000000
--- a/tests/Features/ViteBundlerTest.php
+++ /dev/null
@@ -1,34 +0,0 @@
-assertInstanceOf(\Illuminate\Foundation\Vite::class, $vite);
- $this->assertNotInstanceOf(StanclVite::class, $vite);
-
- config([
- 'tenancy.features' => [ViteBundler::class],
- ]);
-
- $tenant = Tenant::create();
-
- tenancy()->initialize($tenant);
-
- app()->forgetInstance(\Illuminate\Foundation\Vite::class);
-
- $vite = app(\Illuminate\Foundation\Vite::class);
-
- $this->assertInstanceOf(StanclVite::class, $vite);
- }
-}
From c819c69c94f0e9d69b266a6943bfddc58aa5f3cc Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Mon, 20 Feb 2023 10:09:13 +0100
Subject: [PATCH 23/46] Fix PHPStan error
---
.../PermissionControlledMySQLDatabaseManager.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Database/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php b/src/Database/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
index 80dc6647..308d8786 100644
--- a/src/Database/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
+++ b/src/Database/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
@@ -41,7 +41,7 @@ class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager impl
protected function isVersion8(): bool
{
- $versionSelect = $this->database()->raw('select version()')->getValue($this->database()->getQueryGrammar());
+ $versionSelect = (string) $this->database()->raw('select version()')->getValue($this->database()->getQueryGrammar());
$version = $this->database()->select($versionSelect)[0]->{'version()'};
return version_compare($version, '8.0.0') >= 0;
From e0f3a595cc18677ee94dc646a1cc9ff85108c406 Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Mon, 20 Feb 2023 10:18:54 +0100
Subject: [PATCH 24/46] Delete PHPStan error ignore
---
phpstan.neon | 4 ----
1 file changed, 4 deletions(-)
diff --git a/phpstan.neon b/phpstan.neon
index 91e9f3af..19cda805 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -40,10 +40,6 @@ parameters:
message: '#Illuminate\\Routing\\UrlGenerator#'
paths:
- src/Bootstrappers/FilesystemTenancyBootstrapper.php
- -
- message: '#select\(\) expects string, Illuminate\\Database\\Query\\Expression given#'
- paths:
- - src/Database/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
-
message: '#Trying to invoke Closure\|null but it might not be a callable#'
paths:
From 6da74fbf6d2e89bee2ed6bdd16fa9d5bada1ff8d Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Mon, 20 Feb 2023 10:25:51 +0100
Subject: [PATCH 25/46] Fix CONTRIBUTING.md
---
CONTRIBUTING.md | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e2e76c8c..0095be7e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -24,4 +24,16 @@ To fix this, simply delete the database memory by shutting down containers and s
Run `composer docker-m1` to symlink `docker-compose-m1.override.yml` to `docker-compose.override.yml`. This will reconfigure a few services in the docker compose config to be compatible with M1.
-to `docker-compose.override.yml` to make `docker-compose up -d` work on M1.
+### Coverage reports
+
+To run tests and generate coverage reports, use `composer test-full`.
+
+To view the coverage reports in your browser, use `composer coverage` (works on macOS; on other operating systems you can manually open `coverage/phpunit/html/index.html` in your browser).
+
+### Rebuilding containers
+
+If you need to rebuild the container for any reason (e.g. a change in `Dockerfile`), you can use `composer docker-rebuild`.
+
+## PHPStan
+
+Use `composer phpstan` to run our phpstan suite.
From 20996bfd475c4b4444f8a45a29e4f3fcf91259b2 Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Mon, 20 Feb 2023 10:31:12 +0100
Subject: [PATCH 26/46] Delete ViteBundler remains
---
assets/config.php | 1 -
src/Features/ViteBundler.php | 26 --------------------------
2 files changed, 27 deletions(-)
delete mode 100644 src/Features/ViteBundler.php
diff --git a/assets/config.php b/assets/config.php
index 7fc6c928..25811222 100644
--- a/assets/config.php
+++ b/assets/config.php
@@ -286,7 +286,6 @@ return [
// Stancl\Tenancy\Features\TelescopeTags::class,
// Stancl\Tenancy\Features\TenantConfig::class, // https://tenancyforlaravel.com/docs/v3/features/tenant-config
// Stancl\Tenancy\Features\CrossDomainRedirect::class, // https://tenancyforlaravel.com/docs/v3/features/cross-domain-redirect
- // Stancl\Tenancy\Features\ViteBundler::class,
],
/**
diff --git a/src/Features/ViteBundler.php b/src/Features/ViteBundler.php
deleted file mode 100644
index e3fee2fa..00000000
--- a/src/Features/ViteBundler.php
+++ /dev/null
@@ -1,26 +0,0 @@
-app = $app;
- }
-
- public function bootstrap(Tenancy $tenancy): void
- {
- $this->app->singleton(\Illuminate\Foundation\Vite::class, Vite::class);
- }
-}
From 7a0fbc25a842051b566cbf0307680bd951fa3d46 Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Mon, 20 Feb 2023 11:06:00 +0100
Subject: [PATCH 27/46] Bring back ViteBundler
---
assets/config.php | 1 +
src/Features/ViteBundler.php | 26 +++++++++++++++++++++++
tests/Features/ViteBundlerTest.php | 34 ++++++++++++++++++++++++++++++
3 files changed, 61 insertions(+)
create mode 100644 src/Features/ViteBundler.php
create mode 100644 tests/Features/ViteBundlerTest.php
diff --git a/assets/config.php b/assets/config.php
index 25811222..7fc6c928 100644
--- a/assets/config.php
+++ b/assets/config.php
@@ -286,6 +286,7 @@ return [
// Stancl\Tenancy\Features\TelescopeTags::class,
// Stancl\Tenancy\Features\TenantConfig::class, // https://tenancyforlaravel.com/docs/v3/features/tenant-config
// Stancl\Tenancy\Features\CrossDomainRedirect::class, // https://tenancyforlaravel.com/docs/v3/features/cross-domain-redirect
+ // Stancl\Tenancy\Features\ViteBundler::class,
],
/**
diff --git a/src/Features/ViteBundler.php b/src/Features/ViteBundler.php
new file mode 100644
index 00000000..e3fee2fa
--- /dev/null
+++ b/src/Features/ViteBundler.php
@@ -0,0 +1,26 @@
+app = $app;
+ }
+
+ public function bootstrap(Tenancy $tenancy): void
+ {
+ $this->app->singleton(\Illuminate\Foundation\Vite::class, Vite::class);
+ }
+}
diff --git a/tests/Features/ViteBundlerTest.php b/tests/Features/ViteBundlerTest.php
new file mode 100644
index 00000000..23cf164d
--- /dev/null
+++ b/tests/Features/ViteBundlerTest.php
@@ -0,0 +1,34 @@
+assertInstanceOf(\Illuminate\Foundation\Vite::class, $vite);
+ $this->assertNotInstanceOf(StanclVite::class, $vite);
+
+ config([
+ 'tenancy.features' => [ViteBundler::class],
+ ]);
+
+ $tenant = Tenant::create();
+
+ tenancy()->initialize($tenant);
+
+ app()->forgetInstance(\Illuminate\Foundation\Vite::class);
+
+ $vite = app(\Illuminate\Foundation\Vite::class);
+
+ $this->assertInstanceOf(StanclVite::class, $vite);
+ }
+}
From aac038f2331d2989a1c5b5310fdc60c8d23c7d6a Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Mon, 20 Feb 2023 11:37:47 +0100
Subject: [PATCH 28/46] Convert ViteBundlerTest to Pest
---
tests/Features/ViteBundlerTest.php | 35 +++++++++++++-----------------
1 file changed, 15 insertions(+), 20 deletions(-)
diff --git a/tests/Features/ViteBundlerTest.php b/tests/Features/ViteBundlerTest.php
index 23cf164d..0d4c9069 100644
--- a/tests/Features/ViteBundlerTest.php
+++ b/tests/Features/ViteBundlerTest.php
@@ -2,33 +2,28 @@
declare(strict_types=1);
-use Stancl\Tenancy\Features\ViteBundler;
+use Illuminate\Foundation\Vite;
use Stancl\Tenancy\Tests\Etc\Tenant;
-use Stancl\Tenancy\Tests\TestCase;
use Stancl\Tenancy\Vite as StanclVite;
+use Stancl\Tenancy\Features\ViteBundler;
-class ViteBundlerTest extends TestCase
-{
- /** @test */
- public function the_vite_helper_uses_our_custom_class()
- {
- $vite = app(\Illuminate\Foundation\Vite::class);
+test('vite helper uses our custom class', function() {
+ $vite = app(Vite::class);
- $this->assertInstanceOf(\Illuminate\Foundation\Vite::class, $vite);
- $this->assertNotInstanceOf(StanclVite::class, $vite);
+ expect($vite)->toBeInstanceOf(Vite::class);
+ expect($vite)->not()->toBeInstanceOf(StanclVite::class);
- config([
- 'tenancy.features' => [ViteBundler::class],
- ]);
+ config([
+ 'tenancy.features' => [ViteBundler::class],
+ ]);
- $tenant = Tenant::create();
+ $tenant = Tenant::create();
- tenancy()->initialize($tenant);
+ tenancy()->initialize($tenant);
- app()->forgetInstance(\Illuminate\Foundation\Vite::class);
+ app()->forgetInstance(Vite::class);
- $vite = app(\Illuminate\Foundation\Vite::class);
+ $vite = app(Vite::class);
- $this->assertInstanceOf(StanclVite::class, $vite);
- }
-}
+ expect($vite)->toBeInstanceOf(StanclVite::class);
+});
From 128ff12840dcbed00e4275d100c155a23ef47971 Mon Sep 17 00:00:00 2001
From: lukinovec
Date: Mon, 20 Feb 2023 15:09:36 +0100
Subject: [PATCH 29/46] Update ci.yml
---
.github/workflows/ci.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3f46ce64..8ecb863b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,9 +16,9 @@ jobs:
strategy:
matrix:
include:
- - laravel: "9.0"
+ - laravel: 9
php: "8.0"
- - laravel: "10.0"
+ - laravel: 10
php: "8.1"
steps:
@@ -27,7 +27,7 @@ jobs:
- name: Install Composer dependencies
run: |
- composer require "laravel/framework:^${{ matrix.laravel }}" --no-interaction --no-update
+ composer require "laravel/framework:^${{ matrix.laravel }}.0" --no-interaction --no-update
composer update --prefer-dist --no-interaction
- name: Run tests
run: ./vendor/bin/pest
From bcdd607cd4ce974fa85d7fcfe5302b8b94fc7fe2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Mon, 24 Apr 2023 22:02:32 +0200
Subject: [PATCH 30/46] update laravel version
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 95fb7c60..8ce25809 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
-
+
From d9b7107900f938dc404810c59c092a1b8325366b Mon Sep 17 00:00:00 2001
From: Chris Thompson
Date: Thu, 27 Apr 2023 20:40:27 +0700
Subject: [PATCH 31/46] Typo in PHPdoc (#1106)
---
assets/config.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assets/config.php b/assets/config.php
index b12cd6c4..a10ad33c 100644
--- a/assets/config.php
+++ b/assets/config.php
@@ -112,7 +112,7 @@ return [
* See https://tenancyforlaravel.com/docs/v3/tenancy-bootstrappers/#filesystem-tenancy-boostrapper
*/
'root_override' => [
- // Disks whose roots should be overriden after storage_path() is suffixed.
+ // Disks whose roots should be overridden after storage_path() is suffixed.
'local' => '%storage_path%/app/',
'public' => '%storage_path%/app/public/',
],
From e070d137458c26f65bd5c4f1bf1a03ea34fb7fe5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Thu, 27 Jul 2023 05:15:28 +0200
Subject: [PATCH 32/46] update support link
---
.github/ISSUE_TEMPLATE/config.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 6870a17c..2aab2732 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,7 +1,7 @@
blank_issues_enabled: false
contact_links:
- name: Support Questions & Other
- url: https://github.com/stancl/tenancy/blob/3.x/SUPPORT.md
+ url: https://archte.ch/discord
about: 'If you have a question or need help using the package.'
- name: Documentation Issue
url: https://github.com/stancl/tenancy-docs/issues
From 395192442d4000fe901888482c7d9b98ead9bff8 Mon Sep 17 00:00:00 2001
From: tamiroh
Date: Fri, 18 Aug 2023 14:40:21 +0900
Subject: [PATCH 33/46] Add use (#1103)
---
src/Middleware/InitializeTenancyByRequestData.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/Middleware/InitializeTenancyByRequestData.php b/src/Middleware/InitializeTenancyByRequestData.php
index de75d8c5..ef2132e8 100644
--- a/src/Middleware/InitializeTenancyByRequestData.php
+++ b/src/Middleware/InitializeTenancyByRequestData.php
@@ -6,6 +6,7 @@ namespace Stancl\Tenancy\Middleware;
use Closure;
use Illuminate\Http\Request;
+use Stancl\Tenancy\Contracts\TenantResolver;
use Stancl\Tenancy\Resolvers\RequestDataTenantResolver;
use Stancl\Tenancy\Tenancy;
From 4af70d302ffcf19306cc16009bd94162f3743ca7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Thu, 24 Aug 2023 18:21:23 +0200
Subject: [PATCH 34/46] add extra $path validation to TenantAssetsController
---
.gitignore | 1 +
src/Controllers/TenantAssetsController.php | 18 +++++++++++++++++-
tests/TenantAssetTest.php | 13 +++++++++++++
3 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index f470ba75..c7cf933c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ coverage/
clover.xml
tests/Etc/tmp/queuetest.json
docker-compose.override.yml
+.DS_Store
diff --git a/src/Controllers/TenantAssetsController.php b/src/Controllers/TenantAssetsController.php
index 5549da0d..1e2014a7 100644
--- a/src/Controllers/TenantAssetsController.php
+++ b/src/Controllers/TenantAssetsController.php
@@ -18,7 +18,7 @@ class TenantAssetsController extends Controller
public function asset($path = null)
{
- abort_if($path === null, 404);
+ $this->validatePath($path);
try {
return response()->file(storage_path("app/public/$path"));
@@ -26,4 +26,20 @@ class TenantAssetsController extends Controller
abort(404);
}
}
+
+ /**
+ * @throws \Symfony\Component\HttpKernel\Exception\HttpException
+ */
+ protected function validatePath(string|null $path): void
+ {
+ abort_if($path === null, 404);
+
+ $allowedRoot = storage_path('app/public');
+
+ // Prevent path traversal attacks. This is generally a non-issue on modern
+ // webservers but it's still worth handling on the application level as well.
+ if (! str(realpath("{$allowedRoot}/{$path}"))->startsWith($allowedRoot)) {
+ abort(403);
+ }
+ }
}
diff --git a/tests/TenantAssetTest.php b/tests/TenantAssetTest.php
index 703ac65e..c24767cc 100644
--- a/tests/TenantAssetTest.php
+++ b/tests/TenantAssetTest.php
@@ -141,4 +141,17 @@ class TenantAssetTest extends TestCase
$response->assertNotFound();
}
+ public function test_asset_controller_returns_a_403_when_an_invalid_path_is_provided()
+ {
+ TenantAssetsController::$tenancyMiddleware = InitializeTenancyByRequestData::class;
+
+ $tenant = Tenant::create();
+
+ tenancy()->initialize($tenant);
+ $response = $this->get(tenant_asset('../foo.txt'), [
+ 'X-Tenant' => $tenant->id,
+ ]);
+
+ $response->assertForbidden();
+ }
}
From caf2267a085dd8ff0c566b3540bbe94f7a89a4cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Sat, 2 Sep 2023 03:19:37 +0200
Subject: [PATCH 35/46] reimplement TenantAssetsController::validatePath()
(fixes #1143)
---
src/Controllers/TenantAssetsController.php | 36 ++++++++++--
tests/TenantAssetTest.php | 68 ++++++++++++++++++++--
2 files changed, 92 insertions(+), 12 deletions(-)
diff --git a/src/Controllers/TenantAssetsController.php b/src/Controllers/TenantAssetsController.php
index 1e2014a7..356c25dd 100644
--- a/src/Controllers/TenantAssetsController.php
+++ b/src/Controllers/TenantAssetsController.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Controllers;
+use Exception;
use Illuminate\Routing\Controller;
use Throwable;
@@ -28,18 +29,41 @@ class TenantAssetsController extends Controller
}
/**
+ * Prevent path traversal attacks. This is generally a non-issue on modern
+ * webservers but it's still worth handling on the application level as well.
+ *
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
*/
protected function validatePath(string|null $path): void
{
- abort_if($path === null, 404);
+ $this->abortIf($path === null, 'Empty path');
- $allowedRoot = storage_path('app/public');
+ $allowedRoot = realpath(storage_path('app/public'));
- // Prevent path traversal attacks. This is generally a non-issue on modern
- // webservers but it's still worth handling on the application level as well.
- if (! str(realpath("{$allowedRoot}/{$path}"))->startsWith($allowedRoot)) {
- abort(403);
+ // `storage_path('app/public')` doesn't exist, so it cannot contain files
+ $this->abortIf($allowedRoot === false, "Storage root doesn't exist");
+
+ $attemptedPath = realpath("{$allowedRoot}/{$path}");
+
+ // User is attempting to access a nonexistent file
+ $this->abortIf($attemptedPath === false, 'Accessing a nonexistent file');
+
+ // User is attempting to access a file outside the $allowedRoot folder
+ $this->abortIf(! str($attemptedPath)->startsWith($allowedRoot), 'Accessing a file outside the storage root');
+ }
+
+ protected function abortIf($condition, $exceptionMessage): void
+ {
+ if ($condition) {
+ if (app()->runningUnitTests()) {
+ // Makes testing the cause of the failure in validatePath() easier
+ throw new Exception($exceptionMessage);
+ } else {
+ // We always use 404 to avoid leaking information about the cause of the error
+ // e.g. when someone is trying to access a nonexistent file outside of the allowed
+ // root folder, we don't want to let the user know whether such a file exists or not.
+ abort(404);
+ }
}
}
}
diff --git a/tests/TenantAssetTest.php b/tests/TenantAssetTest.php
index c24767cc..8aabc0e2 100644
--- a/tests/TenantAssetTest.php
+++ b/tests/TenantAssetTest.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Tests;
+use Exception;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;
@@ -134,24 +135,79 @@ class TenantAssetTest extends TestCase
$tenant = Tenant::create();
tenancy()->initialize($tenant);
- $response = $this->get(tenant_asset(null), [
+
+ $this->withoutExceptionHandling();
+ $this->expectExceptionMessage('Empty path'); // outside tests this is a 404
+
+ $this->get(tenant_asset(null), [
'X-Tenant' => $tenant->id,
]);
-
- $response->assertNotFound();
}
- public function test_asset_controller_returns_a_403_when_an_invalid_path_is_provided()
+ public function test_asset_controller_returns_a_404_when_the_storage_root_doesnt_exist()
{
TenantAssetsController::$tenancyMiddleware = InitializeTenancyByRequestData::class;
$tenant = Tenant::create();
tenancy()->initialize($tenant);
- $response = $this->get(tenant_asset('../foo.txt'), [
+
+ $storageRoot = storage_path("app/public");
+
+ if (is_dir($storageRoot)) {
+ rmdir(storage_path("app/public"));
+ }
+
+ $this->withoutExceptionHandling();
+ $this->expectExceptionMessage("Storage root doesn't exist"); // outside tests this is a 404
+
+ $this->get(tenant_asset('foo.txt'), [
'X-Tenant' => $tenant->id,
]);
+ }
- $response->assertForbidden();
+ public function test_asset_controller_returns_a_404_when_accessing_a_nonexistent_file()
+ {
+ TenantAssetsController::$tenancyMiddleware = InitializeTenancyByRequestData::class;
+
+ $tenant = Tenant::create();
+
+ tenancy()->initialize($tenant);
+
+ $storageRoot = storage_path("app/public");
+
+ if (! is_dir($storageRoot)) {
+ mkdir(storage_path("app/public"), recursive: true);
+ }
+
+ $this->withoutExceptionHandling();
+ $this->expectExceptionMessage("Accessing a nonexistent file"); // outside tests this is a 404
+
+ $this->get(tenant_asset('foo.txt'), [
+ 'X-Tenant' => $tenant->id,
+ ]);
+ }
+
+ public function test_asset_controller_returns_a_404_when_accessing_a_file_outside_the_storage_root()
+ {
+ TenantAssetsController::$tenancyMiddleware = InitializeTenancyByRequestData::class;
+
+ $tenant = Tenant::create();
+
+ tenancy()->initialize($tenant);
+
+ $storageRoot = storage_path("app/public");
+
+ if (! is_dir($storageRoot)) {
+ mkdir(storage_path("app/public"), recursive: true);
+ file_put_contents(storage_path('app/foo.txt'), 'bar');
+ }
+
+ $this->withoutExceptionHandling();
+ $this->expectExceptionMessage('Accessing a file outside the storage root'); // outside tests this is a 404
+
+ $this->get(tenant_asset('../foo.txt'), [
+ 'X-Tenant' => $tenant->id,
+ ]);
}
}
From 85c7465aca2fb017545a5304dea0ee0006bee5f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Sat, 2 Sep 2023 03:20:42 +0200
Subject: [PATCH 36/46] remove unnecessary import
---
tests/TenantAssetTest.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/TenantAssetTest.php b/tests/TenantAssetTest.php
index 8aabc0e2..2852eae2 100644
--- a/tests/TenantAssetTest.php
+++ b/tests/TenantAssetTest.php
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Tests;
-use Exception;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;
From 0b248f937dd4799aa42ecdbd2fc73c05ddb943bb Mon Sep 17 00:00:00 2001
From: Massimo Simonini
Date: Tue, 21 Nov 2023 02:25:32 +0100
Subject: [PATCH 37/46] Add step option to migrate-fresh command (#1164)
---
src/Commands/MigrateFresh.php | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/Commands/MigrateFresh.php b/src/Commands/MigrateFresh.php
index 283d70b0..b626c775 100644
--- a/src/Commands/MigrateFresh.php
+++ b/src/Commands/MigrateFresh.php
@@ -25,6 +25,7 @@ final class MigrateFresh extends Command
parent::__construct();
$this->addOption('--drop-views', null, InputOption::VALUE_NONE, 'Drop views along with tenant tables.', null);
+ $this->addOption('--step', null, InputOption::VALUE_NONE, 'Force the migrations to be run so they can be rolled back individually.');
$this->setName('tenants:migrate-fresh');
}
@@ -47,6 +48,7 @@ final class MigrateFresh extends Command
$this->info('Migrating.');
$this->callSilent('tenants:migrate', [
'--tenants' => [$tenant->getTenantKey()],
+ '--step' => $this->option('step'),
'--force' => true,
]);
});
From d268a06f5d8d98bbd0aa0c6fb7a4381c0bdc5c85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Thu, 18 Jan 2024 14:30:40 +0100
Subject: [PATCH 38/46] tests: assert that tenants:run runs only for the
specified tenants
---
tests/CommandsTest.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php
index d7da0cab..78fc7c0b 100644
--- a/tests/CommandsTest.php
+++ b/tests/CommandsTest.php
@@ -196,10 +196,12 @@ class CommandsTest extends TestCase
{
$tenantId1 = Tenant::create()->getTenantKey();
$tenantId2 = Tenant::create()->getTenantKey();
+ $tenantId3 = Tenant::create()->getTenantKey();
Artisan::call('tenants:migrate-fresh');
$this->artisan("tenants:run foo --tenants=$tenantId1 --tenants=$tenantId2 --argument='a=foo' --option='b=bar' --option='c=xyz'")
->expectsOutput('Tenant: ' . $tenantId1)
- ->expectsOutput('Tenant: ' . $tenantId2);
+ ->expectsOutput('Tenant: ' . $tenantId2)
+ ->doesntExpectOutput('Tenant: ' . $tenantId3);
}
}
From 5fe8825f13e2141c4388ae2afec01bd85f2f91ae Mon Sep 17 00:00:00 2001
From: chillbram
Date: Thu, 25 Jan 2024 22:34:47 +0100
Subject: [PATCH 39/46] Make universal routes work for controller middleware
(#1151)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Make universal routes work for controller middleware
* add a fallback
---------
Co-authored-by: chillbram <7299762+chillbram@users.noreply.github.com>
Co-authored-by: Samuel Štancl
---
src/Features/UniversalRoutes.php | 2 +-
tests/UniversalRouteTest.php | 42 ++++++++++++++++++++++++++++++++
2 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/src/Features/UniversalRoutes.php b/src/Features/UniversalRoutes.php
index 6b729962..40acbeae 100644
--- a/src/Features/UniversalRoutes.php
+++ b/src/Features/UniversalRoutes.php
@@ -35,7 +35,7 @@ class UniversalRoutes implements Feature
public static function routeHasMiddleware(Route $route, $middleware): bool
{
- if (in_array($middleware, $route->middleware(), true)) {
+ if (in_array($middleware, $route->computedMiddleware ?? $route->middleware(), true)) {
return true;
}
diff --git a/tests/UniversalRouteTest.php b/tests/UniversalRouteTest.php
index c0852545..fff7b9f6 100644
--- a/tests/UniversalRouteTest.php
+++ b/tests/UniversalRouteTest.php
@@ -63,4 +63,46 @@ class UniversalRouteTest extends TestCase
->assertSuccessful()
->assertSee('acme');
}
+
+ /** @test */
+ public function universal_route_works_when_middleware_is_inserted_via_controller_middleware()
+ {
+ Route::middlewareGroup('universal', []);
+ config(['tenancy.features' => [UniversalRoutes::class]]);
+
+ Route::get('/foo', [UniversalRouteController::class, 'show']);
+
+ $this->get('http://localhost/foo')
+ ->assertSuccessful()
+ ->assertSee('Tenancy is not initialized.');
+
+ $tenant = Tenant::create([
+ 'id' => 'acme',
+ ]);
+ $tenant->domains()->create([
+ 'domain' => 'acme.localhost',
+ ]);
+
+ $this->get('http://acme.localhost/foo')
+ ->assertSuccessful()
+ ->assertSee('Tenancy is initialized.');
+ }
+}
+
+class UniversalRouteController
+{
+ public function getMiddleware()
+ {
+ return array_map(fn($middleware) => [
+ 'middleware' => $middleware,
+ 'options' => [],
+ ], ['universal', InitializeTenancyByDomain::class]);
+ }
+
+ public function show()
+ {
+ return tenancy()->initialized
+ ? 'Tenancy is initialized.'
+ : 'Tenancy is not initialized.';
+ }
}
From 8db27a358ef71e01362dd388e5c0439fcda44944 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Sat, 27 Jan 2024 22:55:59 +0100
Subject: [PATCH 40/46] Forget tenant parameter when a tenant is resolved from
cache in PathTenantResolver (fix #1174)
---
src/Resolvers/PathTenantResolver.php | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/Resolvers/PathTenantResolver.php b/src/Resolvers/PathTenantResolver.php
index 0b79626f..e3c32cc7 100644
--- a/src/Resolvers/PathTenantResolver.php
+++ b/src/Resolvers/PathTenantResolver.php
@@ -37,6 +37,14 @@ class PathTenantResolver extends Contracts\CachedTenantResolver
throw new TenantCouldNotBeIdentifiedByPathException($id);
}
+ public function resolved(Tenant $tenant, ...$args): void
+ {
+ /** @var Route $route */
+ $route = $args[0];
+
+ $route->forgetParameter(static::$tenantParameterName);
+ }
+
public function getArgsForTenant(Tenant $tenant): array
{
return [
From 99706f95ef0829c1651ac25fe28da482055e4135 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Sat, 10 Feb 2024 23:37:46 +0100
Subject: [PATCH 41/46] fix ci.yml
---
.github/workflows/ci.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3599511f..2a7da559 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
include:
- - laravel: "^10.0"
+ - laravel: "10.0"
php: "8.2"
steps:
From a7368264c2af3682c79a2488390ecfb8faa2693d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Sat, 10 Feb 2024 23:40:04 +0100
Subject: [PATCH 42/46] remove duplicate method from automerge
---
src/Resolvers/PathTenantResolver.php | 8 --------
1 file changed, 8 deletions(-)
diff --git a/src/Resolvers/PathTenantResolver.php b/src/Resolvers/PathTenantResolver.php
index 0f63e7c4..d5742294 100644
--- a/src/Resolvers/PathTenantResolver.php
+++ b/src/Resolvers/PathTenantResolver.php
@@ -31,14 +31,6 @@ class PathTenantResolver extends Contracts\CachedTenantResolver
throw new TenantCouldNotBeIdentifiedByPathException($id);
}
- public function resolved(Tenant $tenant, ...$args): void
- {
- /** @var Route $route */
- $route = $args[0];
-
- $route->forgetParameter(static::$tenantParameterName);
- }
-
public function getArgsForTenant(Tenant $tenant): array
{
return [
From 2eda22772c496d160926d8e880c6f1de45cc3877 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Sat, 10 Feb 2024 23:51:04 +0100
Subject: [PATCH 43/46] import Exception
---
src/Controllers/TenantAssetController.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/Controllers/TenantAssetController.php b/src/Controllers/TenantAssetController.php
index 3e0b68e5..cada0864 100644
--- a/src/Controllers/TenantAssetController.php
+++ b/src/Controllers/TenantAssetController.php
@@ -7,6 +7,7 @@ namespace Stancl\Tenancy\Controllers;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
+use Exception;
use Throwable;
class TenantAssetController implements HasMiddleware // todo@docs this was renamed from TenantAssetsController
From 56a6f25dacdc40a2bb82879cca80cbf80f592ebd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Sat, 10 Feb 2024 23:55:56 +0100
Subject: [PATCH 44/46] fix phpstan errors
---
phpstan.neon | 4 ++++
src/Controllers/TenantAssetController.php | 3 ++-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/phpstan.neon b/phpstan.neon
index ba269e5e..8a48a672 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -51,6 +51,10 @@ parameters:
- '#Method Stancl\\Tenancy\\Tenancy::cachedResolvers\(\) should return array#'
- '#Access to an undefined property Stancl\\Tenancy\\Middleware\\IdentificationMiddleware\:\:\$tenancy#'
- '#Access to an undefined property Stancl\\Tenancy\\Middleware\\IdentificationMiddleware\:\:\$resolver#'
+ -
+ message: '#string\|false#'
+ paths:
+ - src/Controllers/TenantAssetController.php
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false # later we may want to enable this
diff --git a/src/Controllers/TenantAssetController.php b/src/Controllers/TenantAssetController.php
index cada0864..cfa130c5 100644
--- a/src/Controllers/TenantAssetController.php
+++ b/src/Controllers/TenantAssetController.php
@@ -57,7 +57,8 @@ class TenantAssetController implements HasMiddleware // todo@docs this was renam
$this->abortIf(! str($attemptedPath)->startsWith($allowedRoot), 'Accessing a file outside the storage root');
}
- protected function abortIf($condition, $exceptionMessage): void
+ /** @return void|never */
+ protected function abortIf(bool $condition, string $exceptionMessage = ''): void
{
if ($condition) {
if (app()->runningUnitTests()) {
From 640305284b9711d9b64f8a3e7bf58c2dc63b5daf Mon Sep 17 00:00:00 2001
From: PHP CS Fixer
Date: Sat, 10 Feb 2024 23:04:12 +0000
Subject: [PATCH 45/46] Fix code style (php-cs-fixer)
---
src/Controllers/TenantAssetController.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Controllers/TenantAssetController.php b/src/Controllers/TenantAssetController.php
index cfa130c5..96fc6374 100644
--- a/src/Controllers/TenantAssetController.php
+++ b/src/Controllers/TenantAssetController.php
@@ -4,10 +4,10 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Controllers;
+use Exception;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
-use Exception;
use Throwable;
class TenantAssetController implements HasMiddleware // todo@docs this was renamed from TenantAssetsController
From 4b52fed4a0c22800eef47e76778cc4ef86046773 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C5=A0tancl?=
Date: Sun, 11 Feb 2024 00:07:38 +0100
Subject: [PATCH 46/46] fix more files broken in automerge
---
.github/workflows/ci.yml | 4 ++--
.gitignore | 1 -
src/Vite.php | 22 ------------------
tests/UniversalRouteTest.php | 44 ------------------------------------
4 files changed, 2 insertions(+), 69 deletions(-)
delete mode 100644 src/Vite.php
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2a7da559..21ae92a0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
include:
- - laravel: "10.0"
+ - laravel: "^10.0"
php: "8.2"
steps:
@@ -25,7 +25,7 @@ jobs:
- name: Install Composer dependencies
run: |
- composer require "laravel/framework:^${{ matrix.laravel }}.0" --no-interaction --no-update
+ composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
composer update --prefer-dist --no-interaction
- name: Run tests
run: ./vendor/bin/pest
diff --git a/.gitignore b/.gitignore
index 99545a46..5a5960b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,3 @@ tenant-schema-test.dump
tests/Etc/tmp/queuetest.json
docker-compose.override.yml
.php-cs-fixer.cache
-
diff --git a/src/Vite.php b/src/Vite.php
deleted file mode 100644
index ca47fcc3..00000000
--- a/src/Vite.php
+++ /dev/null
@@ -1,22 +0,0 @@
- [UniversalRoutes::class]]);
-
- Route::get('/foo', [UniversalRouteController::class, 'show']);
-
- $this->get('http://localhost/foo')
- ->assertSuccessful()
- ->assertSee('Tenancy is not initialized.');
-
- $tenant = Tenant::create([
- 'id' => 'acme',
- ]);
- $tenant->domains()->create([
- 'domain' => 'acme.localhost',
- ]);
-
- $this->get('http://acme.localhost/foo')
- ->assertSuccessful()
- ->assertSee('Tenancy is initialized.');
- }
-}
-
-class UniversalRouteController
-{
- public function getMiddleware()
- {
- return array_map(fn($middleware) => [
- 'middleware' => $middleware,
- 'options' => [],
- ], ['universal', InitializeTenancyByDomain::class]);
- }
-
- public function show()
- {
- return tenancy()->initialized
- ? 'Tenancy is initialized.'
- : 'Tenancy is not initialized.';
- }
}