srhinow / training-plan-manager
Wöchentlicher Trainingsplan (Wochentag + Von–Bis + Gruppe) für das Contao CMS – schlanke Alternative zu wiederkehrenden Kalender-Events
Package info
gitlab.com/srhinow/training-plan-manager
Type:contao-bundle
pkg:composer/srhinow/training-plan-manager
Requires
- php: ^8.3
- contao/core-bundle: ^5.7
Requires (Dev)
- contao/manager-plugin: ^2.0
- doctrine/dbal: ^3.6
- friendsofphp/php-cs-fixer: ^3.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
README
Ein schlankes Contao-5-Bundle zur Verwaltung eines wöchentlichen Trainingsplans: Wochentag + Von–Bis + Gruppe, ohne die Umständlichkeit wiederkehrender Kalender-Events.
Gedacht für Vereine/Schulen mit festem Wochenrhythmus (z. B. Kampfsport, Fitness), bei denen der Kalender nur für echte Einzeltermine (Prüfungen, Ausflüge, Lehrgänge) zuständig bleiben soll.
Warum
Wiederkehrende Trainingszeiten als vollwertige Kalender-Events zu pflegen (Datum, Uhrzeit, Wiederholung, Ausnahmen) ist für Redakteure umständlich. Im Kern ist ein Trainingsplan aber nur ein fester Wochenplan. Dieses Bundle bildet genau das ab.
Funktionsumfang
- Datenmodell
tl_training_time:title,weekday(Mo–So),timeStart/timeEnd,trainingGroup(Fremdschlüssel auftl_training_group), optionallocation/note, beliebig viele Ausfall-Zeiträume (cancellations, rowWizard),trainingMode,published. - Backend-Modul „Trainingszeiten": flache, sortierbare Liste, in Sekunden editierbar;
Trainingsgruppen als eigene Einstellungs-Tabelle (
tl_training_group:title,alias,appliesToAll). - Betriebsart-Umschalter „Regelbetrieb ↔ Ferienbetrieb": ein Klick publiziert die Termine der
Ziel-Betriebsart und blendet die der anderen aus. Slots mit
trainingMode = alwaysbleiben unberührt. - Frontend-Module (Kategorie „Trainingsplan"):
training_next– nächstes anstehendes Trainingtraining_list– kommende Termine, nach Tag/Datum gruppiert (Markup wie die Contao-Event-Liste)training_calendar– Wochenkalender Mo–So mit Vor/Zurück-Navigationtraining_feed– „Trainingsplan abonnieren": fertige Abo-Adressen je Gruppe, Kopier-Knopf undwebcal://-Link
- Insert-Tags:
{{next_training_day}},{{next_training_date}},{{next_training_datetime}}. - iCalendar-Abo unter
/training-plan/schedule.ics(siehe unten).
Bedienung im Backend
Alles liegt unter Inhalte → Trainingszeiten. Die Liste zeigt oben drei Schaltflächen: den Betriebsart-Umschalter, „Trainingsgruppen" und „Mehrere bearbeiten".
1. Trainingsgruppen anlegen (Button „Trainingsgruppen"): Name + Alias, z. B. „Anfänger",
„Fortgeschrittene" und – falls zeitweise gemeinsam trainiert wird – „alle". Der Alias ist es,
der später in der Abo-Adresse steht (?group=anfaenger).
2. Bei einer gemeinsamen Gruppe („alle") die Checkbox „Termine gelten für alle Gruppen"
(appliesToAll) setzen. Sie sitzt bewusst an der Gruppe, nicht am einzelnen Termin – sonst
müsste sie an jedem Ferientermin einzeln gepflegt werden. Wirkung siehe
Gemeinsame Termine.
3. Trainingszeiten anlegen: Titel, Wochentag, Von–Bis, Gruppe und Betriebsart:
| Betriebsart | Bedeutung |
|---|---|
Regelbetrieb | normale Zeiten, im Ferienbetrieb ausgeblendet |
Ferienbetrieb | Ferienzeiten (meist gemeinsames Training), im Regelbetrieb ausgeblendet |
immer | läuft in beiden Fällen; der Umschalter fasst diese Termine nie an |
4. Umschalten: Der Button oben links heißt je nach Lage „Ferienbetrieb einschalten" bzw. „Regelbetrieb einschalten" und publiziert mit einem Klick die Termine der Ziel-Betriebsart, während er die der anderen ausblendet. Einzeln „Veröffentlichen" muss also niemand.
5. Ausfälle (Ferien, Feiertage, Einzeltermine) trägt man am jeweiligen Trainingstermin unter „Ausfälle" als Zeiträume ein – siehe Trainingsfreie Zeiten.
Kalender-Abo (iCal)
https://<domain>/training-plan/schedule.ics
https://<domain>/training-plan/schedule.ics?group=<gruppen-alias>
Die URL ist als Abonnement gedacht (Google Kalender „Per URL hinzufügen", Apple Kalender „Kalenderabo", Thunderbird „Netzwerk-Kalender") — nicht als einmaliger Download.
Jede Trainingszeit wird zu einem wiederkehrenden Termin (RRULE:FREQ=WEEKLY) statt zu einer
Liste ausgerollter Einzeltermine. Das Abo läuft dadurch nicht nach ein paar Monaten leer, und die
Kalender-App zeigt den Plan unbegrenzt weiter. Eingetragene Ausfall-Zeiträume erscheinen als
EXDATE, verschwinden also auch im abonnierten Kalender.
Die Zeiten sind lokale Zeiten mit TZID, nie UTC — ein Training um 17:00 bleibt über den
Sommer-/Winterzeit-Wechsel hinweg um 17:00. Die Zeitzone liegt als VTIMEZONE-Komponente bei,
das Dokument ist also selbsttragend.
Ausgegeben werden nur veröffentlichte Trainingszeiten — der Umschalter Regelbetrieb/Ferienbetrieb
wirkt damit automatisch auch auf das Abo. Die Termin-UIDs sind stabil (training-<id>@<domain>),
Änderungen aktualisieren beim Abonnenten also den bestehenden Termin, statt einen zweiten anzulegen.
Gemeinsame Termine („Termine gelten für alle Gruppen")
Trainiert im Ferienbetrieb die ganze Gruppe zusammen, hängen diese Termine üblicherweise an einer
eigenen Gruppe („alle"). Damit ein Abo trotzdem stimmt, hat tl_training_group das Feld
appliesToAll: Termine einer so markierten Gruppe erscheinen zusätzlich in jedem anderen
Gruppen-Abo.
Ein Mitglied abonniert damit einmalig seine Gruppe und sieht im Regelbetrieb nur die eigenen Termine, im Ferienbetrieb die gemeinsamen — ohne das Abo zu wechseln:
| Betriebsart | Abo „Anfänger" zeigt | Abo „Fortgeschrittene" zeigt |
|---|---|---|
| Regelbetrieb | Anfänger-Termine (+ immer-Termine der Gruppe „alle") | Fortgeschrittenen-Termine (+ dieselben immer-Termine) |
| Ferienbetrieb | gemeinsame Ferientermine | gemeinsame Ferientermine |
Das Modul „Trainingsplan abonnieren" bietet für solche Gruppen bewusst keinen eigenen Link an; ein zusätzliches Abo würde dieselben Termine ein zweites Mal in den Kalender legen.
Ohne gesetztes Flag verhält sich alles wie vor 0.6.0: Ein Gruppen-Abo enthält ausschließlich die Termine dieser einen Gruppe — und läuft im Ferienbetrieb entsprechend leer.
Trainingsfreie Zeiten
Ausfälle (Ferien, Feiertage, Einzelausfälle) werden ausschließlich am Trainingszeiten-Datensatz
gepflegt – über die Ausfall-Zeiträume (cancellations). Es gibt bewusst keine Anbindung an
Kalender aus contao/calendar-bundle: sie wäre eine zweite, konkurrierende Pflegestelle für
dieselbe Information. Alle Ausgaben (Module wie Insert-Tags) berücksichtigen die Ausfälle damit
einheitlich.
Installation
composer require srhinow/training-plan-manager
vendor/bin/contao-console contao:migrate # legt tl_training_time + tl_training_group an
Datenmodell
weekday ist ISO-8601 kodiert (1 = Montag … 7 = Sonntag), passend zu date('N') für die
„nächstes Training"-Berechnung. timeStart/timeEnd sind Contao-time-Felder (Unix-Timestamp
auf dem Referenztag 1970-01-01). cancellations ist ein serialisiertes rowWizard-Array aus
from/to-Datumswerten (ISO Y-m-d).
Entwicklung
composer install
composer run qa # php-cs-fixer (Dry-Run) + PHPStan + PHPUnit
composer run cs-fix # Coding-Standard anwenden
composer run unit-tests # nur PHPUnit
Die Tests decken die Terminberechnung (TrainingScheduleCalculator) und das Parsen der
Ausfall-Zeiträume (TrainingTimeModel) ab; sie laufen ohne Datenbank und ohne Contao-Framework.
Die Zeitzone ist in phpunit.xml.dist auf Europe/Berlin festgenagelt, weil die Wochen-Schritte
über Sommer-/Winterzeit-Wechsel hinweg korrekt bleiben müssen.
Lizenz
GPL-3.0-or-later · © Sven Rhinow