PHP code example of mahdisphp / laravel-realm

1. Go to this page and download the library: Download mahdisphp/laravel-realm 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/ */

    

mahdisphp / laravel-realm example snippets


use Realm\Traits\BelongsToRealm;

class Project extends Model
{
    use BelongsToRealm;
}

Schema::create('projects', function (Blueprint $table) {
    $table->id();
    $table->realm();  // Adds realm_id + index
    $table->string('name');
    $table->timestamps();
});

// Tenant routes — realm context is resolved automatically
Route::realm(function () {
    Route::get('/dashboard', [DashboardController::class, 'index']);
    Route::resource('projects', ProjectController::class);
});

// Central routes — guaranteed no tenant context
Route::central(function () {
    Route::get('/', [MarketingController::class, 'index']);
});

// Inside a tenant route, queries are scoped automatically
Project::all();           // Only current tenant's projects
Project::create([...]);   // realm_id set automatically

// Outside tenant context (strict mode) — returns empty, not everything
Project::all();           // [] — fail-closed, logged warning

// FACADE — context management (Realm)
Realm::current();                    // Get active Tenant model
Realm::id();                         // Get active tenant ID
Realm::key();                        // Get active tenant key
Realm::check();                      // True if tenant set & tenancy enabled
Realm::isTenancyDisabled();          // True inside withoutTenancy()
Realm::run('acme', fn() => ...);     // Execute in a tenant's context
Realm::withoutTenancy(fn() => ...);  // Disable all scoping
Realm::forget();                     // Clear active tenant (keep tenancy state)

// FACADE — secrets
Realm::setSecret('acme', 'key', 'value');
Realm::getSecret('acme', 'key');
Realm::deleteSecret('acme', 'key');

// MODEL — data operations (Tenant)
Tenant::create(['key' => 'acme', 'name' => 'Acme Corp']);
Tenant::where('active', true)->get();

// Bypass query scope for ONE query (cache/storage still scoped)
Project::withoutRealm()->get();

// Bypass ALL scoping (queries + cache + storage)
Realm::withoutTenancy(fn() => Project::all());

// Query a specific tenant
$acme = Tenant::where('key', 'acme')->first();
Project::forRealm($acme)->get();

// TENANT MODEL — scoped, has realm_id
class Project extends Model { use BelongsToRealm; }

// SHARED MODEL — no trait, no realm_id, available to all tenants
class Category extends Model { /* no BelongsToRealm */ }

// Relationships work across the boundary:
// $project->category works (Category is not scoped)

// Inside tenant 'acme' context:
Cache::put('settings', $data);  // Actually stores as realm:acme:settings
Cache::get('settings');          // Reads from realm:acme:settings

// Inside withoutTenancy — reads/writes global keys
Realm::withoutTenancy(fn() => Cache::get('settings'));  // Reads 'settings' (global)

use Realm\Traits\RealmAwareJob;
use Realm\Integrations\RealmQueueMiddleware;

class GenerateReport implements ShouldQueue
{
    use RealmAwareJob;

    public function middleware(): array
    {
        return $this->realmMiddleware();
    }

    public function handle(): void
    {
        // Realm context is automatically restored here
    }
}

// Inside tenant 'acme' context:
Storage::put('logo.png', $file);  // Stores at tenants/acme/logo.png
Storage::get('logo.png');          // Reads from tenants/acme/logo.png

// On the Tenant model
$tenant->setSecret('stripe_key', 'sk_live_...');
$tenant->getSecret('stripe_key');   // Returns decrypted value
$tenant->deleteSecret('stripe_key');

// Via the Facade
Realm::setSecret('acme', 'stripe_key', 'sk_live_...');
Realm::getSecret('acme', 'stripe_key');

// Attach a user
$tenant->users()->attach($user, ['role' => 'owner']);

// Query users
$tenant->users;                              // All users for this tenant
$tenant->users()->wherePivot('role', 'owner')->first();

$tenant = Tenant::create([
    'key' => 'acme',
    'name' => 'Acme Corp',
    'data' => [
        'config' => [
            'app.name' => 'Acme Dashboard',
            'mail.from.name' => 'Acme Support',
        ],
    ],
]);

// Inside Realm::run() or middleware, config() returns tenant-specific values
Realm::run($tenant, function () {
    config('app.name'); // 'Acme Dashboard'
});
// After run(), original config values are restored

'resolvers' => [
    SubdomainResolver::class,
    HeaderResolver::class,
    // Add more as needed
],

use Realm\Testing\RealmTestHelpers;

class ProjectTest extends TestCase
{
    use RealmTestHelpers;

    public function test_projects_are_isolated(): void
    {
        $acme = $this->createRealm('acme');
        $globex = $this->createRealm('globex');

        $this->actingAsRealm($acme, fn() => Project::create(['name' => 'Acme Project']));
        $this->actingAsRealm($globex, fn() => Project::create(['name' => 'Globex Project']));

        $this->assertRealmCount($acme, Project::class, 1);
        $this->assertRealmMissing($acme, Project::class, ['name' => 'Globex Project']);
    }
}

$table->realm();                   // Default: restrictOnDelete (safe)
$table->realm(cascade: true);      // Opt-in: cascadeOnDelete