Skip to content

Basic Usage

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

Basic Usage

Common patterns and examples for everyday use.

Setting Up a Model

Basic Setup

use RomegaSoftware\Availability\Traits\HasAvailability;
use RomegaSoftware\Availability\Support\Effect;

class Resource extends Model
{
    use HasAvailability;
    
    protected $fillable = [
        'name',
        'availability_default',
        'availability_timezone',
    ];
    
    protected $casts = [
        'availability_default' => Effect::class,
    ];
}

Implementing the Interface (Alternative)

Instead of using the trait, you can implement the interface directly:

use RomegaSoftware\Availability\Contracts\AvailabilitySubject;

class Resource extends Model implements AvailabilitySubject
{
    public function availabilityRules()
    {
        return $this->morphMany(
            config('availability.models.rule'),
            'subject'
        );
    }
    
    public function getAvailabilityTimezone(): string
    {
        return $this->timezone ?? config('app.timezone');
    }
    
    public function getAvailabilityDefaultEffect(): Effect
    {
        return $this->default_availability ?? Effect::Allow;
    }
}

Common Scenarios

Business Hours

// Open Monday-Friday, 9 AM to 5 PM
$business->availabilityRules()->createMany([
    [
        'type' => 'weekdays',
        'config' => ['days' => [1, 2, 3, 4, 5]],
        'effect' => Effect::Allow,
        'priority' => 10,
        'enabled' => true,
    ],
    [
        'type' => 'time_of_day',
        'config' => ['from' => '09:00', 'to' => '17:00'],
        'effect' => Effect::Allow,
        'priority' => 20,
        'enabled' => true,
    ],
]);

Seasonal Availability

// Summer season (June-August)
$facility->availabilityRules()->create([
    'type' => 'months_of_year',
    'config' => ['months' => [6, 7, 8]],
    'effect' => Effect::Allow,
    'priority' => 10,
    'enabled' => true,
]);

// Or using date ranges
$facility->availabilityRules()->create([
    'type' => 'date_range',
    'config' => [
        'from' => '06-01',
        'to' => '08-31',
        'kind' => 'yearly',
    ],
    'effect' => Effect::Allow,
    'priority' => 10,
    'enabled' => true,
]);

24/7 with Maintenance Windows

// Default: always available
$service->availability_default = Effect::Allow;
$service->save();

// Weekly maintenance window (Sunday 2-4 AM)
$service->availabilityRules()->createMany([
    [
        'type' => 'weekdays',
        'config' => ['days' => [7]], // Sunday
        'effect' => Effect::Deny,
        'priority' => 10,
        'enabled' => true,
    ],
    [
        'type' => 'time_of_day',
        'config' => ['from' => '02:00', 'to' => '04:00'],
        'effect' => Effect::Deny,
        'priority' => 20,
        'enabled' => true,
    ],
]);

Working with Rules

Listing Rules

$resource = Resource::find(1);

// Get all rules
$rules = $resource->availabilityRules;

// Get only enabled rules
$enabledRules = $resource->availabilityRules()
    ->where('enabled', true)
    ->orderBy('priority')
    ->get();

// Get rules by type
$weekdayRules = $resource->availabilityRules()
    ->where('type', 'weekdays')
    ->get();

Updating Rules

$rule = $resource->availabilityRules()->find($ruleId);

// Disable a rule temporarily
$rule->update(['enabled' => false]);

// Change priority
$rule->update(['priority' => 50]);

// Update configuration
$rule->update([
    'config' => ['days' => [1, 2, 3]], // Mon-Wed only
]);

Deleting Rules

// Delete a specific rule
$resource->availabilityRules()->find($ruleId)->delete();

// Delete all rules of a type
$resource->availabilityRules()
    ->where('type', 'blackout_date')
    ->delete();

// Clear all rules
$resource->availabilityRules()->delete();

Checking Availability

Basic Checks

use RomegaSoftware\Availability\Support\AvailabilityEngine;

$engine = app(AvailabilityEngine::class);

// Check current availability
$isAvailable = $engine->isAvailable($resource, now());

// Check future availability
$tomorrow = now()->addDay();
$isAvailableTomorrow = $engine->isAvailable($resource, $tomorrow);

// Check specific datetime
$checkTime = Carbon::parse('2025-06-15 14:30:00');
$isAvailable = $engine->isAvailable($resource, $checkTime);

Batch Checking

// Check multiple times
$times = [
    now(),
    now()->addHour(),
    now()->addDay(),
    now()->addWeek(),
];

$availability = [];
foreach ($times as $time) {
    $availability[$time->toDateTimeString()] = $engine->isAvailable($resource, $time);
}

Finding Next Available Slot

function findNextAvailable($resource, $startTime, $maxDays = 30) {
    $engine = app(AvailabilityEngine::class);
    $current = $startTime->copy();
    $end = $startTime->copy()->addDays($maxDays);
    
    while ($current <= $end) {
        if ($engine->isAvailable($resource, $current)) {
            return $current;
        }
        $current->addHour();
    }
    
    return null;
}

$nextSlot = findNextAvailable($resource, now());

Timezone Handling

Setting Timezones

// On the model
$resource->availability_timezone = 'America/New_York';
$resource->save();

// Rules are evaluated in the resource's timezone
$resource->availabilityRules()->create([
    'type' => 'time_of_day',
    'config' => ['from' => '09:00', 'to' => '17:00'], // 9 AM-5 PM EST
    'effect' => Effect::Allow,
    'priority' => 10,
    'enabled' => true,
]);

Checking Across Timezones

// User in London checking NY resource availability
$userTime = Carbon::parse('2025-01-15 14:00:00', 'Europe/London');
$isAvailable = $engine->isAvailable($resource, $userTime);
// The engine automatically converts to resource's timezone for evaluation

Default Behavior

Allow by Default

$resource->availability_default = Effect::Allow;
// Resource is available unless rules say otherwise

Deny by Default

$resource->availability_default = Effect::Deny;
// Resource is unavailable unless rules explicitly allow

Best Practices

1. Use Clear Priority Levels

// Good: Clear priority groups
const PRIORITY_BASE = 10;      // Base availability
const PRIORITY_SCHEDULE = 20;  // Regular schedule
const PRIORITY_OVERRIDE = 30;  // Special overrides
const PRIORITY_BLACKOUT = 40;  // Blackout dates (highest)

2. Name Your Rules

// Store a description in config
$resource->availabilityRules()->create([
    'type' => 'weekdays',
    'config' => [
        'days' => [1, 2, 3, 4, 5],
        '_description' => 'Regular weekday schedule',
    ],
    'effect' => Effect::Allow,
    'priority' => 10,
    'enabled' => true,
]);

3. Group Related Rules

// Create a service method
public function setBusinessHours($from, $to, $days = [1,2,3,4,5])
{
    $this->availabilityRules()->createMany([
        [
            'type' => 'weekdays',
            'config' => ['days' => $days],
            'effect' => Effect::Allow,
            'priority' => 10,
            'enabled' => true,
        ],
        [
            'type' => 'time_of_day',
            'config' => ['from' => $from, 'to' => $to],
            'effect' => Effect::Allow,
            'priority' => 20,
            'enabled' => true,
        ],
    ]);
}

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