Milk Admin

ScheduleGridBuilder

The ScheduleGridBuilder provides a powerful grid system for visualizing resource schedules across time periods. It extends GetDataBuilder and creates dynamic grids where rows represent resources (rooms, teachers, equipment, etc.) and columns represent time slots (days, hours, etc.).

Key Features

  • Database Integration: Automatically queries and filters events from your database
  • Multiple Period Types: Week, month, day, or custom date range views
  • Dynamic Rows: Rows are generated dynamically from your data (unlike CalendarBuilder's fixed date-based structure)
  • Time Intervals: Configurable time intervals for day view (10, 15, 30, or 60 minutes)
  • Field Mapping: Map database fields to grid properties with support for callable functions
  • Cell Grouping: Events spanning multiple time slots are automatically merged
  • AJAX Support: Built-in AJAX navigation with automatic period tracking
  • Click Handlers: Configure URLs for event clicks and empty cell clicks
  • Custom Rendering: Full control over cell appearance with custom renderers
  • Localization: Multi-language support using PHP's IntlDateFormatter

Quick Start

Basic Weekly Schedule

use Builders\ScheduleGridBuilder;

// Simple weekly resource schedule
$schedule = ScheduleGridBuilder::create($bookingModel, 'weekly_schedule')
    ->setPeriod('week')
    ->detectPeriodFromRequest()
    ->setHeaderTitle('Room Schedule')
    ->render();

echo $schedule;

Complete Example

$schedule = ScheduleGridBuilder::create($bookingModel, 'resource_schedule')
    ->setPeriod('week')
    ->detectPeriodFromRequest()
    ->mapFields([
        'row_id' => 'resource_name',
        'id' => 'booking_id',
        'start_datetime' => 'start_time',
        'end_datetime' => 'end_time',
        'label' => 'activity_name',
        'class' => function($row, $raw_row) {
            return 'booking-' . $raw_row->status;
        },
        'color' => 'booking_color'
    ])
    ->setHeaderTitle('Weekly Resource Schedule')
    ->setHeaderIcon('bi-calendar3')
    ->setHeaderColor('primary')
    ->setRowHeaderLabel('Resources')
    ->onEventClick('?page=bookings&action=edit&id=%id%')
    ->onEmptyCellClick('?page=bookings&action=new&resource=%row_id%&date=%date%')
    ->render();

Live Example

Interactive Demo: Below is a working example of ScheduleGridBuilder with sample data. Try navigating between weeks to see the AJAX functionality in action.
Resource Booking Schedule - Live Demo
Week 29, 2026
Rooms
Mon
13
Tue
14
Wed
15
Thu
16
Fri
17
Sat
18
Sun
19
Training Room
Interview
Interview
Training Session
 
Project Review
Training Session
Workshop
Conference Room B
 
 
Workshop
 
Client Presentation
 
Client Presentation
Meeting Room 2
Training Session
 
Project Review
Interview
Client Presentation
Interview
 
Conference Room A
 
 
 
 
 
Project Review
 
Meeting Room 1
 
 
 
 
Workshop
 
 
What you see above:
  • A weekly schedule grid with 5 different conference rooms
  • 20 randomly generated bookings for the current week
  • Events spanning multiple hours are automatically grouped
  • Full AJAX navigation - click the arrows to change weeks
  • Data is generated using ArrayDB (no database required)

Period Configuration

ScheduleGridBuilder supports four period types: week, month, day, and custom date ranges.

Weekly View

// Current week (auto-detected)
$schedule = ScheduleGridBuilder::create($model, 'weekly_grid')
    ->setPeriod('week')
    ->detectPeriodFromRequest()
    ->render();

// Specific week
$schedule = ScheduleGridBuilder::create($model, 'weekly_grid')
    ->setWeek(15, 2025)  // Week 15 of 2025
    ->render();

Monthly View

// Current month (auto-detected)
$schedule = ScheduleGridBuilder::create($model, 'monthly_grid')
    ->setPeriod('month')
    ->detectPeriodFromRequest()
    ->render();

// Specific month
$schedule = ScheduleGridBuilder::create($model, 'monthly_grid')
    ->setMonth(3, 2025)  // March 2025
    ->render();

Daily View with Time Intervals

// Day view with 15-minute intervals
$baseDate = new DateTime('2025-03-15');

$schedule = ScheduleGridBuilder::create($model, 'daily_grid')
    ->setDateRange(
        (clone $baseDate)->setTime(8, 0),
        (clone $baseDate)->setTime(18, 0)
    )
    ->setPeriod('day')  // MUST be after setDateRange()
    ->setTimeInterval(15)  // 15-minute intervals
    ->setColumnWidth('3rem')  // Fixed column width
    ->render();

// Different time intervals
$schedule = ScheduleGridBuilder::create($model, 'daily_grid')
    ->setDateRange($startDate, $endDate)
    ->setPeriod('day')
    ->setTimeInterval(30)  // Options: 10, 15, 30, or 60 minutes
    ->render();

Custom Date Range

$start = new DateTime('2025-03-01 08:00:00');
$end = new DateTime('2025-03-07 20:00:00');

$schedule = ScheduleGridBuilder::create($model, 'custom_grid')
    ->setDateRange($start, $end)
    ->render();

Field Mapping

Map your database fields to schedule grid properties. The row_id field is unique to ScheduleGridBuilder and determines which row each event appears in.

Basic Field Mapping

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->mapFields([
        'row_id' => 'room_name',          // Required: determines the row
        'id' => 'booking_id',             // Event identifier
        'start_datetime' => 'start_time', // Start date/time
        'end_datetime' => 'end_time',     // End date/time
        'label' => 'event_name',          // Display text
        'class' => 'css_class',           // CSS class
        'color' => 'bg_color'             // Background color
    ])
    ->detectPeriodFromRequest()
    ->render();

Advanced Mapping with Callable Functions

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->mapFields([
        'row_id' => function($row, $raw_row) {
            // Dynamic row assignment
            return $raw_row->department . ' - ' . $raw_row->room;
        },
        'id' => 'id',
        'start_datetime' => 'booking_start',
        'end_datetime' => 'booking_end',
        'label' => function($row, $raw_row) {
            // Custom label with instructor
            $name = $raw_row->course_name ?? 'Event';
            $instructor = $raw_row->instructor_name ?? '';
            return $instructor ? "$name ($instructor)" : $name;
        },
        'class' => function($row, $raw_row) {
            // Dynamic CSS based on status
            return match($raw_row->status) {
                'confirmed' => 'booking-confirmed',
                'pending' => 'booking-pending',
                'cancelled' => 'booking-cancelled',
                default => 'booking-default'
            };
        },
        'color' => function($row, $raw_row) {
            // Dynamic color based on priority
            return match($raw_row->priority) {
                'high' => '#F44336',
                'medium' => '#FF9800',
                'low' => '#4CAF50',
                default => '#2196F3'
            };
        }
    ])
    ->detectPeriodFromRequest()
    ->render();

Mapping with Related Data

// When using joins or related objects
$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->join('LEFT JOIN #__resources r ON r.id = t.resource_id')
    ->mapFields([
        'row_id' => function($row, $raw_row) {
            // Access joined data
            return $raw_row->resource->name ?? 'Unknown Resource';
        },
        'id' => 'id',
        'start_datetime' => 'start_datetime',
        'end_datetime' => 'end_datetime',
        'label' => function($row, $raw_row) {
            return $raw_row->title . ' - ' . $raw_row->resource->location;
        }
    ])
    ->detectPeriodFromRequest()
    ->render();

Database Query Manipulation

ScheduleGridBuilder extends GetDataBuilder, providing full access to query manipulation methods.

Basic Query Filtering

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->where('status = ?', ['active'])
    ->where('department_id = ?', [$deptId])
    ->orderBy('start_datetime', 'asc')
    ->detectPeriodFromRequest()
    ->render();

Advanced Query with Joins

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    // Join with resources and users
    ->join('LEFT JOIN #__resources r ON r.id = t.resource_id')
    ->join('LEFT JOIN #__users u ON u.id = t.user_id')

    // Filter by building
    ->where('r.building_id = ?', [$buildingId])

    // Only confirmed or pending bookings
    ->where('t.status IN (?, ?)', ['confirmed', 'pending'])

    // Order by resource then time
    ->orderBy('r.name', 'asc')
    ->orderBy('t.start_datetime', 'asc')

    ->detectPeriodFromRequest()
    ->render();

Display Configuration

Header Customization

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setHeaderTitle('Conference Room Schedule')
    ->setHeaderIcon('bi-calendar3')
    ->setHeaderColor('success')  // primary, secondary, success, danger, warning, info
    ->setShowHeader(true)
    ->setShowNavigation(true)
    ->detectPeriodFromRequest()
    ->render();

// Hide header completely
$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setShowHeader(false)
    ->detectPeriodFromRequest()
    ->render();

Row Header Label

// Set label for the top-left corner cell
$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setRowHeaderLabel('Rooms')  // or 'Teachers', 'Equipment', etc.
    ->detectPeriodFromRequest()
    ->render();

Column Width Configuration

// Fixed width columns
$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setColumnWidth('60px')  // Fixed 60px columns
    ->detectPeriodFromRequest()
    ->render();

// Flexible columns (default)
$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setColumnWidth(null)  // Auto width (1fr)
    ->detectPeriodFromRequest()
    ->render();

Navigation Limits

// Limit navigable date range
$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setMinYear(2024)
    ->setMaxYear(2026)
    ->detectPeriodFromRequest()
    ->render();

// Or use combined method
$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setYearRange(2024, 2026)
    ->detectPeriodFromRequest()
    ->render();

Locale Settings

// Italian locale
$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setLocale('it_IT')
    ->detectPeriodFromRequest()
    ->render();

// French locale
$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setLocale('fr_FR')
    ->detectPeriodFromRequest()
    ->render();

Styling and Appearance

Quick Color Theme

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->gridColor('primary')  // Applies coordinated theme
    ->detectPeriodFromRequest()
    ->render();

// Available colors: primary, secondary, success, danger, warning, info, light, dark

Custom Grid Attributes

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->addGridAttr('container', 'class', 'shadow-lg rounded-3')
    ->addGridAttr('grid', 'class', 'border-primary')
    ->addGridAttr('row-header', 'class', 'bg-light fw-bold')
    ->detectPeriodFromRequest()
    ->render();

// Set all attributes at once
$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setGridAttrs([
        'container' => ['class' => 'shadow-lg'],
        'grid' => ['class' => 'custom-grid'],
        'row-header' => ['class' => 'bg-primary text-white']
    ])
    ->detectPeriodFromRequest()
    ->render();

Click Handlers

Configure URLs for event clicks and empty cell clicks. Placeholders are automatically replaced with actual values.

Event Click Handler

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->onEventClick('?page=bookings&action=edit&id=%id%')
    ->detectPeriodFromRequest()
    ->render();

// Available placeholders for event clicks:
// %id% = event ID
// %row_id% = row identifier (resource name/id)
// %col_id% = column identifier (date or time)

Empty Cell Click Handler

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->onEmptyCellClick('?page=bookings&action=new&resource=%row_id%&date=%date%')
    ->detectPeriodFromRequest()
    ->render();

// Available placeholders for empty cell clicks:
// %row_id% = row identifier (resource name/id)
// %col_id% = column identifier (date or time)
// %date% = date in Y-m-d format (for week/month views)
// %time% = time in H:i format (for day view)

Combined Click Handlers

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->onEventClick('?page=bookings&action=view&id=%id%&resource=%row_id%')
    ->onEmptyCellClick('?page=bookings&action=create&resource=%row_id%&time=%col_id%')
    ->detectPeriodFromRequest()
    ->render();

Custom Cell Renderer

For advanced customization, provide a custom function to render each cell. The renderer receives all cell information and returns custom HTML.

Custom Renderer Example

$schedule = ScheduleGridBuilder::create($model, 'schedule')
    ->setCustomCellRenderer(function($row_id, $col_id, $event, $is_grouped, $colspan) {
        // Empty cell
        if (!$event) {
            return '<div class="schedule-cell empty"> </div>';
        }

        $label = $event['label'] ?? '';
        $status = $event['class'] ?? '';
        $color = $event['color'] ?? '#ccc';

        // Status badge
        $badge = match($status) {
            'confirmed' => '<span class="badge bg-success">✓</span>',
            'pending' => '<span class="badge bg-warning">⏳</span>',
            'cancelled' => '<span class="badge bg-danger">✗</span>',
            default => ''
        };

        // Multi-column span
        $style = "grid-column: span {$colspan}; background-color: {$color};";
        $duration = $is_grouped ? " ({$colspan} slots)" : "";

        return <<<HTML
        <div class="schedule-cell {$status}" style="{$style}">
            <div class="p-2">
                <strong>{$label}{$duration}</strong>
                {$badge}
            </div>
        </div>
HTML;
    })
    ->detectPeriodFromRequest()
    ->render();

Custom Renderer Parameters

  • $row_id: Row identifier (resource name/id)
  • $col_id: Column identifier (date or time slot)
  • $event: Event data array or null for empty cells
  • $is_grouped: Boolean indicating if cell is part of a multi-column group
  • $colspan: Number of columns spanned by this cell

AJAX Implementation

ScheduleGridBuilder automatically handles AJAX requests for navigation.

Basic AJAX Handler

// In your controller
#[RequestAction('home')]
public function scheduleView()
{
    $schedule = ScheduleGridBuilder::create($this->model, 'resource_schedule')
        ->detectPeriodFromRequest()
        ->setHeaderTitle('Resource Schedule')
        ->render();

    // Handle AJAX request
    if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
        strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {

        Response::json([
            'success' => true,
            'html' => $schedule
        ]);
    }

    // Full page render
    Response::render(__DIR__ . '/Views/schedule.php', [
        'schedule' => $schedule
    ]);
}

AJAX with Filters

#[RequestAction('home')]
public function scheduleView()
{
    $gridId = 'resource_schedule';
    $department = $_GET['department'] ?? '';

    $schedule = ScheduleGridBuilder::create($this->model, $gridId)
        ->detectPeriodFromRequest();

    // Apply filter if provided
    if ($department) {
        $schedule->where('department = ?', [$department]);
    }

    $html = $schedule->render();

    // Handle AJAX request
    if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
        strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {

        Response::json([
            'success' => true,
            'html' => $html
        ]);
    }

    // Full page render
    Response::render(__DIR__ . '/Views/schedule.php', [
        'schedule' => $html
    ]);
}

Complete Real-World Examples

Example 1: Weekly Room Schedule

class RoomScheduleController extends AbstractController
{
    #[RequestAction('home')]
    public function weeklyRoomSchedule()
    {
        $schedule = ScheduleGridBuilder::create($this->model, 'room_schedule')
            ->setPeriod('week')
            ->detectPeriodFromRequest()
            ->mapFields([
                'row_id' => 'room_name',
                'id' => 'booking_id',
                'start_datetime' => 'start_time',
                'end_datetime' => 'end_time',
                'label' => function($row, $raw_row) {
                    return $raw_row->event_name . ' - ' . $raw_row->organizer;
                },
                'class' => function($row, $raw_row) {
                    return 'booking-' . $raw_row->status;
                },
                'color' => 'event_color'
            ])
            ->setHeaderTitle('Weekly Room Schedule')
            ->setHeaderIcon('bi-door-open')
            ->setHeaderColor('primary')
            ->setRowHeaderLabel('Rooms')
            ->onEventClick('?page=bookings&action=edit&id=%id%')
            ->onEmptyCellClick('?page=bookings&action=new&room=%row_id%&date=%date%')
            ->gridColor('primary')
            ->render();

        // Handle AJAX
        if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
            strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
            Response::json(['success' => true, 'html' => $schedule]);
        }

        Response::render(__DIR__ . '/Views/schedule.php', [
            'schedule' => $schedule
        ]);
    }
}

Example 2: Daily Equipment Schedule with Time Slots

class EquipmentScheduleController extends AbstractController
{
    #[RequestAction('home')]
    public function dailyEquipmentSchedule()
    {
        $date = $_GET['date'] ?? date('Y-m-d');
        $baseDate = new DateTime($date);

        $schedule = ScheduleGridBuilder::create($this->model, 'equipment_schedule')
            ->setDateRange(
                (clone $baseDate)->setTime(6, 0),
                (clone $baseDate)->setTime(22, 0)
            )
            ->setPeriod('day')  // Must be after setDateRange
            ->setTimeInterval(30)  // 30-minute slots
            ->setColumnWidth('4rem')
            ->mapFields([
                'row_id' => function($row, $raw_row) {
                    return $raw_row->equipment_type . ' - ' . $raw_row->equipment_id;
                },
                'id' => 'reservation_id',
                'start_datetime' => 'checkout_time',
                'end_datetime' => 'return_time',
                'label' => function($row, $raw_row) {
                    return $raw_row->project_name . '\n' . $raw_row->user_name;
                },
                'class' => function($row, $raw_row) {
                    return $raw_row->is_overdue ? 'reservation-overdue' : 'reservation-active';
                },
                'color' => function($row, $raw_row) {
                    return $raw_row->is_overdue ? '#F44336' : '#4CAF50';
                }
            ])
            ->setHeaderTitle('Equipment Schedule - ' . $baseDate->format('F j, Y'))
            ->setHeaderIcon('bi-tools')
            ->setHeaderColor('info')
            ->setRowHeaderLabel('Equipment')
            ->setShowNavigation(true)
            ->onEventClick('?page=reservations&action=view&id=%id%')
            ->onEmptyCellClick('?page=reservations&action=new&equipment=%row_id%&time=%time%')
            ->render();

        // Handle AJAX
        if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
            strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
            Response::json(['success' => true, 'html' => $schedule]);
        }

        Response::render(__DIR__ . '/Views/schedule.php', [
            'schedule' => $schedule
        ]);
    }
}

Example 3: Monthly Staff Schedule

class StaffScheduleController extends AbstractController
{
    #[RequestAction('home')]
    public function monthlyStaffSchedule()
    {
        $schedule = ScheduleGridBuilder::create($this->model, 'staff_schedule')
            ->setPeriod('month')
            ->detectPeriodFromRequest()
            ->join('LEFT JOIN #__departments d ON d.id = t.department_id')
            ->mapFields([
                'row_id' => function($row, $raw_row) {
                    return $raw_row->department->name . ' - ' . $raw_row->staff_name;
                },
                'id' => 'shift_id',
                'start_datetime' => 'shift_start',
                'end_datetime' => 'shift_end',
                'label' => function($row, $raw_row) {
                    $shift = $raw_row->shift_type; // morning, afternoon, night
                    $location = $raw_row->location;
                    return "$shift - $location";
                },
                'class' => function($row, $raw_row) {
                    return match($raw_row->shift_type) {
                        'morning' => 'shift-morning',
                        'afternoon' => 'shift-afternoon',
                        'night' => 'shift-night',
                        default => 'shift-default'
                    };
                },
                'color' => function($row, $raw_row) {
                    return match($raw_raw->shift_type) {
                        'morning' => '#FFC107',
                        'afternoon' => '#2196F3',
                        'night' => '#673AB7',
                        default => '#9E9E9E'
                    };
                }
            ])
            ->setHeaderTitle('Monthly Staff Schedule')
            ->setHeaderIcon('bi-people')
            ->setHeaderColor('success')
            ->setRowHeaderLabel('Staff')
            ->setYearRange(2024, 2026)
            ->onEventClick('?page=shifts&action=edit&id=%id%')
            ->onEmptyCellClick('?page=shifts&action=assign&staff=%row_id%&date=%date%')
            ->gridColor('success')
            ->render();

        // Handle AJAX
        if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
            strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
            Response::json(['success' => true, 'html' => $schedule]);
        }

        Response::render(__DIR__ . '/Views/schedule.php', [
            'schedule' => $schedule
        ]);
    }
}

Method Reference

Period Configuration Methods

Method Parameters Description
setPeriod() string $type Set period type: 'week', 'month', 'day', or 'custom'
setWeek() int $week, int $year Set specific week (1-53) and year for weekly view
setMonth() int $month, int $year Set specific month (1-12) and year for monthly view
setDateRange() DateTime $start, DateTime $end Set custom date range (used for day view and custom periods)
detectPeriodFromRequest() - Auto-detect period from REQUEST parameters based on grid_id

Field Mapping Methods

Method Parameters Description
mapFields() array $mappings Map database fields to grid properties. Supports string field names or callable functions.
Required keys: 'row_id', 'id', 'start_datetime', 'end_datetime'
Optional keys: 'label', 'class', 'color'

Display Configuration Methods

Method Parameters Description
setLocale() string $locale Set locale for date formatting (e.g., 'en_US', 'it_IT', 'fr_FR')
setHeaderTitle() string $title Set header title text
setHeaderIcon() string $icon Set header icon (Bootstrap Icons class, e.g., 'bi-calendar3')
setHeaderColor() string $color Set header color: 'primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark'
setShowHeader() bool $show Show or hide the grid header
setShowNavigation() bool $show Show or hide navigation controls
setMinYear() int $year Set minimum navigable year
setMaxYear() int $year Set maximum navigable year
setYearRange() int $minYear, int $maxYear Set both minimum and maximum navigable years
setTimeInterval() int $minutes Set time interval for day view columns (10, 15, 30, or 60 minutes)
setRowHeaderLabel() string $label Set label for row header column (top-left corner cell)
setColumnWidth() ?string $width Set column width (CSS value: '60px', '5rem', etc. or null for auto 1fr)

Styling Methods

Method Parameters Description
gridColor() string $color Apply coordinated color theme to grid (primary, secondary, success, danger, warning, info, light, dark)
setGridAttrs() array $attrs Set all grid attributes at once
addGridAttr() string $element, string $key, string $value Add single attribute to a grid element (container, grid, row-header, etc.)

Click Handler Methods

Method Parameters Description
onEventClick() string $url Set URL template for event clicks
Placeholders: %id%, %row_id%, %col_id%
onEmptyCellClick() string $url Set URL template for empty cell clicks
Placeholders: %row_id%, %col_id%, %date%, %time%

Custom Rendering Methods

Method Parameters Description
setCustomCellRenderer() callable $renderer Set custom function to render cells
Function receives: ($row_id, $col_id, $event, $is_grouped, $colspan)
Returns: HTML string

Grid Identification Methods

Method Parameters Description
setGridId() string $grid_id Set grid ID for AJAX requests and HTML element identification
getId() - Get grid ID (auto-generates if not set)

Query Methods (Inherited from GetDataBuilder)

Method Parameters Description
where() $condition, $params, $logic Add WHERE condition to query
orderBy() $field, $direction Add ORDER BY clause
join() $join_clause Add JOIN clause
limit() $limit Set query LIMIT (note: grid removes limit automatically)

Rendering Methods

Method Parameters Description
render() - Generate and return grid HTML
__toString() - Magic method - allows using grid as string

Best Practices

  • Set Period After DateRange: When using day view, call setPeriod('day') AFTER setDateRange() to override the 'custom' period type
  • Use Auto-Detection: Call detectPeriodFromRequest() to automatically handle period navigation from request parameters
  • Set Grid ID: Always provide a unique grid ID when creating the builder (second parameter of create())
  • Map row_id Correctly: The 'row_id' field determines which row each event appears in - ensure it returns consistent values
  • Use Callable Mapping: For dynamic values or complex logic, use callable functions in mapFields()
  • Filter Efficiently: Add WHERE conditions before calling render() for better performance
  • Handle AJAX: Always check for AJAX requests and return JSON for smooth navigation
  • Set Time Intervals: For day view, choose appropriate time intervals based on your needs (10, 15, 30, or 60 minutes)
  • Test Multi-day Events: Ensure your events can span multiple columns/days and are rendered correctly
  • Localization: Set locale to match your application's language for proper date formatting

Differences from CalendarBuilder

  • Dynamic Rows: ScheduleGridBuilder generates rows from data (resources), while CalendarBuilder has fixed date-based structure
  • row_id Field: ScheduleGridBuilder requires a 'row_id' mapping to determine which row each event belongs to
  • Time Intervals: Day view supports configurable time intervals (10, 15, 30, 60 minutes)
  • Cell Grouping: Events spanning multiple time slots are automatically merged into grouped cells
  • Pattern: Same base pattern as CalendarBuilder but with resource-based rows instead of fixed dates

Common Use Cases

Room Booking System

$schedule = ScheduleGridBuilder::create($bookingModel, 'room_schedule')
    ->setPeriod('week')
    ->detectPeriodFromRequest()
    ->where('building_id = ?', [$buildingId])
    ->mapFields([
        'row_id' => 'room_name',
        'id' => 'booking_id',
        'start_datetime' => 'start_time',
        'end_datetime' => 'end_time',
        'label' => 'event_name'
    ])
    ->setHeaderTitle('Room Bookings')
    ->setRowHeaderLabel('Rooms')
    ->render();

Teacher/Instructor Schedule

$schedule = ScheduleGridBuilder::create($lessonModel, 'teacher_schedule')
    ->setPeriod('week')
    ->detectPeriodFromRequest()
    ->mapFields([
        'row_id' => 'teacher_name',
        'id' => 'lesson_id',
        'start_datetime' => 'lesson_start',
        'end_datetime' => 'lesson_end',
        'label' => 'course_name'
    ])
    ->setHeaderTitle('Teacher Schedule')
    ->setRowHeaderLabel('Teachers')
    ->render();

Equipment Reservation

$today = new DateTime();
$schedule = ScheduleGridBuilder::create($reservationModel, 'equipment_schedule')
    ->setDateRange(
        (clone $today)->setTime(8, 0),
        (clone $today)->setTime(18, 0)
    )
    ->setPeriod('day')
    ->setTimeInterval(30)
    ->mapFields([
        'row_id' => 'equipment_name',
        'id' => 'reservation_id',
        'start_datetime' => 'checkout_time',
        'end_datetime' => 'return_time',
        'label' => 'project_name'
    ])
    ->setHeaderTitle('Equipment Reservations')
    ->setRowHeaderLabel('Equipment')
    ->render();
Loading...