PHP code example of monkeyscloud / monkeyslegion-tenancy

1. Go to this page and download the library: Download monkeyscloud/monkeyslegion-tenancy library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

monkeyscloud / monkeyslegion-tenancy example snippets


// Mark entities as tenant-scoped
#[Entity(table: 'invoices')]
#[BelongsToTenant]
class Invoice
{
    #[Id]
    public private(set) int $id;

    #[Field(type: 'string')]
    public string $title;

    // tenant_id column is auto-managed — you don't touch it
}

// Automatically switches to tenant schema on each request
// PostgreSQL: SET search_path TO "tenant_acme", public
// MySQL:      USE `tenant_acme`

// 1. Subdomain: "acme.example.com" → tenant key "acme"
// 2. HTTP Header: X-Tenant-ID: acme
// 3. URL Path: /t/acme/dashboard
// 4. Full Domain: custom-domain.com → tenants.domain match
// 5. Query Parameter: ?tenant=acme

use MonkeysLegion\Tenancy\Context\TenantContext;

// Set by middleware automatically, but can be used manually
TenantContext::set($tenant);

// Quick access
$tenant = TenantContext::get();        // ?TenantInterface
$id     = TenantContext::id();         // int|string|null
$key    = TenantContext::key();        // ?string
$tenant = TenantContext::text restored here

use MonkeysLegion\Tenancy\Scope\TenantScope;

// Before your query, apply tenant scoping
$result = TenantScope::apply(
    "SELECT * FROM invoices WHERE status = :status",
    ['status' => 'paid'],
);
// Result: "SELECT * FROM invoices WHERE tenant_id = :__tenant_scope_id AND status = :status"
// Params: ['status' => 'paid', '__tenant_scope_id' => 42]

$stmt = $conn->query($result['sql'], $result['params']);

$data = TenantScope::insertData();
// Returns: ['tenant_id' => 42]
// Merge into your INSERT data to auto-set the tenant column

// Validates a row belongs to the current tenant — throws on mismatch
TenantScope::validate($row);

use MonkeysLegion\Tenancy\Scope\TenantScopeListener;

// Auto-inject tenant_id on INSERT
$data = TenantScopeListener::beforeInsert($entity, $data);

// Validate before UPDATE/DELETE
TenantScopeListener::beforeMutation($entity, $data);

use MonkeysLegion\Tenancy\Lifecycle\TenantManager;
use MonkeysLegion\Tenancy\Enum\TenancyMode;

$manager = $container->get(TenantManager::class);

// Create a new tenant (auto-provisions schema, runs migrations, activates)
$tenant = $manager->create(
    key: 'acme',
    name: 'Acme Corporation',
    mode: TenancyMode::Schema,
    plan: 'enterprise',
    domain: 'acme.example.com',
    migrationSqls: [
        'CREATE TABLE invoices (...)',
        'CREATE TABLE projects (...)',
    ],
);

// Suspend (e.g., payment overdue)
$manager->suspend($tenant, reason: 'Payment overdue — invoice #1234');

// Reactivate
$manager->activate($tenant);

// Soft delete (sets status = 'deleted')
$manager->delete($tenant);

// Hard delete (drops schema/DB, removes row)
$manager->delete($tenant, hard: true);

// List all active tenants
$tenants = $manager->all();

// Find by key
$tenant = $manager->findByKey('acme');

$migration = $container->get(TenantMigrationRunner::class);
$migration->ensureCentralTable();

use MonkeysLegion\Tenancy\Infrastructure\TenantCacheAdapter;

$adapter = $container->get(TenantCacheAdapter::class);

$cacheKey = $adapter->key('user:42');
// → "tenant:5:user:42"

$tag = $adapter->tag('reports');
// → "tenant_5:reports"

$pattern = $adapter->flushPattern();
// → "tenant:5:*"

use MonkeysLegion\Tenancy\Infrastructure\TenantQueueAdapter;

$adapter = $container->get(TenantQueueAdapter::class);

$queueName = $adapter->queueName();
// → "tenant_acme"

// Enrich job payload with tenant metadata
$payload = $adapter->enrichPayload(['job' => 'SendInvoice', 'invoice_id' => 99]);
// → ['job' => 'SendInvoice', 'invoice_id' => 99, '__tenant_id' => 5, '__tenant_key' => 'acme']

// Restore tenant context in the worker
$info = $adapter->extractTenantFromPayload($payload);
// → ['tenant_id' => 5, 'tenant_key' => 'acme']

use MonkeysLegion\Tenancy\Infrastructure\TenantStorageAdapter;

$adapter = $container->get(TenantStorageAdapter::class);

$path = $adapter->path('uploads/logo.png');
// → "/app/storage/tenants/acme/uploads/logo.png"

$root = $adapter->tenantRoot();
// → "/app/storage/tenants/acme/"

// Path traversal protection — this throws:
$adapter->path('../../etc/passwd'); // RuntimeException!

use MonkeysLegion\Tenancy\Infrastructure\TenantSessionAdapter;

$key = TenantSessionAdapter::key('cart_items');
// → "t5:cart_items"

$name = TenantSessionAdapter::sessionName();
// → "MLSESSID_t5"

// Listen to tenant events for audit/telemetry
$dispatcher->listen(TenantResolved::class, function (TenantResolved $event) {
    $logger->info("Tenant resolved: {$event->tenant->getKey()} via {$event->resolverClass}");
});

$dispatcher->listen(TenantSuspended::class, function (TenantSuspended $event) {
    $notifier->alertAdmin("Tenant {$event->tenant->getName()} suspended: {$event->reason}");
});

// In your middleware configuration
$pipeline->pipe(TenantResolverMiddleware::class);

// The middleware automatically:
// 1. Resolves tenant via ChainResolver
// 2. Returns 404 if no tenant found
// 3. Returns 503 if tenant is suspended
// 4. Sets TenantContext
// 5. Activates the tenancy driver (connect)
// 6. Adds tenant to request attributes
// 7. Cleans up after response (disconnect + context reset)

use MonkeysLegion\Tenancy\Entity\Tenant;
use MonkeysLegion\Tenancy\Enum\TenancyMode;

// Factory creation
$tenant = Tenant::create('acme', 'Acme Corp', TenancyMode::Schema, 'enterprise');

// Property hooks — computed on access
$tenant->isActive;     // bool (delegates to status->isOperational())
$tenant->isSuspended;  // bool
$tenant->status;       // TenantStatus enum
$tenant->mode;         // TenancyMode enum
$tenant->displayName;  // name or key fallback

// Lifecycle actions
$tenant->activate();
$tenant->suspend();
$tenant->archive();
$tenant->markDeleted();

// Metadata
$tenant->setMetadata('max_users', 50);
$tenant->getMetadataValue('max_users'); // 50