='); if ($strftimeDeprecated) { require 'php-8.1-strftime.php'; } $strftime = function (...$args) { global $strftimeDeprecated; return $strftimeDeprecated ? PHP81_BC\strftime(...$args) : \strftime(...$args); }; function parseData($config, $data) { global $strftime; $languages = array( 'en' => array( 'name' => 'English', 'locale' => 'en_US.UTF8' ), 'bg' => array( 'name' => 'Български', 'locale' => 'bg_BG.UTF8' ) ); if ($data === false) return false; $halls = $data['halls']; ksort($halls); // We need to set these so we actually parse properly the dates. WP fucks up both. date_default_timezone_set('Europe/Sofia'); setlocale(LC_TIME, $languages[$config['lang']]['locale']); // Filter out invalid slots $data['slots'] = array_filter($data['slots'], function($slot) { return isset($slot['starts_at'], $slot['ends_at'], $slot['hall_id'], $slot['event_id']); }); // Collect the slots for each hall, sort them in order of starting $slots = []; $timestamps = []; $filtered_type_id = array_key_exists('filterEventType', $config) && array_key_exists($config['filterEventType'], $config['eventTypes']) ? $config['eventTypes'][$config['filterEventType']] : null; foreach ($halls as $hall_id => $hall) { $slots[$hall_id] = []; foreach ($data['slots'] as $slot_id => $slot) { if ($slot['hall_id'] !== $hall_id) { continue; } $eid = $slot['event_id']; $etype = $data['events'][$eid]['event_type_id']; if ($etype !== $filtered_type_id && !is_null($filtered_type_id)) { continue; } if (!in_array($slot['starts_at'], $timestamps)) { $timestamps[] = $slot['starts_at']; } if (!in_array($slot['ends_at'], $timestamps)) { $timestamps[] = $slot['ends_at']; } $slots[$hall_id][$slot['starts_at']] = $slot; } ksort($slots[$hall_id]); if (empty($slots[$hall_id])) unset($slots[$hall_id]); } sort($timestamps); // Find all microslots (the smallest time unit) $microslots = []; $lastTs = 0; $first = true; foreach ($timestamps as $ts) { if ($first) { $lastTs = $ts; $first = false; continue; } if (date('d.m', $lastTs) !== date('d.m', $ts)) { $lastTs = $ts; continue; } $microslots[] = [$lastTs, $ts]; $lastTs = $ts; } // Fill in the event ID for each time slot in each hall $events = []; foreach ($halls as $hall_id => $hall) { $hall_data = []; foreach ($microslots as $timestamps) { $found = false; foreach ($data['slots'] as $slot_id => $slot) { if ( $slot['hall_id'] === $hall_id && $slot['starts_at'] <= $timestamps[0] && $slot['ends_at'] >= $timestamps[1] && array_key_exists($slot['event_id'], $data['events']) ) { if (!is_null($filtered_type_id)) { if ($data['events'][$slot['event_id']]['event_type_id'] !== $filtered_type_id) { continue; } } $found = true; $hall_data[] = [ 'event_id' => $slot['event_id'], 'hall_id' => $slot['hall_id'], 'edge' => $slot['starts_at'] === $timestamps[0] || $slot['ends_at'] === $timestamps[1], ]; break; } } if (!$found) { $hall_data[] = null; } } $events[$hall_id] = $hall_data; } // Remove halls with no events after filtering foreach ($events as $i => $event) { $hasEvents = false; foreach ($event as $event_info) { if (!is_null($event_info)) { $hasEvents = true; break; } } if (!$hasEvents) { unset($events[$i]); } } // Transpose the matrix // rows->halls, cols->timeslots ===> rows->timeslots, cols->halls $events = array_map(null, ...$events); // Filter empty slots foreach($events as $i => $event) { $hall_count = count($event); $hasEvents = false; for ($j = 0; $j < $hall_count; ++$j) { if (!is_null($event[$j]) && $event[$j]['edge']) { $hasEvents = true; continue 2; } } if (!$hasEvents) { unset($events[$i]); } } // Merge events longer than one slot $prevEventId = []; $prevEventSlot = []; $prevSlotIndex = 0; $first = true; foreach ($events as $slot_index => &$events_data) { if ($first) { $prevEventId = array_map(function($event_info) { return is_null($event_info) ? null : $event_info['event_id']; }, $events_data); $prevEventSlot = array_fill(0, count($events_data), null); $prevSlotIndex = $slot_index; $first = false; continue; } foreach ($events_data as $hall_index => &$event_info) { if (is_null($event_info)) { $prevEventId[$hall_index] = null; $prevEventSlot[$hall_index] = null; continue; } if ($event_info['event_id'] !== $prevEventId[$hall_index]) { $prevEventId[$hall_index] = $event_info['event_id']; $prevEventSlot[$hall_index] = null; continue; } // We have a long event if (is_null($prevEventSlot[$hall_index])) { $prevEventSlot[$hall_index] = $prevSlotIndex; } $masterSlotIndex = $prevEventSlot[$hall_index]; // check if the events spans on the next day if (date('d.m', $microslots[$slot_index][0]) !== date('d.m', $microslots[$masterSlotIndex][1])) { // not sure why this is needed, but it fixes things $prevEventSlot[$hall_index] = null; continue; } $master_slot = &$events[$masterSlotIndex][$hall_index]; if (!array_key_exists('rowspan', $master_slot)) { $master_slot['rowspan'] = 2; } else { ++$master_slot['rowspan']; } unset($master_slot); $event_info = false; } unset($event_info); $prevSlotIndex = $slot_index; } unset($events_data); // Build the HTML $schedule_body = ''; $lastTs = 0; $fulltalks = ''; $hall_ids = []; $now = time(); $known_events = array(); foreach ($events as $slot_index => $events_data) { $columns = []; if (date('d.m', $microslots[$slot_index][0]) !== date('d.m', $lastTs)) { $schedule_body .= '
' . htmlentities($event['title']) . ' ' . $fulltalk_spkr . '
'; $fulltalks .= '' . htmlentities($event['abstract']) . '
'; $fulltalks .= $fullfb; $fulltalks .= ''; foreach ($halls as $hall_id => $hall) { if (!in_array($hall_id, $hall_ids)) { continue; } $schedule .= ' | ' . $hall[$config['lang']] . ' | '; } $schedule .= '
---|