Skip to content

Configuration

Braden Keith edited this page Sep 20, 2025 · 1 revision

Configuration

Complete reference for configuring the Romega Software - Availability package.

Configuration File

After publishing the configuration file, you'll find it at config/availability.php:

<?php

return [
    'table' => 'availability_rules',
    'default_effect' => 'allow',
    'models' => [
        'rule' => \RomegaSoftware\Availability\Models\AvailabilityRule::class,
    ],
    'rule_types' => [
        // Built-in rule types
        'months_of_year' => \RomegaSoftware\Availability\Evaluators\MonthsOfYearEvaluator::class,
        'weekdays' => \RomegaSoftware\Availability\Evaluators\WeekdaysEvaluator::class,
        'date_range' => \RomegaSoftware\Availability\Evaluators\DateRangeEvaluator::class,
        'rrule' => \RomegaSoftware\Availability\Evaluators\RRuleEvaluator::class,
        'blackout_date' => \RomegaSoftware\Availability\Evaluators\BlackoutDateEvaluator::class,
        'time_of_day' => \RomegaSoftware\Availability\Evaluators\TimeOfDayEvaluator::class,
        'inventory_gate' => \RomegaSoftware\Availability\Evaluators\InventoryGateEvaluator::class,

        // Add your custom evaluators here
        // 'custom_rule' => \App\Availability\CustomEvaluator::class,
    ],
    'inventory_gate' => [
        'resolver' => null,
        'resolvers' => [],
    ],
];

Configuration Options

Table Name

Change the database table name for availability rules:

'table' => 'custom_availability_rules',

Remember to update your migration if you change this.

Default Effect

Set the global default availability when no rules match:

'default_effect' => 'allow', // or 'deny'

This can be overridden per model using getAvailabilityDefaultEffect().

Custom Rule Model

Use a custom model for availability rules:

'models' => [
    'rule' => \App\Models\CustomAvailabilityRule::class,
],

Your custom model must extend the base AvailabilityRule:

namespace App\Models;

use RomegaSoftware\Availability\Models\AvailabilityRule as BaseRule;

class CustomAvailabilityRule extends BaseRule
{
    // Add custom methods or attributes
    protected $appends = ['description'];

    public function getDescriptionAttribute()
    {
        return $this->config['_description'] ?? null;
    }
}

Rule Types Registry

Register custom evaluators:

'rule_types' => [
    // Keep existing types
    ...existing types...

    // Add custom types
    'business_days' => \App\Evaluators\BusinessDaysEvaluator::class,
    'api_limit' => \App\Evaluators\ApiLimitEvaluator::class,
    'geo_fence' => \App\Evaluators\GeoFenceEvaluator::class,
],

Inventory Gate Configuration

Configure inventory resolvers:

'inventory_gate' => [
    // Global resolver for all models
    'resolver' => function ($subject, $moment, $config) {
        return $subject->getInventoryAt($moment);
    },

    // Per-model resolvers
    'resolvers' => [
        \App\Models\Product::class => function ($product, $moment, $config) {
            return $product->stock_quantity;
        },
        \App\Models\Room::class => \App\Resolvers\RoomInventoryResolver::class,
    ],
],

Environment Variables

You can use environment variables for configuration:

// config/availability.php
return [
    'table' => env('AVAILABILITY_TABLE', 'availability_rules'),
    'default_effect' => env('AVAILABILITY_DEFAULT', 'allow'),
    // ...
];
# .env
AVAILABILITY_TABLE=custom_rules
AVAILABILITY_DEFAULT=deny

Dynamic Configuration

Runtime Configuration

Change configuration at runtime:

// Change default effect
config(['availability.default_effect' => 'deny']);

// Add a custom evaluator
config(['availability.rule_types.custom' => CustomEvaluator::class]);

// Set inventory resolver
config(['availability.inventory_gate.resolver' => function ($subject, $moment) {
    return $subject->checkInventory($moment);
}]);

Service Provider Configuration

Configure in a service provider for better organization:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use RomegaSoftware\Availability\Support\RuleEvaluatorRegistry;

class AvailabilityServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->configureInventoryResolvers();
        $this->registerCustomEvaluators();
    }

    private function configureInventoryResolvers()
    {
        config(['availability.inventory_gate.resolvers' => [
            Product::class => ProductInventoryResolver::class,
            Service::class => ServiceCapacityResolver::class,
            Room::class => function ($room, $moment) {
                return !$room->hasBookingAt($moment);
            },
        ]]);
    }

    private function registerCustomEvaluators()
    {
        $registry = $this->app->make(RuleEvaluatorRegistry::class);

        $registry->register('holiday', new HolidayEvaluator());
        $registry->register('maintenance', new MaintenanceEvaluator());
        $registry->register('capacity', new CapacityEvaluator());
    }
}

Model Configuration

Using the Trait

use RomegaSoftware\Availability\Traits\HasAvailability;

class Resource extends Model
{
    use HasAvailability;

    // Optional: Override default timezone
    public function getAvailabilityTimezone(): string
    {
        return $this->custom_timezone ?? 'UTC';
    }

    // Optional: Override default effect
    public function getAvailabilityDefaultEffect(): Effect
    {
        return $this->is_public ? Effect::Allow : Effect::Deny;
    }
}

Custom Implementation

use RomegaSoftware\Availability\Contracts\AvailabilitySubject;

class CustomResource extends Model implements AvailabilitySubject
{
    public function availabilityRules()
    {
        return $this->morphMany(
            config('availability.models.rule'),
            'subject'
        )->orderBy('priority');
    }

    public function getAvailabilityTimezone(): string
    {
        // Complex timezone logic
        if ($this->location) {
            return $this->location->timezone;
        }

        if ($this->user) {
            return $this->user->timezone;
        }

        return config('app.timezone');
    }

    public function getAvailabilityDefaultEffect(): Effect
    {
        // Dynamic default based on conditions
        if ($this->is_premium) {
            return Effect::Allow;
        }

        if ($this->under_maintenance) {
            return Effect::Deny;
        }

        return Effect::from(config('availability.default_effect'));
    }
}

Database Configuration

Custom Migration

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCustomAvailabilityRulesTable extends Migration
{
    public function up()
    {
        Schema::create('custom_availability_rules', function (Blueprint $table) {
            $table->id();
            $table->morphs('subject');
            $table->string('type', 50)->index();
            $table->json('config')->nullable();
            $table->string('effect', 10);
            $table->integer('priority')->default(50);
            $table->boolean('enabled')->default(true);

            // Custom fields
            $table->string('name')->nullable();
            $table->text('description')->nullable();
            $table->uuid('created_by')->nullable();
            $table->timestamp('expires_at')->nullable();

            $table->timestamps();

            // Indexes
            $table->index(['subject_type', 'subject_id', 'enabled', 'priority']);
            $table->index(['expires_at']);
        });
    }
}

Using Different Database Connections

namespace App\Models;

use RomegaSoftware\Availability\Models\AvailabilityRule as BaseRule;

class CustomAvailabilityRule extends BaseRule
{
    protected $connection = 'availability_db';
    protected $table = 'custom_rules';
}

Caching Configuration

Cache Rules

namespace App\Models;

use Illuminate\Support\Facades\Cache;

trait CachedAvailability
{
    public function availabilityRules()
    {
        $cacheKey = "availability_rules.{$this->getMorphClass()}.{$this->id}";

        return Cache::remember($cacheKey, 3600, function () {
            return $this->morphMany(
                config('availability.models.rule'),
                'subject'
            )->where('enabled', true)
             ->orderBy('priority')
             ->get();
        });
    }

    public function clearAvailabilityCache()
    {
        $cacheKey = "availability_rules.{$this->getMorphClass()}.{$this->id}";
        Cache::forget($cacheKey);
    }
}

Multi-Tenant Configuration

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Services\TenantService;

class TenantAvailabilityProvider extends ServiceProvider
{
    public function boot()
    {
        // Set configuration based on current tenant
        if ($tenant = TenantService::current()) {
            config([
                'availability.default_effect' => $tenant->default_availability,
                'availability.inventory_gate.resolver' => function ($subject, $moment) use ($tenant) {
                    return $subject->getInventoryForTenant($tenant, $moment);
                },
            ]);
        }
    }
}

Testing Configuration

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        // Test-specific configuration
        config([
            'availability.default_effect' => 'deny',
            'availability.inventory_gate.resolver' => function () {
                return 10; // Fixed inventory for testing
            },
        ]);
    }

    protected function withCustomAvailabilityConfig(array $config)
    {
        config(['availability' => array_merge(
            config('availability'),
            $config
        )]);

        return $this;
    }
}

Performance Configuration

return [
    // ... other config ...

    // Performance settings (custom additions)
    'performance' => [
        // Cache TTL for availability checks (seconds)
        'cache_ttl' => env('AVAILABILITY_CACHE_TTL', 300),

        // Maximum rules to process per subject
        'max_rules' => env('AVAILABILITY_MAX_RULES', 100),

        // Enable query optimization
        'optimize_queries' => env('AVAILABILITY_OPTIMIZE', true),

        // Batch size for bulk checks
        'batch_size' => env('AVAILABILITY_BATCH_SIZE', 50),
    ],
];

Next Steps

Getting Started

Installation
Set up the package in your Laravel app

Quick Start
Get running in 5 minutes

Basic Usage
Common patterns and examples


Core Concepts

How It Works
Understanding the evaluation engine

Rule Types
Available rule types and configurations

Priority System
How rule priority affects evaluation


Advanced Topics

Inventory Gates
Dynamic availability based on stock

Custom Evaluators
Build your own rule types

Complex Scenarios
Real-world implementation patterns

Performance Tips
Optimization strategies


API Reference

Configuration
Package configuration options

Models & Traits
Available models and traits

Testing
Testing your availability rules

Clone this wiki locally