main
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:
caldavSyncEnabledcaldavUrlcaldavUsernamecaldavPasswordcaldavAuthorIdcaldavTimezone(FallbackUTC)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 einentl_calendarsynchronisieren--direction=pull|push|both: Richtung waehlen (Defaultboth)--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
- Push (lokal -> remote)
- Pull (remote -> lokal)
Delta-Sync (CTAG + ETAG)
- CTAG wird per
PROPFINDgelesen und pro Kalender-URL incaldavSyncCtagsgespeichert. - Wenn CTAG unveraendert ist, wird Pull fruehzeitig uebersprungen.
- Delta-Inventar per
REPORT(href + etag). GETnur fuer neue/geaenderte Remote-Objekte.
Konfliktregel (Last-Modified-Wins)
- Lokal wird ueber
tl_calendar_events.tstampbewertet. - Remote wird ueber
LAST-MODIFIEDbzw.DTSTAMPbewertet. - 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.pidgeladen und nur in diesem Kalender verarbeitet. - Matcher nutzt
caldavHrefundcaldavUid, optional mit explizitem Guard auf erwartetecalendarId. - Zielkalender fuer Push wird ueber
caldavCalendarHrefauf 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 = 1gesetzt.
Feldmapping
Bidirektional (hash-relevant):
titlestart/endall-day(addTime)description<->teaser(Plaintext/HTML-Konvertierung)locationurl(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:
caldavCalendarHrefcaldavUidcaldavHrefcaldavEtagcaldavSyncHashcaldavLastSynccaldavOrigincaldavSyncState
Alias-Verhalten:
- Alias wird bei Remote-Neuanlage als
YYYY-MM-DD_slugerzeugt. - Maximale Laenge: 40 Zeichen.
- Kollisionen werden mit Suffix (
_2,_3, ...) aufgeloest.
Wichtige Architekturpunkte
SyncRunner: Orchestrierung pro Kalender und RichtungRemoteToLocalSynchronizer: Pull + lokale Upserts/DeletesLocalToRemoteSynchronizer: Push + remote Upserts/DeletesSyncFieldExtractor: Mapping, Datumslogik, Teaser-Konvertierung, AliasbildungRemoteCalendarReader/RemoteCalendarWriter: CalDAV Lesen/SchreibenContaoCalendarEventRepository: 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 RichtungLocalToRemoteSynchronizer: Push + LMW + Hash-Guard + DeletesRemoteToLocalSynchronizer: Pull + LMW + Delta + DeletesRemoteCalendarReader: CTAG/REPORT/GET-DeltalogikSyncFieldExtractor: Feldmapping inkl. all-day-Umrechnung
Troubleshooting
- Keine Kalender in der Mehrfachauswahl:
- URL, Benutzername, Passwort pruefen
- Server muss CalDAV-Discovery/PROPFIND erlauben
- Unerwartete Konflikte:
tstamplokal undLAST-MODIFIEDremote vergleichen- Zeitzonen-Setup im Kalender pruefen
- Schreibfehler beim Push:
- ETag-Precondition und Zugriffsrechte am CalDAV-Server pruefen
Description
Languages
PHP
100%