rasuvaeff/yii3-tenancy-db

Database tenant storage for rasuvaeff/yii3-tenancy

Maintainers

Package info

github.com/rasuvaeff/yii3-tenancy-db

pkg:composer/rasuvaeff/yii3-tenancy-db

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v2.0.0 2026-07-25 13:27 UTC

This package is auto-updated.

Last update: 2026-07-25 13:27:52 UTC


README

Stable Version Total Downloads Build Static analysis Psalm level PHP License Русская версия

Database tenant storage for rasuvaeff/yii3-tenancy: TenantProvider backed by a tenants table via yiisoft/db, an optional PSR-16 read-through cache, and a ready-made migration.

Using an AI coding assistant? llms.txt contains a compact API reference you can share with the model. Contributors: see AGENTS.md.

Requirements

Requirement Version
PHP 8.3 – 8.5
rasuvaeff/yii3-tenancy ^1.0
yiisoft/db ^2.0
yiisoft/db-migration ^2.0 (for the bundled migration)

Installation

composer require rasuvaeff/yii3-tenancy-db

Register the bundled migration by namespace — no vendor paths:

// config/common/di/migration.php
use Yiisoft\Db\Migration\Service\MigrationService;

return [
    MigrationService::class => [
        'setSourceNamespaces()' => [['App\\Migration', 'Rasuvaeff\\Yii3TenancyDb\\Migration']],
    ],
];
./yii migrate:up

Set the table name in params — config/di.php turns it into a TenantsTableName that reaches the migration and DbTenantProvider:

// config/common/params.php
'rasuvaeff/yii3-tenancy-db' => [
    'table' => 'my_tenants',
    'table_prefix' => '',   // prepended to `table`; e.g. 'rsv_' → rsv_my_tenants
],

Do not configure the migration through the DI container. M...::class => ['__construct()' => ['table' => ...]] does not work: the migration is built by Injector::make(), which resolves arguments by type and never reads a container definition keyed by the migration's own class. Worse, adding that definition makes the container fatal at build time in every request, because the class is not autoloadable until the migration runner requires it. That recipe was documented in 1.x; it never worked.

Usage

With yiisoft/config no wiring is needed — this package binds TenantProvider to DbTenantProvider (the core deliberately leaves that interface unbound; installing core + this backend just works):

use Rasuvaeff\Yii3Tenancy\CurrentTenant;

final readonly class InvoiceService
{
    public function __construct(private CurrentTenant $currentTenant) {}
    // TenantResolutionMiddleware looks tenants up through DbTenantProvider
}

Manual construction:

use Rasuvaeff\Yii3TenancyDb\CachedTenantProvider;
use Rasuvaeff\Yii3TenancyDb\DbTenantProvider;

$provider = new DbTenantProvider(db: $connection, table: 'tenants');

// optional PSR-16 read-through cache
$cached = new CachedTenantProvider(inner: $provider, cache: $psr16, ttl: 60);
$cached->forget('acme');   // drop the entry after updating/suspending a tenant

Caching semantics: only found tenants are cached (a newly created tenant appears immediately); cache read/write failures are non-fatal; entries expire by TTL or explicit forget().

Enable the cache through params:

// config/params.php
return [
    'rasuvaeff/yii3-tenancy-db' => [
        'table' => 'tenants',
        'cache' => ['enabled' => true, 'ttl' => 60],
    ],
];

Table schema

Column Type Notes
id string(64) PK must satisfy core Tenant::isValidId()
name string(190) default ''
status string(20) active (default) / suspended
attributes text JSON object, default '{}'

Invalid rows (unknown status, malformed JSON, invalid id) throw InvalidTenantRowException — never silently skipped or defaulted.

Components

Class Role
DbTenantProvider TenantProvider over yiisoft/db: single-row find() by primary key
CachedTenantProvider PSR-16 read-through decorator (yii3-tenancy-db.tenant.{key}), forget() invalidation
Exception\InvalidTenantRowException thrown by the internal row mapper on invalid rows

Security

  • Lookups use bound parameters via the yiisoft/db query builder — no SQL string interpolation.
  • The table name is configuration (developer-controlled), not user input.
  • Rows are strictly validated on read; a corrupted row fails loudly instead of producing a half-valid tenant.

Examples

See examples/ for a runnable script.

Script Shows Needs server?
db-provider.php Migration + lookup + cached lookup on in-memory SQLite no

Development

No PHP/Composer on the host — run in Docker via the composer:2 image:

docker run --rm -v "$PWD":/app -w /app composer:2 composer build

Or with Make: make build, make cs-fix, make psalm, make test.

License

BSD-3-Clause. See LICENSE.md.