mirror of
https://github.com/archtechx/tenancy.git
synced 2026-02-05 08:14:02 +00:00
Ditch models for custom repositories
This commit is contained in:
parent
58f488784f
commit
a7cdfdacb4
7 changed files with 284 additions and 274 deletions
|
|
@ -13,8 +13,8 @@ return [
|
||||||
],
|
],
|
||||||
'connection' => null, // Your central database connection. Set to null to use the default connection.
|
'connection' => null, // Your central database connection. Set to null to use the default connection.
|
||||||
'table_names' => [
|
'table_names' => [
|
||||||
'TenantModel' => 'tenants',
|
'tenants' => 'tenants',
|
||||||
'DomainModel' => 'domains',
|
'domains' => 'domains',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'redis' => [
|
'redis' => [
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Stancl\Tenancy\StorageDrivers\Database;
|
namespace Stancl\Tenancy\StorageDrivers\Database;
|
||||||
|
|
||||||
|
use Illuminate\Config\Repository as ConfigRepository;
|
||||||
|
use Illuminate\Database\Connection;
|
||||||
use Illuminate\Foundation\Application;
|
use Illuminate\Foundation\Application;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Stancl\Tenancy\Contracts\Future\CanDeleteKeys;
|
use Stancl\Tenancy\Contracts\Future\CanDeleteKeys;
|
||||||
|
|
@ -13,8 +15,6 @@ use Stancl\Tenancy\Exceptions\DomainsOccupiedByOtherTenantException;
|
||||||
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedException;
|
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedException;
|
||||||
use Stancl\Tenancy\Exceptions\TenantDoesNotExistException;
|
use Stancl\Tenancy\Exceptions\TenantDoesNotExistException;
|
||||||
use Stancl\Tenancy\Exceptions\TenantWithThisIdAlreadyExistsException;
|
use Stancl\Tenancy\Exceptions\TenantWithThisIdAlreadyExistsException;
|
||||||
use Stancl\Tenancy\StorageDrivers\Database\DomainModel as Domains;
|
|
||||||
use Stancl\Tenancy\StorageDrivers\Database\TenantModel as Tenants;
|
|
||||||
use Stancl\Tenancy\Tenant;
|
use Stancl\Tenancy\Tenant;
|
||||||
|
|
||||||
class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys
|
class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys
|
||||||
|
|
@ -22,24 +22,32 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys
|
||||||
/** @var Application */
|
/** @var Application */
|
||||||
protected $app;
|
protected $app;
|
||||||
|
|
||||||
/** @var \Illuminate\Database\Connection */
|
/** @var Connection */
|
||||||
protected $centralDatabase;
|
protected $centralDatabase;
|
||||||
|
|
||||||
|
/** @var TenantRepository */
|
||||||
|
protected $tenants;
|
||||||
|
|
||||||
|
/** @var DomainRepository */
|
||||||
|
protected $domains;
|
||||||
|
|
||||||
/** @var Tenant The default tenant. */
|
/** @var Tenant The default tenant. */
|
||||||
protected $tenant;
|
protected $tenant;
|
||||||
|
|
||||||
public function __construct(Application $app)
|
public function __construct(Application $app, ConfigRepository $config)
|
||||||
{
|
{
|
||||||
$this->app = $app;
|
$this->app = $app;
|
||||||
$this->centralDatabase = $this->getCentralConnection();
|
$this->centralDatabase = $this->getCentralConnection();
|
||||||
|
$this->tenants = new TenantRepository($this->centralDatabase, $config);
|
||||||
|
$this->domains = new DomainRepository($this->centralDatabase, $config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the central database connection.
|
* Get the central database connection.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Connection
|
* @return Connection
|
||||||
*/
|
*/
|
||||||
public static function getCentralConnection(): \Illuminate\Database\Connection
|
public static function getCentralConnection(): Connection
|
||||||
{
|
{
|
||||||
return DB::connection(static::getCentralConnectionName());
|
return DB::connection(static::getCentralConnectionName());
|
||||||
}
|
}
|
||||||
|
|
@ -51,7 +59,7 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys
|
||||||
|
|
||||||
public function findByDomain(string $domain): Tenant
|
public function findByDomain(string $domain): Tenant
|
||||||
{
|
{
|
||||||
$id = $this->getTenantIdByDomain($domain);
|
$id = $this->domains->getTenantIdByDomain($domain);
|
||||||
if (! $id) {
|
if (! $id) {
|
||||||
throw new TenantCouldNotBeIdentifiedException($domain);
|
throw new TenantCouldNotBeIdentifiedException($domain);
|
||||||
}
|
}
|
||||||
|
|
@ -61,14 +69,14 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys
|
||||||
|
|
||||||
public function findById(string $id): Tenant
|
public function findById(string $id): Tenant
|
||||||
{
|
{
|
||||||
$tenant = Tenants::find($id);
|
$tenant = $this->tenants->find($id);
|
||||||
|
|
||||||
if (! $tenant) {
|
if (! $tenant) {
|
||||||
throw new TenantDoesNotExistException($id);
|
throw new TenantDoesNotExistException($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Tenant::fromStorage($tenant->decoded())
|
return Tenant::fromStorage($this->tenants->decodeData($tenant))
|
||||||
->withDomains($this->getTenantDomains($id));
|
->withDomains($this->domains->getTenantDomains($id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -81,31 +89,24 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys
|
||||||
*/
|
*/
|
||||||
public function findBy(string $key, $value): Tenant
|
public function findBy(string $key, $value): Tenant
|
||||||
{
|
{
|
||||||
// The key has to be a custom column. It's recommended to set up an index
|
// The key has to be a custom column. It's recommended to set up an index // TODO can we query JSON?
|
||||||
$tenant = Tenants::where($key, $value)->first();
|
$tenant = $this->tenants->where($key, $value)->first()->toArray();
|
||||||
|
|
||||||
if (! $tenant) {
|
if (! $tenant) {
|
||||||
throw new TenantDoesNotExistException($value, $key);
|
throw new TenantDoesNotExistException($value, $key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Tenant::fromStorage($tenant->decoded())
|
return Tenant::fromStorage($tenant->decoded())
|
||||||
->withDomains($this->getTenantDomains($tenant->id));
|
->withDomains($this->domains->getTenantDomains($tenant->id));
|
||||||
}
|
|
||||||
|
|
||||||
protected function getTenantDomains($id)
|
|
||||||
{
|
|
||||||
return Domains::where('tenant_id', $id)->get()->map(function ($model) {
|
|
||||||
return $model->domain;
|
|
||||||
})->toArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ensureTenantCanBeCreated(Tenant $tenant): void
|
public function ensureTenantCanBeCreated(Tenant $tenant): void
|
||||||
{
|
{
|
||||||
if (Tenants::find($tenant->id)) {
|
if ($this->tenants->exists($tenant)) {
|
||||||
throw new TenantWithThisIdAlreadyExistsException($tenant->id);
|
throw new TenantWithThisIdAlreadyExistsException($tenant->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Domains::whereIn('domain', $tenant->domains)->exists()) {
|
if ($this->domains->occupied($tenant->domains)) {
|
||||||
throw new DomainsOccupiedByOtherTenantException;
|
throw new DomainsOccupiedByOtherTenantException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -117,53 +118,32 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTenantIdByDomain(string $domain): ?string
|
|
||||||
{
|
|
||||||
return Domains::where('domain', $domain)->first()->tenant_id ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createTenant(Tenant $tenant): void
|
public function createTenant(Tenant $tenant): void
|
||||||
{
|
{
|
||||||
$this->centralDatabase->transaction(function () use ($tenant) {
|
$this->centralDatabase->transaction(function () use ($tenant) {
|
||||||
Tenants::create(array_merge(Tenants::encodeData($tenant->data), [
|
$this->tenants->insert(array_merge(
|
||||||
'id' => $tenant->id,
|
$this->tenants->encodeData($tenant->data),
|
||||||
]))->toArray();
|
[] // ['id' => $tenant->id] // todo remove this line if things work
|
||||||
|
));
|
||||||
|
|
||||||
$domainData = [];
|
$this->domains->insertTenantDomains($tenant);
|
||||||
foreach ($tenant->domains as $domain) {
|
|
||||||
$domainData[] = ['domain' => $domain, 'tenant_id' => $tenant->id];
|
|
||||||
}
|
|
||||||
|
|
||||||
Domains::insert($domainData);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateTenant(Tenant $tenant): void
|
public function updateTenant(Tenant $tenant): void
|
||||||
{
|
{
|
||||||
$this->centralDatabase->transaction(function () use ($tenant) {
|
$this->centralDatabase->transaction(function () use ($tenant) {
|
||||||
Tenants::find($tenant->id)->putMany($tenant->data);
|
$this->tenants->updateTenant($tenant);
|
||||||
|
|
||||||
$original_domains = Domains::where('tenant_id', $tenant->id)->get()->map(function ($model) {
|
$this->domains->updateTenantDomains($tenant);
|
||||||
return $model->domain;
|
|
||||||
})->toArray();
|
|
||||||
$deleted_domains = array_diff($original_domains, $tenant->domains);
|
|
||||||
|
|
||||||
Domains::whereIn('domain', $deleted_domains)->delete();
|
|
||||||
|
|
||||||
foreach ($tenant->domains as $domain) {
|
|
||||||
Domains::firstOrCreate([
|
|
||||||
'tenant_id' => $tenant->id,
|
|
||||||
'domain' => $domain,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteTenant(Tenant $tenant): void
|
public function deleteTenant(Tenant $tenant): void
|
||||||
{
|
{
|
||||||
$this->centralDatabase->transaction(function () use ($tenant) {
|
$this->centralDatabase->transaction(function () use ($tenant) {
|
||||||
Tenants::find($tenant->id)->delete();
|
$this->tenants->find($tenant)->delete();
|
||||||
Domains::where('tenant_id', $tenant->id)->delete();
|
$this->domains->where('tenant_id', $tenant->id)->delete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,8 +155,8 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys
|
||||||
*/
|
*/
|
||||||
public function all(array $ids = []): array
|
public function all(array $ids = []): array
|
||||||
{
|
{
|
||||||
return Tenants::getAllTenants($ids)->map(function ($data) {
|
return $this->tenants->all($ids)->map(function ($data) {
|
||||||
return Tenant::fromStorage($data)->withDomains($this->getTenantDomains($data['id']));
|
return Tenant::fromStorage($data)->withDomains($this->domains->getTenantDomains($data['id']));
|
||||||
})->toArray();
|
})->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,53 +172,26 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys
|
||||||
|
|
||||||
public function get(string $key, Tenant $tenant = null)
|
public function get(string $key, Tenant $tenant = null)
|
||||||
{
|
{
|
||||||
$tenant = $tenant ?? $this->currentTenant();
|
return $this->tenants->get($key, $tenant ?? $this->currentTenant());
|
||||||
|
|
||||||
return Tenants::find($tenant->id)->get($key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMany(array $keys, Tenant $tenant = null): array
|
public function getMany(array $keys, Tenant $tenant = null): array
|
||||||
{
|
{
|
||||||
$tenant = $tenant ?? $this->currentTenant();
|
return $this->tenants->getMany($keys, $tenant ?? $this->currentTenant());
|
||||||
|
|
||||||
return Tenants::find($tenant->id)->getMany($keys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function put(string $key, $value, Tenant $tenant = null): void
|
public function put(string $key, $value, Tenant $tenant = null): void
|
||||||
{
|
{
|
||||||
$tenant = $tenant ?? $this->currentTenant();
|
$this->tenants->put($key, $value, $tenant ?? $this->currentTenant());
|
||||||
Tenants::find($tenant->id)->put($key, $value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function putMany(array $kvPairs, Tenant $tenant = null): void
|
public function putMany(array $kvPairs, Tenant $tenant = null): void
|
||||||
{
|
{
|
||||||
$tenant = $tenant ?? $this->currentTenant();
|
$this->tenants->putMany($kvPairs, $tenant ?? $this->currentTenant());
|
||||||
Tenants::find($tenant->id)->putMany($kvPairs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteMany(array $keys, Tenant $tenant = null): void
|
public function deleteMany(array $keys, Tenant $tenant = null): void
|
||||||
{
|
{
|
||||||
$tenant = $tenant ?? $this->currentTenant();
|
$this->tenants->deleteMany($keys, $tenant ?? $this->currentTenant());
|
||||||
Tenants::find($tenant->id)->deleteMany($keys);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TenantModelTODO
|
|
||||||
{
|
|
||||||
public static function makeTenant($data, $domains)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findBy(string $key, $value)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO Use this w/ DB builder calls instead of an Eloquent model
|
|
||||||
}
|
|
||||||
|
|
||||||
class DomainModelTODO
|
|
||||||
{
|
|
||||||
// TODO Use this w/ DB builder calls instead of an Eloquent model
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Stancl\Tenancy\StorageDrivers\Database;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal Class is subject to breaking changes in minor and patch versions.
|
|
||||||
*/
|
|
||||||
class DomainModel extends Model
|
|
||||||
{
|
|
||||||
use CentralConnection;
|
|
||||||
|
|
||||||
protected $guarded = [];
|
|
||||||
protected $primaryKey = 'domain';
|
|
||||||
public $incrementing = false;
|
|
||||||
public $timestamps = false;
|
|
||||||
|
|
||||||
public function getTable()
|
|
||||||
{
|
|
||||||
return config('tenancy.storage_drivers.db.table_names.DomainModel', 'domains');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
55
src/StorageDrivers/Database/DomainRepository.php
Normal file
55
src/StorageDrivers/Database/DomainRepository.php
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Stancl\Tenancy\StorageDrivers\Database;
|
||||||
|
|
||||||
|
use Illuminate\Config\Repository as ConfigRepository;
|
||||||
|
use Stancl\Tenancy\Tenant;
|
||||||
|
|
||||||
|
class DomainRepository extends Repository
|
||||||
|
{
|
||||||
|
public function getTenantIdByDomain(string $domain): string
|
||||||
|
{
|
||||||
|
return $this->where('domain', $domain)->first()->tenant_id ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function occupied(array $domains): bool
|
||||||
|
{
|
||||||
|
return $this->whereIn('domain', $domains)->exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTenantDomains($tenant)
|
||||||
|
{
|
||||||
|
$id = $tenant instanceof Tenant ? $tenant->id : $tenant;
|
||||||
|
return $this->where('tenant_id', $id)->get('domain')->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insertTenantDomains(Tenant $tenant)
|
||||||
|
{
|
||||||
|
$this->insert(array_map(function ($domain) use ($tenant) {
|
||||||
|
return ['domain' => $domain, 'tenant_id' => $tenant->id];
|
||||||
|
}, $tenant->domains));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateTenantDomains(Tenant $tenant)
|
||||||
|
{
|
||||||
|
$originalDomains = $this->domains->getTenantDomains($tenant);
|
||||||
|
$deletedDomains = array_diff($originalDomains, $tenant->domains);
|
||||||
|
$newDomains = array_intersect($originalDomains, $tenant->domains);
|
||||||
|
|
||||||
|
$this->domains->whereIn('domain', $deletedDomains)->delete();
|
||||||
|
|
||||||
|
foreach ($newDomains as $domain) {
|
||||||
|
$this->insert([
|
||||||
|
'tenant_id' => $tenant->id,
|
||||||
|
'domain' => $domain,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTable(ConfigRepository $config)
|
||||||
|
{
|
||||||
|
return $config->get('tenancy.storage_drivers.db.table_names.DomainModel') // legacy
|
||||||
|
?? $config->get('tenancy.storage_drivers.db.table_names.domains')
|
||||||
|
?? 'domains';
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/StorageDrivers/Database/Repository.php
Normal file
30
src/StorageDrivers/Database/Repository.php
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Stancl\Tenancy\StorageDrivers\Database;
|
||||||
|
|
||||||
|
use Illuminate\Config\Repository as ConfigRepository;
|
||||||
|
use Illuminate\Database\Connection;
|
||||||
|
use Illuminate\Database\Query\Builder;
|
||||||
|
|
||||||
|
/** @mixin Builder */
|
||||||
|
abstract class Repository
|
||||||
|
{
|
||||||
|
/** @var Connection */
|
||||||
|
protected $database;
|
||||||
|
|
||||||
|
/** @var Builder */
|
||||||
|
protected $table;
|
||||||
|
|
||||||
|
public function __construct(Connection $database, ConfigRepository $config)
|
||||||
|
{
|
||||||
|
$this->database = $database;
|
||||||
|
$this->table = $database->table($this->getTable($config));
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function getTable(ConfigRepository $config);
|
||||||
|
|
||||||
|
public function __call($method, $parameters)
|
||||||
|
{
|
||||||
|
return $this->table->$method(...$parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Stancl\Tenancy\StorageDrivers\Database;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal Class is subject to breaking changes in minor and patch versions.
|
|
||||||
*/
|
|
||||||
class TenantModel extends Model
|
|
||||||
{
|
|
||||||
use CentralConnection;
|
|
||||||
|
|
||||||
protected $guarded = [];
|
|
||||||
protected $primaryKey = 'id';
|
|
||||||
public $incrementing = false;
|
|
||||||
public $timestamps = false;
|
|
||||||
|
|
||||||
public function getTable()
|
|
||||||
{
|
|
||||||
return config('tenancy.storage_drivers.db.table_names.TenantModel', 'tenants');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function dataColumn()
|
|
||||||
{
|
|
||||||
return config('tenancy.storage_drivers.db.data_column', 'data');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function customColumns()
|
|
||||||
{
|
|
||||||
return config('tenancy.storage_drivers.db.custom_columns', []);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function encodeData(array $data)
|
|
||||||
{
|
|
||||||
$result = [];
|
|
||||||
$jsonData = [];
|
|
||||||
|
|
||||||
foreach ($data as $key => $value) {
|
|
||||||
if (in_array($key, static::customColumns(), true)) {
|
|
||||||
$result[$key] = $value;
|
|
||||||
} else {
|
|
||||||
$jsonData[$key] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$result['data'] = $jsonData ? json_encode($jsonData) : '{}';
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getAllTenants(array $ids)
|
|
||||||
{
|
|
||||||
$tenants = $ids ? static::findMany($ids) : static::all();
|
|
||||||
|
|
||||||
return $tenants->map([__CLASS__, 'decodeData'])->toBase();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function decoded()
|
|
||||||
{
|
|
||||||
return static::decodeData($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a tenant array with data decoded into separate keys.
|
|
||||||
*
|
|
||||||
* @param self|array $tenant
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function decodeData($tenant)
|
|
||||||
{
|
|
||||||
$tenant = $tenant instanceof self ? (array) $tenant->attributes : $tenant;
|
|
||||||
$decoded = json_decode($tenant[$dataColumn = static::dataColumn()], true);
|
|
||||||
|
|
||||||
foreach ($decoded as $key => $value) {
|
|
||||||
$tenant[$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If $tenant[$dataColumn] has been overriden by a value, don't delete the key.
|
|
||||||
if (! array_key_exists($dataColumn, $decoded)) {
|
|
||||||
unset($tenant[$dataColumn]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tenant;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFromData(string $key)
|
|
||||||
{
|
|
||||||
$this->dataArray = $this->dataArray ?? json_decode($this->{$this->dataColumn()}, true);
|
|
||||||
|
|
||||||
return $this->dataArray[$key] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get(string $key)
|
|
||||||
{
|
|
||||||
return $this->attributes[$key] ?? $this->getFromData($key) ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMany(array $keys): array
|
|
||||||
{
|
|
||||||
return array_reduce($keys, function ($result, $key) {
|
|
||||||
$result[$key] = $this->get($key);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function put(string $key, $value)
|
|
||||||
{
|
|
||||||
if (in_array($key, $this->customColumns())) {
|
|
||||||
$this->update([$key => $value]);
|
|
||||||
} else {
|
|
||||||
$obj = json_decode($this->{$this->dataColumn()});
|
|
||||||
$obj->$key = $value;
|
|
||||||
|
|
||||||
$this->update([$this->dataColumn() => json_encode($obj)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function putMany(array $kvPairs)
|
|
||||||
{
|
|
||||||
$customColumns = [];
|
|
||||||
$jsonObj = json_decode($this->{$this->dataColumn()});
|
|
||||||
|
|
||||||
foreach ($kvPairs as $key => $value) {
|
|
||||||
if (in_array($key, $this->customColumns())) {
|
|
||||||
$customColumns[$key] = $value;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$jsonObj->$key = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->update(array_merge($customColumns, [
|
|
||||||
$this->dataColumn() => json_encode($jsonObj),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deleteKeys(array $keys)
|
|
||||||
{
|
|
||||||
$customColumns = [];
|
|
||||||
$jsonObj = json_decode($this->{$this->dataColumn()});
|
|
||||||
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
if (in_array($key, $this->customColumns())) {
|
|
||||||
$customColumns[$key] = null;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($jsonObj->$key);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->update(array_merge($customColumns, [
|
|
||||||
$this->dataColumn() => json_encode($jsonObj),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
158
src/StorageDrivers/Database/TenantRepository.php
Normal file
158
src/StorageDrivers/Database/TenantRepository.php
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Stancl\Tenancy\StorageDrivers\Database;
|
||||||
|
|
||||||
|
use Illuminate\Config\Repository as ConfigRepository;
|
||||||
|
use Stancl\Tenancy\Tenant;
|
||||||
|
|
||||||
|
class TenantRepository extends Repository
|
||||||
|
{
|
||||||
|
public function all($ids = [])
|
||||||
|
{
|
||||||
|
if ($ids) {
|
||||||
|
return $this->whereIn('id', $ids)->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->table->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($tenant)
|
||||||
|
{
|
||||||
|
return $this->table->find(
|
||||||
|
$tenant instanceof Tenant ? $tenant->id : $tenant
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateTenant(Tenant $tenant)
|
||||||
|
{
|
||||||
|
$this->putMany($tenant->data, $tenant);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exists(Tenant $tenant)
|
||||||
|
{
|
||||||
|
return $this->where('id', $tenant->id)->exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $key, Tenant $tenant)
|
||||||
|
{
|
||||||
|
return $this->decodedData($tenant)[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMany(array $keys, Tenant $tenant)
|
||||||
|
{
|
||||||
|
$decodedData = $this->decodedData($tenant);
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$result[$key] = $decodedData[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function put(string $key, $value, Tenant $tenant)
|
||||||
|
{
|
||||||
|
$record = $this->where('id', $tenant->id);
|
||||||
|
|
||||||
|
if (in_array($key, static::customColumns())) {
|
||||||
|
$record->update([$key => $value]);
|
||||||
|
} else {
|
||||||
|
$data = json_decode($record->first(static::dataColumn()), true);
|
||||||
|
$data[$key] = $value;
|
||||||
|
|
||||||
|
$record->update([static::dataColumn() => $data]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function putMany(array $kvPairs, Tenant $tenant)
|
||||||
|
{
|
||||||
|
$record = $this->where('id', $tenant->id);
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
$jsonData = json_decode($record->first(static::dataColumn()), true);
|
||||||
|
foreach ($kvPairs as $key => $value) {
|
||||||
|
if (in_array($key, static::customColumns())) {
|
||||||
|
$data[$key] = $value;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
$jsonData[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[static::dataColumn()] = json_encode($jsonData);
|
||||||
|
|
||||||
|
$record->update($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteMany(array $keys, Tenant $tenant)
|
||||||
|
{
|
||||||
|
$record = $this->where('id', $tenant->id);
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
$jsonData = json_decode($record->first(static::dataColumn()), true);
|
||||||
|
foreach ($keys as $key => $key) {
|
||||||
|
if (in_array($key, static::customColumns())) {
|
||||||
|
$data[$key] = null;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
unset($jsonData[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[static::dataColumn()] = json_encode($jsonData);
|
||||||
|
|
||||||
|
$record->update($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function decodedData($tenant): array
|
||||||
|
{
|
||||||
|
return $this->decodeData(
|
||||||
|
$this->table->where('id', $tenant->id)->get()->toArray()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function decodeData(array $columns): array
|
||||||
|
{
|
||||||
|
$dataColumn = static::dataColumn();
|
||||||
|
$decoded = json_decode($columns[$dataColumn], true);
|
||||||
|
$columns = array_merge($columns, $decoded);
|
||||||
|
|
||||||
|
// If $columns[$dataColumn] has been overriden by a value, don't delete the key.
|
||||||
|
if (! array_key_exists($dataColumn, $decoded)) {
|
||||||
|
unset($columns[$dataColumn]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function encodeData(array $data): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
foreach (array_intersect(static::customColumns(), array_keys($data)) as $customColumn) {
|
||||||
|
$result[$customColumn] = $data[$customColumn];
|
||||||
|
unset($data[$customColumn]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = array_merge($result, [static::dataColumn() => json_encode($data)]);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function customColumns(): array
|
||||||
|
{
|
||||||
|
return config('tenancy.storage_drivers.db.custom_columns', []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function dataColumn(): string
|
||||||
|
{
|
||||||
|
return config('tenancy.storage_drivers.db.data_column', 'data');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTable(ConfigRepository $config)
|
||||||
|
{
|
||||||
|
return $config->get('tenancy.storage_drivers.db.table_names.TenantModel') // legacy
|
||||||
|
?? $config->get('tenancy.storage_drivers.db.table_names.tenants')
|
||||||
|
?? 'tenants';
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue