Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tenant caching #540

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4b85835
Add cache_store
francoism90 Jun 25, 2024
7843fb0
Add UsesMultitenancyCaching
francoism90 Jun 25, 2024
3681e40
Fix return types
francoism90 Jun 25, 2024
c7f8e68
Update multitenancy.php
francoism90 Jun 25, 2024
9f5b49f
Update UsesMultitenancyCaching.php
francoism90 Jun 25, 2024
ccd2e63
Update UsesMultitenancyCaching.php
francoism90 Jun 25, 2024
6556013
Update UsesMultitenancyCaching.php
francoism90 Jun 25, 2024
5e513d5
Create TenantsCacheCommand
francoism90 Jun 25, 2024
03ffd2a
Create TenantsRefreshCommand
francoism90 Jun 25, 2024
faba545
Update MultitenancyServiceProvider.php
francoism90 Jun 25, 2024
ab180e2
Update UsesMultitenancyCaching.php
francoism90 Jun 25, 2024
9f71776
Update UsesMultitenancyCaching.php
francoism90 Jun 25, 2024
c2a0ad5
Add cache
francoism90 Jun 25, 2024
4fa3514
Create TenantsCacheCommandTest
francoism90 Jun 25, 2024
a56d8b2
Update UsesMultitenancyCaching.php
francoism90 Jun 25, 2024
812b7b2
Update TenantsCacheCommand
francoism90 Jun 25, 2024
f9daac1
Update TenantsRefreshCommand
francoism90 Jun 25, 2024
f69cab2
Update UsesMultitenancyCaching.php
francoism90 Jun 25, 2024
ab909bd
Rename TenantsCacheCommand to TenantsCacheCommand.php
francoism90 Jun 25, 2024
0a8b1f6
Rename TenantsRefreshCommand to TenantsRefreshCommand.php
francoism90 Jun 25, 2024
01ff4f6
Update DomainTenantFinder.php
francoism90 Jun 25, 2024
f18f25c
Update UsesMultitenancyCaching.php
francoism90 Jun 25, 2024
cdab2ba
Update UsesMultitenancyCaching.php
francoism90 Jun 25, 2024
570e730
Use false by default
francoism90 Jun 25, 2024
4ae177d
Create caching-tenants.md
francoism90 Jun 25, 2024
5f19de3
Add missing return
francoism90 Jun 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion config/multitenancy.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* This class should extend `Spatie\Multitenancy\TenantFinder\TenantFinder`
*
*/
'tenant_finder' => null,
'tenant_finder' => \Spatie\Multitenancy\TenantFinder\DomainTenantFinder::class,

/*
* These fields are used by tenant:artisan command to match one or more tenant.
Expand Down Expand Up @@ -70,6 +70,20 @@
*/
'current_tenant_container_key' => 'currentTenant',

/**
* This key specifies the name of a cache store. When set to `null`
* the default cache store will be used. If you do not want to use
* caching set this value to `false`.
*/
'cache_store' => false,

/*
* When cache_store is set to `true`, this value will be used to determine
* how long the cache will be valid. If you set this to `null` the
* cache will never expire.
*/
'cache_duration' => null,

/**
* Set it to `true` if you like to cache the tenant(s) routes
* in a shared file using the `SwitchRouteCacheTask`.
Expand Down
23 changes: 23 additions & 0 deletions docs/advanced-usage/caching-tenants.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: Caching tenants
weight: 10
---

When using many tenants, each tenant retrieval can have a performance impact on the database.
It is possible to cache the tenants to reduce the number of requests to the database.

To configure the cache store to use, or to disable caching, change the value of the `cache_store` in the `multitenancy` config file.

## Using cache

To build the tenant cache using the configured store:

```bash
php artisan tenants:cache
```

To clear the tenant cache using the configured store:

```bash
php artisan tenants:refresh
```
22 changes: 22 additions & 0 deletions src/Commands/TenantsCacheCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Spatie\Multitenancy\Commands;

use Illuminate\Console\Command;
use Spatie\Multitenancy\Concerns\UsesMultitenancyCaching;

class TenantsCacheCommand extends Command
{
use UsesMultitenancyCaching;

protected $signature = 'tenants:cache';

protected $description = 'Cache tenant models';

public function handle()
{
$this->info('Caching tenants...');

$this->createTenantCache();
}
}
22 changes: 22 additions & 0 deletions src/Commands/TenantsRefreshCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Spatie\Multitenancy\Commands;

use Illuminate\Console\Command;
use Spatie\Multitenancy\Concerns\UsesMultitenancyCaching;

class TenantsRefreshCommand extends Command
{
use UsesMultitenancyCaching;

protected $signature = 'tenants:refresh';

protected $description = 'Refresh tenant cache';

public function handle()
{
$this->info('Clearing tenant caches...');

$this->clearTenantCache();
}
}
69 changes: 69 additions & 0 deletions src/Concerns/UsesMultitenancyCaching.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace Spatie\Multitenancy\Concerns;

use Illuminate\Support\Collection;

trait UsesMultitenancyCaching
{
protected function createTenantCache(): void
{
$cacheStore = $this->getTenantCacheStore();

if ($cacheStore === false) {
return;
}

$cacheKey = $this->getTenantCacheKey();

$cacheDuration = $this->getTenantCacheDuration();

if ($cacheDuration === null) {
cache()
->store($cacheStore)
->rememberForever($cacheKey, fn () => $this->getTenantCollection());

return;
}

cache()
->store($cacheStore)
->remember($cacheKey, $cacheDuration, fn () => $this->getTenantCollection());
}

protected function clearTenantCache(): void
{
cache()
->store($this->getTenantCacheStore())
->delete($this->getTenantCacheKey());
}

protected function getTenantCache(): Collection
{
return cache()
->store($this->getTenantCacheStore())
->get($this->getTenantCacheKey(), collect());
}

protected function getTenantCollection(): Collection
{
$tenantModelClass = config('multitenancy.tenant_model');

return app($tenantModelClass)::all();
}

protected function getTenantCacheKey(): string
{
return config('multitenancy.cache_key', 'multitenancy');
}

protected function getTenantCacheDuration(): ?int
{
return config('multitenancy.cache_duration');
}

protected function getTenantCacheStore(): mixed
{
return config('multitenancy.cache_store');
}
}
8 changes: 7 additions & 1 deletion src/MultitenancyServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
use Spatie\Multitenancy\Commands\TenantsArtisanCommand;
use Spatie\Multitenancy\Commands\TenantsCacheCommand;
use Spatie\Multitenancy\Commands\TenantsRefreshCommand;
use Spatie\Multitenancy\Concerns\UsesMultitenancyConfig;
use Spatie\Multitenancy\Models\Concerns\UsesTenantModel;

Expand All @@ -22,7 +24,11 @@ public function configurePackage(Package $package): void
->name('laravel-multitenancy')
->hasConfigFile()
->hasMigration('landlord/create_landlord_tenants_table')
->hasCommand(TenantsArtisanCommand::class);
->hasCommands([
TenantsArtisanCommand::class,
TenantsCacheCommand::class,
TenantsRefreshCommand::class,
]);
}

public function packageBooted(): void
Expand Down
15 changes: 14 additions & 1 deletion src/TenantFinder/DomainTenantFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,30 @@
namespace Spatie\Multitenancy\TenantFinder;

use Illuminate\Http\Request;
use Spatie\Multitenancy\Concerns\UsesMultitenancyCaching;
use Spatie\Multitenancy\Models\Concerns\UsesTenantModel;
use Spatie\Multitenancy\Models\Tenant;

class DomainTenantFinder extends TenantFinder
{
use UsesMultitenancyCaching;
use UsesTenantModel;

public function findForRequest(Request $request): ?Tenant
{
$host = $request->getHost();

return $this->getTenantModel()::whereDomain($host)->first();
if ($this->getTenantCacheStore() === false) {
return $this->findTenantByDomain($host);
}

$cache = $this->getTenantCache();

return $cache->firstWhere('domain', $host) ?? $this->findTenantByDomain($host);
}

protected function findTenantByDomain(string $domain): ?Tenant
{
return $this->getTenantModel()::firstWhere('domain', $domain);
}
}
13 changes: 13 additions & 0 deletions tests/Feature/Commands/TenantsCacheCommandTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

it('can cache tenants', function () {
$this
->artisan('tenants:cache')
->assertExitCode(0);
});

it('can refresh tenants', function () {
$this
->artisan('tenants:refresh')
->assertExitCode(0);
});
Loading