- Implement SyncCron class for scheduling iCal sync every 15 minutes. - Create main plugin file with initialization and activation hooks. - Add admin booking modal for managing reservations, including AJAX functionality for searching available rooms and creating bookings. - Include necessary CSS and JS for modal functionality and user interaction. - Ensure compatibility with MotoPress Hotel Booking plugin.
145 lines
3.4 KiB
PHP
145 lines
3.4 KiB
PHP
<?php
|
|
|
|
namespace MphbIcalSync;
|
|
|
|
/**
|
|
* Parser plików iCal (.ics) zgodny z RFC 5545.
|
|
* Nie wymaga zewnętrznych bibliotek.
|
|
*/
|
|
class Parser {
|
|
|
|
/**
|
|
* Parsuje zawartość pliku .ics i zwraca tablicę eventów.
|
|
*
|
|
* @param string $icsContent Zawartość pliku .ics
|
|
* @return array[] Tablica eventów: [uid, dtstart, dtend, summary, status]
|
|
*/
|
|
public function parse( string $icsContent ): array {
|
|
// Unfold lines (RFC 5545: linia złożona z CRLF + spacja/tab jest kontynuacją)
|
|
$icsContent = preg_replace( "/\r\n[ \t]/", '', $icsContent );
|
|
$icsContent = preg_replace( "/\n[ \t]/", '', $icsContent );
|
|
|
|
$lines = preg_split( "/\r\n|\n|\r/", $icsContent );
|
|
|
|
$events = [];
|
|
$inEvent = false;
|
|
$current = [];
|
|
|
|
foreach ( $lines as $line ) {
|
|
$line = trim( $line );
|
|
|
|
if ( $line === 'BEGIN:VEVENT' ) {
|
|
$inEvent = true;
|
|
$current = [];
|
|
continue;
|
|
}
|
|
|
|
if ( $line === 'END:VEVENT' ) {
|
|
$inEvent = false;
|
|
if ( ! empty( $current ) ) {
|
|
$event = $this->parseEvent( $current );
|
|
if ( $event !== null ) {
|
|
$events[] = $event;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if ( $inEvent && $line !== '' ) {
|
|
$current[] = $line;
|
|
}
|
|
}
|
|
|
|
return $events;
|
|
}
|
|
|
|
/**
|
|
* @param string[] $lines Linie z wnętrza VEVENT
|
|
* @return array|null Sparsowany event lub null (jeśli CANCELLED/niepełny)
|
|
*/
|
|
private function parseEvent( array $lines ): ?array {
|
|
$event = [
|
|
'uid' => '',
|
|
'dtstart' => '',
|
|
'dtend' => '',
|
|
'summary' => '',
|
|
'status' => '',
|
|
];
|
|
|
|
foreach ( $lines as $line ) {
|
|
$colonPos = strpos( $line, ':' );
|
|
if ( $colonPos === false ) {
|
|
continue;
|
|
}
|
|
|
|
$key = strtoupper( substr( $line, 0, $colonPos ) );
|
|
$value = substr( $line, $colonPos + 1 );
|
|
|
|
// Oddziel parametry od nazwy właściwości (DTSTART;VALUE=DATE → DTSTART)
|
|
$semiPos = strpos( $key, ';' );
|
|
$baseKey = $semiPos !== false ? substr( $key, 0, $semiPos ) : $key;
|
|
|
|
switch ( $baseKey ) {
|
|
case 'UID':
|
|
$event['uid'] = trim( $value );
|
|
break;
|
|
case 'DTSTART':
|
|
$event['dtstart'] = $this->parseDate( $value );
|
|
break;
|
|
case 'DTEND':
|
|
$event['dtend'] = $this->parseDate( $value );
|
|
break;
|
|
case 'SUMMARY':
|
|
$event['summary'] = $this->unescapeIcalText( $value );
|
|
break;
|
|
case 'STATUS':
|
|
$event['status'] = strtoupper( trim( $value ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Pomiń anulowane eventy
|
|
if ( $event['status'] === 'CANCELLED' ) {
|
|
return null;
|
|
}
|
|
|
|
// Pomiń eventy bez wymaganych pól
|
|
if ( empty( $event['uid'] ) || empty( $event['dtstart'] ) || empty( $event['dtend'] ) ) {
|
|
return null;
|
|
}
|
|
|
|
return $event;
|
|
}
|
|
|
|
/**
|
|
* Konwertuje datę iCal do formatu Y-m-d.
|
|
* Obsługuje: YYYYMMDD, YYYYMMDDTHHmmss, YYYYMMDDTHHmmssZ
|
|
*/
|
|
private function parseDate( string $value ): string {
|
|
$value = trim( $value );
|
|
|
|
// Usuń część czasową i strefę czasową (Z lub identyfikator)
|
|
$tPos = strpos( $value, 'T' );
|
|
if ( $tPos !== false ) {
|
|
$value = substr( $value, 0, $tPos );
|
|
}
|
|
|
|
// Usuń myślniki jeśli są
|
|
$value = str_replace( '-', '', $value );
|
|
|
|
if ( strlen( $value ) === 8 && ctype_digit( $value ) ) {
|
|
return substr( $value, 0, 4 ) . '-' . substr( $value, 4, 2 ) . '-' . substr( $value, 6, 2 );
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
private function unescapeIcalText( string $text ): string {
|
|
$text = str_replace( '\\n', "\n", $text );
|
|
$text = str_replace( '\,', ',', $text );
|
|
$text = str_replace( '\;', ';', $text );
|
|
$text = str_replace( '\\\\', '\\', $text );
|
|
return $text;
|
|
}
|
|
}
|