Skip to content

Commit d9ee7ca

Browse files
committed
Merge remote-tracking branch 'origin/august' into tenant-param-before-route-prefix
2 parents 0dc7e5d + 364637d commit d9ee7ca

37 files changed

+337
-204
lines changed

.github/workflows/validate.yml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,8 @@ jobs:
88
runs-on: ubuntu-latest
99
steps:
1010
- uses: actions/checkout@v2
11-
- name: Check for todo0
12-
run: '! grep -r "todo0" --exclude-dir=workflows .'
13-
if: always()
14-
- name: Check for todo1
15-
run: '! grep -r "todo1" --exclude-dir=workflows .'
16-
if: always()
17-
- name: Check for todo2
18-
run: '! grep -r "todo2" --exclude-dir=workflows .'
11+
- name: Check for priority todos
12+
run: '! grep -r "todo[0-9]" --exclude-dir=workflows .'
1913
if: always()
2014
- name: Check for non-todo skip()s in tests
2115
run: '! grep -r "skip(" --exclude-dir=workflows tests/ | grep -v "todo"'

assets/TenancyServiceProvider.stub.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@
2121
use Stancl\Tenancy\Middleware\InitializeTenancyByRequestData;
2222
use Stancl\Tenancy\Bootstrappers\Integrations\FortifyRouteBootstrapper;
2323

24+
/**
25+
* Tenancy for Laravel.
26+
*
27+
* Documentation: https://tenancyforlaravel.com
28+
*
29+
* We can sustainably develop Tenancy for Laravel thanks to our sponsors.
30+
* Big thanks to everyone listed here: https://github.com/sponsors/stancl
31+
*
32+
* You can also support us, and save time, by purchasing these products:
33+
* Exclusive content for sponsors: https://sponsors.tenancyforlaravel.com
34+
* Multi-Tenant SaaS boilerplate: https://portal.archte.ch/boilerplate
35+
* Multi-Tenant Laravel in Production e-book: https://portal.archte.ch/book
36+
*
37+
* All of these products can also be accessed at https://portal.archte.ch
38+
*/
2439
class TenancyServiceProvider extends ServiceProvider
2540
{
2641
// By default, no namespace is used to support the callable array syntax.

assets/config.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@
88
use Stancl\Tenancy\Enums\RouteMode;
99
use Stancl\Tenancy\UniqueIdentifierGenerators;
1010

11+
/**
12+
* Tenancy for Laravel.
13+
*
14+
* Documentation: https://tenancyforlaravel.com
15+
*
16+
* We can sustainably develop Tenancy for Laravel thanks to our sponsors.
17+
* Big thanks to everyone listed here: https://github.com/sponsors/stancl
18+
*
19+
* You can also support us, and save time, by purchasing these products:
20+
* Exclusive content for sponsors: https://sponsors.tenancyforlaravel.com
21+
* Multi-Tenant SaaS boilerplate: https://portal.archte.ch/boilerplate
22+
* Multi-Tenant Laravel in Production e-book: https://portal.archte.ch/book
23+
*
24+
* All of these products can also be accessed at https://portal.archte.ch
25+
*/
1126
return [
1227
/**
1328
* Configuration for the models used by Tenancy.

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ services:
8080
image: mcr.microsoft.com/mssql/server:2022-latest
8181
environment:
8282
- ACCEPT_EULA=Y
83-
- SA_PASSWORD=P@ssword # todo reuse env from above
83+
- SA_PASSWORD=P@ssword # must be the same as TENANCY_TEST_SQLSRV_PASSWORD
8484
healthcheck: # https://github.com/Microsoft/mssql-docker/issues/133#issuecomment-1995615432
8585
test: timeout 2 bash -c 'cat < /dev/null > /dev/tcp/127.0.0.1/1433'
8686
interval: 10s

src/Bootstrappers/DatabaseTenancyBootstrapper.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ public function bootstrap(Tenant $tenant): void
3232
throw new Exception('The template connection must NOT have URL defined. Specify the connection using individual parts instead of a database URL.');
3333
}
3434

35-
// Better debugging, but breaks cached lookup in prod
36-
if (app()->environment('local') || app()->environment('testing')) { // todo@docs mention this change in v4 upgrade guide https://github.com/archtechx/tenancy/pull/945#issuecomment-1268206149
35+
// Better debugging, but breaks cached lookup, so we disable this in prod
36+
if (app()->environment('local') || app()->environment('testing')) {
3737
$database = $tenant->database()->getName();
38-
if (! $tenant->database()->manager()->databaseExists($database)) { // todo@samuel does this call correctly use the host connection?
38+
if (! $tenant->database()->manager()->databaseExists($database)) { // todo@dbRefactor does this call correctly use the host connection?
3939
throw new TenantDatabaseDoesNotExistException($database);
4040
}
4141
}

src/Commands/CreatePendingTenants.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class CreatePendingTenants extends Command
1010
{
11-
protected $signature = 'tenants:pending-create {--count= : The number of pending tenants to be created}';
11+
protected $signature = 'tenants:pending-create {--count= : The number of pending tenants to maintain}';
1212

1313
protected $description = 'Create pending tenants.';
1414

src/Commands/Migrate.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,24 @@ public function handle(): int
5151
return 1;
5252
}
5353

54+
$originalTemplateConnection = config('tenancy.database.template_tenant_connection');
55+
56+
if ($database = $this->input->getOption('database')) {
57+
config(['tenancy.database.template_tenant_connection' => $database]);
58+
}
59+
5460
if ($this->getProcesses() > 1) {
55-
return $this->runConcurrently($this->getTenantChunks()->map(function ($chunk) {
61+
$code = $this->runConcurrently($this->getTenantChunks()->map(function ($chunk) {
5662
return $this->getTenants($chunk);
5763
}));
64+
} else {
65+
$code = $this->migrateTenants($this->getTenants()) ? 0 : 1;
5866
}
5967

60-
return $this->migrateTenants($this->getTenants()) ? 0 : 1;
68+
// Reset the template tenant connection to the original one
69+
config(['tenancy.database.template_tenant_connection' => $originalTemplateConnection]);
70+
71+
return $code;
6172
}
6273

6374
protected function childHandle(mixed ...$args): bool

src/Commands/MigrateFresh.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Stancl\Tenancy\Commands;
66

7+
use Illuminate\Console\ConfirmableTrait;
78
use Illuminate\Database\Console\Migrations\BaseCommand;
89
use Illuminate\Database\QueryException;
910
use Illuminate\Support\LazyCollection;
@@ -17,7 +18,7 @@
1718

1819
class MigrateFresh extends BaseCommand
1920
{
20-
use HasTenantOptions, DealsWithMigrations, ParallelCommand;
21+
use HasTenantOptions, DealsWithMigrations, ParallelCommand, ConfirmableTrait;
2122

2223
protected $description = 'Drop all tables and re-run all migrations for tenant(s)';
2324

@@ -27,13 +28,18 @@ public function __construct()
2728

2829
$this->addOption('drop-views', null, InputOption::VALUE_NONE, 'Drop views along with tenant tables.', null);
2930
$this->addOption('step', null, InputOption::VALUE_NONE, 'Force the migrations to be run so they can be rolled back individually.');
31+
$this->addOption('force', null, InputOption::VALUE_NONE, 'Force the command to run when in production.', null);
3032
$this->addProcessesOption();
3133

3234
$this->setName('tenants:migrate-fresh');
3335
}
3436

3537
public function handle(): int
3638
{
39+
if (! $this->confirmToProceed()) {
40+
return 1;
41+
}
42+
3743
$success = true;
3844

3945
if ($this->getProcesses() > 1) {

src/Contracts/Feature.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44

55
namespace Stancl\Tenancy\Contracts;
66

7-
use Stancl\Tenancy\Tenancy;
8-
97
/** Additional features, like Telescope tags and tenant redirects. */
108
interface Feature
119
{
12-
public function bootstrap(Tenancy $tenancy): void;
10+
public function bootstrap(): void;
1311
}

src/Database/Concerns/HasPending.php

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@
66

77
use Carbon\Carbon;
88
use Illuminate\Database\Eloquent\Model;
9+
use Illuminate\Support\Facades\DB;
910
use Stancl\Tenancy\Contracts\Tenant;
1011
use Stancl\Tenancy\Events\CreatingPendingTenant;
1112
use Stancl\Tenancy\Events\PendingTenantCreated;
1213
use Stancl\Tenancy\Events\PendingTenantPulled;
1314
use Stancl\Tenancy\Events\PullingPendingTenant;
1415

15-
// todo consider adding a method that sets pending_since to null — to flag tenants as not-pending
16-
1716
/**
1817
* @property ?Carbon $pending_since
1918
*
@@ -50,46 +49,62 @@ public function pending(): bool
5049
*/
5150
public static function createPending(array $attributes = []): Model&Tenant
5251
{
53-
$tenant = static::create($attributes);
54-
55-
event(new CreatingPendingTenant($tenant));
56-
57-
// Update the pending_since value only after the tenant is created so it's
58-
// Not marked as pending until finishing running the migrations, seeders, etc.
59-
$tenant->update([
60-
'pending_since' => now()->timestamp,
61-
]);
52+
try {
53+
$tenant = static::create($attributes);
54+
event(new CreatingPendingTenant($tenant));
55+
} finally {
56+
// Update the pending_since value only after the tenant is created so it's
57+
// not marked as pending until after migrations, seeders, etc are run.
58+
$tenant->update([
59+
'pending_since' => now()->timestamp,
60+
]);
61+
}
6262

6363
event(new PendingTenantCreated($tenant));
6464

6565
return $tenant;
6666
}
6767

68-
/** Pull a pending tenant. */
69-
public static function pullPending(): Model&Tenant
68+
/**
69+
* Pull a pending tenant from the pool or create a new one if the pool is empty.
70+
*
71+
* @param array $attributes The attributes to set on the tenant.
72+
*/
73+
public static function pullPending(array $attributes = []): Model&Tenant
7074
{
7175
/** @var Model&Tenant $pendingTenant */
72-
$pendingTenant = static::pullPendingFromPool(true);
76+
$pendingTenant = static::pullPendingFromPool(true, $attributes);
7377

7478
return $pendingTenant;
7579
}
7680

77-
/** Try to pull a tenant from the pool of pending tenants. */
78-
public static function pullPendingFromPool(bool $firstOrCreate = true, array $attributes = []): ?Tenant
81+
/**
82+
* Try to pull a tenant from the pool of pending tenants.
83+
*
84+
* @param bool $firstOrCreate If true, a tenant will be *created* if the pool is empty. Otherwise null is returned.
85+
* @param array $attributes The attributes to set on the tenant.
86+
*/
87+
public static function pullPendingFromPool(bool $firstOrCreate = false, array $attributes = []): ?Tenant
7988
{
80-
/** @var (Model&Tenant)|null $tenant */
81-
$tenant = static::onlyPending()->first();
89+
$tenant = DB::transaction(function () use ($attributes): ?Tenant {
90+
/** @var (Model&Tenant)|null $tenant */
91+
$tenant = static::onlyPending()->first();
92+
93+
if ($tenant !== null) {
94+
event(new PullingPendingTenant($tenant));
95+
$tenant->update(array_merge($attributes, [
96+
'pending_since' => null,
97+
]));
98+
}
99+
100+
return $tenant;
101+
});
82102

83103
if ($tenant === null) {
84104
return $firstOrCreate ? static::create($attributes) : null;
85105
}
86106

87-
event(new PullingPendingTenant($tenant));
88-
89-
$tenant->update(array_merge($attributes, [
90-
'pending_since' => null,
91-
]));
92-
107+
// Only triggered if a tenant that was pulled from the pool is returned
93108
event(new PendingTenantPulled($tenant));
94109

95110
return $tenant;

0 commit comments

Comments
 (0)