CalDAV Sync Bundle (Contao 5.7)

Internes Bundle fuer 2-Way-CalDAV-Sync in Contao 5.7 (PHP 8.4). Diese README ist bewusst technisch gehalten (Prinzip, Logik, Betriebs-Commands) und kein oeffentliches Tutorial.

Umfang (V1)

  • Kein RRULE/EXDATE/RECURRENCE-ID-Support
  • Kein Backend-Button, Sync nur ueber Command/Cron
  • Harte Loeschung auf beiden Seiten, wenn das Gegenstueck fehlt
  • Konfliktaufloesung pro Event ueber Last-Modified-Wins (mit Toleranz)
  • Contao-only-Felder werden nicht in den Sync-Hash aufgenommen

Betriebsrelevante Konfiguration (tl_calendar)

Verwendete CalDAV-Felder pro Kalender:

  • caldavSyncEnabled
  • caldavUrl
  • caldavUsername
  • caldavPassword
  • caldavAuthorId
  • caldavTimezone (Fallback UTC)
  • caldavCalendarHrefs (Mehrfachauswahl)
  • caldavPastSyncRange (none|all|1y|2y)
  • caldavFutureSyncRange (all|1y|2y)
  • caldavSyncCtags (technischer Cache pro Remote-URL)

Mehrfachauswahl-Logik:

  • Ein Contao-Kalender kann mehrere Remote-Kalender referenzieren.
  • Beim Pull werden importierte Events aus abgewaehlten Remote-Kalendern entfernt.

Sync ausfuehren

php bin/console contao:caldav:sync --direction=both
php bin/console contao:caldav:sync --calendar=4 --direction=pull
php bin/console contao:caldav:sync --direction=push --dry-run

Optionen:

  • --calendar=ID: nur einen tl_calendar synchronisieren
  • --direction=pull|push|both: Richtung waehlen (Default both)
  • --dry-run: keine Schreiboperationen lokal/remote

Ergaenzende Betriebs-Commands:

php vendor/bin/contao-console contao:migrate --no-interaction
php vendor/bin/contao-console cache:clear

Sync-Verhalten im Detail

Reihenfolge bei --direction=both

  1. Push (lokal -> remote)
  2. Pull (remote -> lokal)

Delta-Sync (CTAG + ETAG)

  • CTAG wird per PROPFIND gelesen und pro Kalender-URL in caldavSyncCtags gespeichert.
  • Wenn CTAG unveraendert ist, wird Pull fruehzeitig uebersprungen.
  • Delta-Inventar per REPORT (href + etag).
  • GET nur fuer neue/geaenderte Remote-Objekte.

Konfliktregel (Last-Modified-Wins)

  • Lokal wird ueber tl_calendar_events.tstamp bewertet.
  • Remote wird ueber LAST-MODIFIED bzw. DTSTAMP bewertet.
  • Es gilt eine Toleranz von 120 Sekunden.
  • Wenn Remote-Zeitstempel fehlen, wird konservativ lokal bevorzugt.
  • Alle Vergleiche erfolgen auf Unix-Timestamps.

Kalenderbindung beim Matching

  • Events werden pro tl_calendar_events.pid geladen und nur in diesem Kalender verarbeitet.
  • Matcher nutzt caldavHref und caldavUid, optional mit explizitem Guard auf erwartete calendarId.
  • Zielkalender fuer Push wird ueber caldavCalendarHref auf die aktuelle Config-URL aufgeloest.

Loeschverhalten

  • Pull: lokale Gegenstuecke ohne Remote-Pendant werden geloescht.
  • Push: Remote-Events ohne lokales Pendant werden geloescht.
  • Zusaetzlich entfernt der Runner bei Pull importierte Events aus inzwischen abgewaehlten Remote-Kalendern.
  • Bei aktivem Zeitfenster werden Events ausserhalb des Fensters nicht aktiv geloescht.

Publikationsverhalten

  • Remote-importierte Events werden auf published = 1 gesetzt.

Feldmapping

Bidirektional (hash-relevant):

  • title
  • start/end
  • all-day (addTime)
  • description <-> teaser (Plaintext/HTML-Konvertierung)
  • location
  • url (optional)

Hash-Regel:

  • SyncHash basiert ausschliesslich auf den oben genannten bidirektionalen Feldern.
  • Push erfolgt nur bei Hash-Aenderung (oder Initialzustand ohne gespeicherten Hash).

Technische Sync-Felder in tl_calendar_events:

  • caldavCalendarHref
  • caldavUid
  • caldavHref
  • caldavEtag
  • caldavSyncHash
  • caldavLastSync
  • caldavOrigin
  • caldavSyncState

Alias-Verhalten:

  • Alias wird bei Remote-Neuanlage als YYYY-MM-DD_slug erzeugt.
  • Maximale Laenge: 40 Zeichen.
  • Kollisionen werden mit Suffix (_2, _3, ...) aufgeloest.

Wichtige Architekturpunkte

  • SyncRunner: Orchestrierung pro Kalender und Richtung
  • RemoteToLocalSynchronizer: Pull + lokale Upserts/Deletes
  • LocalToRemoteSynchronizer: Push + remote Upserts/Deletes
  • SyncFieldExtractor: Mapping, Datumslogik, Teaser-Konvertierung, Aliasbildung
  • RemoteCalendarReader / RemoteCalendarWriter: CalDAV Lesen/Schreiben
  • ContaoCalendarEventRepository: DB-Zugriff inkl. schema-toleranter Writes

Grenzen und Hinweise

  • V1 behandelt keine Serienereignisse.
  • Sync ist command-getrieben; ein Cronjob sollte das Command zyklisch starten.
  • CalDAV-Passwort wird als Klartext fuer Authentifizierung verwendet.

Kernkomponenten

  • SyncRunner: Orchestrierung je Kalender und Richtung
  • LocalToRemoteSynchronizer: Push + LMW + Hash-Guard + Deletes
  • RemoteToLocalSynchronizer: Pull + LMW + Delta + Deletes
  • RemoteCalendarReader: CTAG/REPORT/GET-Deltalogik
  • SyncFieldExtractor: Feldmapping inkl. all-day-Umrechnung

Troubleshooting

  • Keine Kalender in der Mehrfachauswahl:
    • URL, Benutzername, Passwort pruefen
    • Server muss CalDAV-Discovery/PROPFIND erlauben
  • Unerwartete Konflikte:
    • tstamp lokal und LAST-MODIFIED remote vergleichen
    • Zeitzonen-Setup im Kalender pruefen
  • Schreibfehler beim Push:
    • ETag-Precondition und Zugriffsrechte am CalDAV-Server pruefen
S
Description
No description provided
Readme 82 KiB
Languages
PHP 100%