FORCal ist flexibel wie ein Framework und lässt sich an die individuellen Anforderungen anpassen. Das AddOn ist skalierbar, unterstützt Multi-Language.
- Kalender-Flexibilität: Von Terminen über Events bis zu News – alles machbar.
- Custom Fields mit
.yml
: Definiere deine eigenen Eingabefelder und erweitere die Funktionalität. - Multi-Language-Support: Native Unterstützung für mehrsprachige REDAXO-Installationen.
- Einfacher Datenzugriff: Greife mit PHP-Methoden auf Termine zu, bekommst Objekte zurück.
- JSON API: Gib deine Events über eine API aus und filtere sie.
- Nahtlose Frontend & Backend Integration: Passt sich perfekt in dein REDAXO ein.
- Feingliedrige Benutzerrechte: Kontrolliere, wer was darf.
- iCal/CalDAV Export & Abo: Exportiere Termine als iCal, CalDAV oder biete Abo-Feeds an.
- Termin-Links für alle: Google Calendar, Outlook, ICS – alles dabei.
- Optionale Orte-Verwaltung: Verwalte Veranstaltungsorte, wenn du es brauchst.
- SQL-Filter für Power-User: Dynamisch gefilterte Auswahlfelder, die sich anpassen.
- Editor-Freedom: Wähle deinen bevorzugten Editor für Textfelder.
Die folgenden Abschnitte liefern dir die Details, Beispiele und Code-Schnipsel, die du als Dev brauchst, um FORCal in deine Projekte zu integrieren.
Im Handumdrehen Termine, Veranstaltungen und News verwalten
Egal ob man einen einfachen Kalender oder ein komplexes Event-System benötigt.
- Termine und Events erstellen: Füge Veranstaltungen, Termine und News einfach hinzu.
- Benutzerfreundliche Oberfläche: Intuitive Bedienung für schnelles Arbeiten.
- Flexibel anpassbar: Eigene Felder für deine speziellen Anforderungen.
- Mehrsprachige Unterstützung: Verwende FORCal in mehreren Sprachen.
- Kalender-Integration: Zeige deine Termine auf deiner Webseite an.
- Verwaltung von Orten: Ordne Veranstaltungen einfach Veranstaltungsorten zu.
- Export und Teilen: Exportiere Termine und teile sie mit anderen.
- Benutzerrechte verwalten: Bestimme, wer welche Inhalte bearbeiten darf.
Nach der Installation müssen die Nutzerrechte in den Benutzer-Rollen und die Benutzerberechtigungen im Kalender definiert werden.
Einbindung
use forCal\Factory\forCalEventsFactory;
Die forCalEventsFactory
-Klasse bietet eine elegante und flexible Methode, um Termine in forCal abzufragen. Mit einer intuitiven Fluent API ermöglicht sie komplexe Abfragen ohne umständliche Parameter und unterstützt automatisch die korrekte Behandlung von Benutzerberechtigungen im Backend und Frontend.
Die Factory-Klasse bietet eine fluide API für das Abrufen von Terminen:
use forCal\Factory\forCalEventsFactory;
// Alle Termine ab heute für die nächsten 6 Monate
$termine = forCalEventsFactory::create()
->from('today')
->to('+6 months')
->get();
- create(): Statische Methode zum Erstellen einer neuen Factory-Instanz
- from($startTime): Setzt den Startzeitpunkt (z.B. 'now', 'today', 'all', DateTime-Objekt)
- to($endTime): Setzt den Endzeitpunkt (z.B. '+6 months', '+1 year', DateTime-Objekt)
- inCategories($categories): Filtert nach Kategorien (ID oder Array von IDs)
- atVenue($venueId): Filtert nach Veranstaltungsort
- withFilter($field, $value): Fügt einen benutzerdefinierten Filter hinzu
- withUserPermissions($use): Aktiviert/Deaktiviert die Benutzerberechtigungen explizit
- sortBy($field, $direction): Fügt ein Sortierkriterium hinzu ('asc' oder 'desc')
- get(): Führt die Abfrage aus und gibt die Termine zurück
- getEntryById($id): Gibt einen einzelnen Termin nach ID zurück
// Termine ab jetzt
$termine = forCalEventsFactory::create()
->from('now')
->get();
// Termine ab heute bis Ende des Jahres
$termine = forCalEventsFactory::create()
->from('today')
->to('last day of december')
->get();
// Alle vergangenen und zukünftigen Termine
$termine = forCalEventsFactory::create()
->from('all')
->get();
// Termine der letzten Woche
$termine = forCalEventsFactory::create()
->from('-1 week')
->to('today')
->get();
// Termine für die nächsten 4 Wochen
$termine = forCalEventsFactory::create()
->from('now')
->to('+4 weeks')
->get();
// Mit DateTime-Objekten für den aktuellen Monat
$startDate = new \DateTime('first day of this month');
$endDate = new \DateTime('last day of this month');
$termine = forCalEventsFactory::create()
->from($startDate)
->to($endDate)
->get();
// Einen spezifischen Zeitraum definieren
$startDate = new \DateTime('2024-05-01');
$endDate = new \DateTime('2024-08-31');
$termine = forCalEventsFactory::create()
->from($startDate)
->to($endDate)
->get();
// DateTime mit spezifischen Uhrzeiten
$start = new \DateTime();
$start->setTime(8, 0, 0); // Heute um 8:00 Uhr
$end = new \DateTime();
$end->setTime(18, 0, 0); // Heute um 18:00 Uhr
$end->modify('+7 days'); // Eine Woche später
$termine = forCalEventsFactory::create()
->from($start)
->to($end)
->get();
// Termine der Kategorie 3
$termine = forCalEventsFactory::create()
->from('today')
->inCategories(3)
->get();
// Termine der Kategorien 1, 3 und 5
$termine = forCalEventsFactory::create()
->from('today')
->inCategories([1, 3, 5])
->get();
// Termine am Ort mit ID 2
$termine = forCalEventsFactory::create()
->from('today')
->atVenue(2)
->get();
// Termine der Kategorie 3 am Ort 2
$termine = forCalEventsFactory::create()
->from('today')
->inCategories(3)
->atVenue(2)
->get();
// Nur Termine mit Bildern
$termine = forCalEventsFactory::create()
->from('today')
->withFilter('image', true)
->get();
// Termine in Berlin
$termine = forCalEventsFactory::create()
->from('today')
->withFilter('city', 'Berlin')
->get();
// Termine mit Bildern, aber ohne Datei-Anhänge
$termine = forCalEventsFactory::create()
->from('today')
->withFilter('image', true)
->withFilter('file', false)
->get();
// Nach Titel alphabetisch sortieren
$termine = forCalEventsFactory::create()
->from('today')
->sortBy('title', 'asc')
->get();
// Nach Datum absteigend (neueste zuerst)
$termine = forCalEventsFactory::create()
->from('today')
->sortBy('date_time.date', 'desc')
->get();
// Mehrfache Sortierung: Erst nach Kategorie, dann nach Datum
$termine = forCalEventsFactory::create()
->from('today')
->sortBy('category_name', 'asc') // Primäres Sortierkriterium
->sortBy('date_time.date', 'asc') // Sekundäres Sortierkriterium
->get();
Die Factory erkennt automatisch, ob sie im Frontend oder Backend verwendet wird:
// Im Frontend: Ignoriert Benutzerberechtigungen
$termine = forCalEventsFactory::create()
->from('today')
->get();
// Im Backend: Berücksichtigt Benutzerberechtigungen automatisch
$termine = forCalEventsFactory::create()
->from('today')
->get();
// Explizit Benutzerberechtigungen ignorieren (z.B. für Admin-Übersicht)
$termine = forCalEventsFactory::create()
->from('today')
->withUserPermissions(false)
->get();
// Termin mit ID 123 abrufen
$termin = forCalEventsFactory::create()
->getEntryById(123);
// Termin mit ID 123 abrufen, aber nur wenn er ein Bild hat
$termin = forCalEventsFactory::create()
->withFilter('image', true)
->getEntryById(123);
// Workshop-Termine aus Berlin mit Bildern, nach Datum sortiert
$termine = forCalEventsFactory::create()
->from('today')
->to('+1 year')
->inCategories(3) // Angenommen, Kategorie 3 ist "Workshops"
->withFilter('city', 'Berlin')
->withFilter('image', true)
->sortBy('date_time.date', 'asc')
->get();
// Alle vergangenen Konzerte, gruppiert nach Veranstaltungsort
$termine = forCalEventsFactory::create()
->from('all')
->to('today')
->inCategories(2) // Angenommen, Kategorie 2 ist "Konzerte"
->sortBy('venue_name', 'asc')
->sortBy('date_time.date', 'desc')
->get();
// Termine abrufen
$termine = forCalEventsFactory::create()
->from('today')
->to('+3 months')
->sortBy('date_time.date', 'asc')
->get();
// Termine ausgeben
echo '<div class="termine-liste">';
foreach ($termine as $termin) {
echo '<div class="termin">';
echo '<h3>' . $termin['title'] . '</h3>';
echo '<p>' . $termin['date_time']['date'] . '</p>';
if (!$termin['date_time']['full_time'] && !empty($termin['date_time']['time'])) {
echo '<p>' . $termin['date_time']['time'] . '</p>';
}
if (isset($termin['teaser'])) {
echo '<div class="teaser">' . $termin['teaser'] . '</div>';
}
echo '</div>';
}
echo '</div>';
// Termine in einer bestimmten Stadt und mit einem bestimmten Attribut
$termine = forCalEventsFactory::create()
->from('today')
->withFilter('city', 'München')
->withFilter('besondere_eigenschaft', true)
->get();
// Nur Termine, deren Name das Wort "Workshop" enthält
$termine = forCalEventsFactory::create()
->from('today')
->withFilter('custom_filter', function($entry) {
return stripos($entry->entry_name, 'Workshop') !== false;
})
->get();
// Nur Termine, die vormittags stattfinden
$termine = forCalEventsFactory::create()
->from('today')
->withFilter('time_filter', function($entry) {
$hour = (int)substr($entry->entry_start_time, 0, 2);
return $hour >= 8 && $hour < 12;
})
->get();
Benutzer mit dem Recht forcal[all]
haben vollen Zugriff auf alle Kategorien, ähnlich wie Administratoren. Diese Benutzer können alle Termine einsehen und bearbeiten, unabhängig von den ihnen zugewiesenen Kategorien.
// Beispiel: Prüfen, ob ein Benutzer Zugriff auf eine bestimmte Kategorie hat
$hasAccess = forCalUserPermission::hasPermission($category_id);
Eine neue Berechtigung steuert, ob ein Benutzer Medien hochladen darf. Wenn deaktiviert, werden automatisch alle Media/Medialist-Felder in den Formularen ausgeblendet.
// Beispiel: Prüfen, ob ein Benutzer Medien hochladen darf
$canUploadMedia = forCalUserPermission::canUploadMedia();
Die Benutzerauswahl in der Berechtigungsverwaltung zeigt jetzt nur noch Benutzer mit forCal-Rechten an.
Die Orte-Funktionalität kann jetzt komplett deaktiviert werden. Ist diese Option abgeschaltet:
- Die Orte-Navigationspunkt wird ausgeblendet
- Orte-Auswahlfelder werden in Formularen nicht angezeigt
- SQL-Abfragen enthalten keine JOINs zur Orte-Tabelle
- Keine Orte-Eigenschaften in API-Antworten
// Beispiel: Prüfen, ob Orte aktiviert sind
$venuesEnabled = rex_addon::get('forcal')->getConfig('forcal_venues_enabled', true);
Media/Medialist-Felder werden automatisch ausgeblendet, wenn der Benutzer keine Medien-Upload-Berechtigung hat. Orte-bezogene Felder werden ausgeblendet, wenn die Orte-Funktionalität deaktiviert ist.
Validierung von Pflichtfeldern wie Terminname und Kategorie direkt im Browser mit benutzerfreundlichen Fehlermeldungen.
Das Addon prüft bei der Installation, ob die notwendigen Tabellen vorhanden sind, und erstellt diese falls nötig.
Bei einem Upgrade werden vorhandene Einstellungen beibehalten. Die neuen Berechtigungsfunktionen werden nahtlos zu bestehenden Installationen hinzugefügt.
// Prüfen, ob ein Benutzer Zugriff auf eine Kategorie hat
if (forCalUserPermission::hasPermission($category_id)) {
// Benutzer hat Zugriff
}
// Prüfen, ob ein Benutzer Medien hochladen darf
if (forCalUserPermission::canUploadMedia()) {
// Media-Felder anzeigen
}
// SQL-Abfrage mit Benutzerfilterung
$query = forCalSqlHelper::createFilteredQuery(
rex::getTable('forcal_entries'),
'user_id',
rex::getUser()->getId(),
'status = 1'
);
$results = rex_sql::factory()->getArray($query);
Eigene Felder können im Ordner /redaxo/data/addons/forcal/definitions/
angelegt werden. Die nach Installation dort befindlichen .yml Dateien erzeugen die Standardfelder. Möchte man eigene Definitionen erstellen, erstellt man entsprechende yml-files mit dem Prefix custom_
. Möchte man die Standardfelder behalten und weiternutzen, sollten diese auch in die custom Definitionen kopiert werden.
Beispiele für mögliche Felder findet man auch in den mitgelieferten yml.
- media: Definiert ein Medienauswahfeld für Medien aus dem Medienpool
- medialist: Definiert ein Mehrfach-Medienauswahfeld für Medien aus dem Medienpool
- text: Stellt eine Texteingabe zur Verfügung
- textarea: Stellt eine mehrzeilige Texteingabe zur Verfügung
- Link: Stellt einen Auswahldialog zur Auswahl eines internen Links zur Verfügung
- Linklist: Stellt einen Auswahldialog zur Mehrfach-Auswahl eines internen Links zur Verfügung
- select: Fügt dem Formular eine Selectbox mit definierbaren Werten und ggf. Werte aus einer Tabelle hinzu
- radio: Fügt dem Formular eine Radiobutton Group mit definierbaren Werten und ggf. Werte aus einer Tabelle hinzu
- checkbox: Fügt dem Formular eine Checkbox mit definierbaren Werten hinzu
- checkboxsql: Fügt dem Formular eine Checkbox mit Werten aus einer Tabelle hinzu
fields:
- name: 'image'
type: 'media'
label_de: 'Bildelement'
label_en: 'Image element'
- name: 'file'
type: 'media'
label_de: 'Datei Anhang'
label_en: 'File attachment'
langfields:
- panel: 'images'
label_de: 'Sprachbezogene Bildelemente'
label_en: 'Language-related images elements'
fields:
- name: 'lang_image'
type: 'media'
label_de: 'Bild'
label_en: 'Image'
- name: 'lang_images'
type: 'medialist'
label_de: 'Bilder'
label_en: 'Images'
- name: favfood
type: select
label_de: 'Lieblingsspeise'
label_en: 'Favorite Food'
options:
lk: 'Leberkäse'
pz: 'Pizza'
tf: 'Tofu'
- name: favfood
type: select
label_de: 'Lieblingsspeise'
label_en: 'Favorite Food'
qry: 'SELECT id, name FROM rex_yourfoodtable'
attribute:
multiple: multiple
size: 5
- name: haircolor
type: checkbox
label_de: 'Haarfarbe'
label_en: 'Hair Color'
options:
bl: 'Blau'
gr: 'Grün'
rt: 'Rot'
- name: haircolor
type: radio
label_de: 'Haarfarbe'
label_en: 'Hair Color'
options:
bl: 'Blau'
gr: 'Grün'
rt: 'Rot'
Zu allen Feldern können Attribute angegeben werden.
Beispiel für ein Textfeld, für das der Tinymce Editor verwendet werden soll. Das AddOn muss natürlich installiert sein damit das funktioniert.
- name: extratext
type: textarea
label_de: Extratext
label_en: Extratext
attribute:
class: 'tinyMCEEditor'
Ein Selectfeld mit mehrfacher Auswahlmöglichkeit und einer Höhe von 5 Elementen
- name: blumenstrauss
type: select
label_de: 'Zusammenstellung'
label_en: 'Collection'
options:
ro: 'Rosen'
da: 'Dalien'
tu: 'Tulpen'
attribute:
multiple: multiple
size: 5
forCal bietet jetzt die Möglichkeit, benutzerdefinierte Felder mit dynamisch gefilterten SQL-Abfragen zu erstellen. Dies ermöglicht eine berechtigungsabhängige Darstellung von Daten in Auswahlfeldern.
Um ein SQL-gefiltertes Auswahlfeld zu erstellen, nutze die .yml
-Datei im data/definitions/
-Verzeichnis:
fields:
- name: 'assigned_user'
type: 'selectsql'
label_de: 'Zuständiger Benutzer'
label_en: 'Assigned User'
qry: 'SELECT id, name FROM rex_user WHERE id = ###user_id### OR (SELECT LENGTH(rights) FROM rex_user WHERE id = ###user_id###) > 0 ORDER BY name'
Die ###user_id###
-Platzhalter werden automatisch durch die ID des aktuellen Benutzers ersetzt.
Für komplexere Filterungen bietet die neue forCalSqlHelper
-Klasse nützliche Methoden:
fields:
- name: 'assigned_user'
type: 'selectsql'
label_de: 'Zuständiger Benutzer'
label_en: 'Assigned User'
qry: '<?php echo \forCal\Utils\forCalSqlHelper::getFilteredQueryString(rex::getTable("user"), "id", "name", "id", rex::getUser()->getId(), "status = 1"); ?>'
Die Methode getFilteredQueryString
erzeugt eine SQL-Abfrage, die automatisch Benutzerberechtigungen berücksichtigt.
Hier ist ein Beispiel für ein Auswahlfeld, das basierend auf Benutzerberechtigungen unterschiedliche Optionen anzeigt:
fields:
- name: 'assigned_user'
type: 'selectsql'
label_de: 'Zuständiger Benutzer'
label_en: 'Assigned User'
qry: '<?php
$userId = rex::getUser()->getId();
$user = rex_user::get($userId);
if ($user->isAdmin() || $user->hasPerm("forcal[all]")) {
echo "SELECT id, CONCAT(name, \' (\', login, \')\') as name FROM " . rex::getTable("user") . " WHERE status = 1 ORDER BY name";
} else {
echo "SELECT id, CONCAT(name, \' (\', login, \')\') as name FROM " . rex::getTable("user") . " WHERE id = " . $userId . " OR id IN (SELECT user_id FROM " . rex::getTablePrefix() . "forcal_user_categories WHERE category_id IN (SELECT category_id FROM " . rex::getTablePrefix() . "forcal_user_categories WHERE user_id = " . $userId . ")) ORDER BY name";
}
?>'
Dieses Beispiel zeigt:
- Für Administratoren oder Benutzer mit
forcal[all]
-Recht: Alle Benutzer - Für eingeschränkte Benutzer: Nur der eigene Benutzer plus Benutzer mit gemeinsamen Kategoriezuweisungen
Du kannst auch eigene Hilfsfunktionen für komplexe Filterungen definieren:
- Erstelle eine PHP-Datei in deinem
lib/
-Verzeichnis:
<?php
namespace forCal\Custom;
use rex;
use rex_user;
class CustomFields
{
public static function getFilteredUserOptions($user_id)
{
// Prüfen, ob der aktuelle Benutzer Admin oder forcal[all]-Rechte hat
$user = rex_user::get($user_id);
$hasFullAccess = $user->isAdmin() || $user->hasPerm('forcal[all]');
// SQL-Abfrage erstellen
$table = rex::getTable('user');
if ($hasFullAccess) {
// Alle Benutzer anzeigen
return "SELECT id, name FROM $table ORDER BY name";
} else {
// Nur den eigenen Benutzer und Benutzer mit bestimmten Rechten anzeigen
return "SELECT id, name FROM $table WHERE id = $user_id OR rights LIKE '%forcal%' ORDER BY name";
}
}
}
- Verwende diese Funktion in deiner
.yml
-Datei:
fields:
- name: 'assigned_user'
type: 'selectsql'
label_de: 'Zuständiger Benutzer'
label_en: 'Assigned User'
qry: '<?php echo \forCal\Custom\CustomFields::getFilteredUserOptions(rex::getUser()->getId()); ?>'
Mit diesem Ansatz kannst du komplexe, dynamisch gefilterte Auswahlfelder erstellen, die Benutzerberechtigungen berücksichtigen und nur relevante Optionen anzeigen.
forCal erlaubt es, einen beliebigen Editor für die Eingabe in den Textfeldern zu wählen. Die Standard Textfelder können über JSON-Definitionen eingestellt werden. Das Verfahren entspricht der Lösung in yForm.
In den Einstellungen findet man zwei Felder zur Definition der individuellen Attribute für die Textfelder. Hier gibt man die gewünschten Attribute für den gewünschten Editor ein:
z.B.
{"class":"redactorEditor2-forcal_text"}
oder
{"class":"tinyMCEEditor-lite"}
Es können beliebige weitere Attribute hinzugefügt werden wie required
, data-attribute
, Zeichenlänge etc..
In den Eigenen Feldern können für jedes Feld Attribute angegeben werden, die die Textfelder beeinflussen und so auch Editoren einbinden.
Die API kann mit folgenden Parametern verwendet werden:
categories[]
- Eine oder mehrere Kategorie-IDs (optional)entry
- ID eines einzelnen Termins (optional)filename
- Name der heruntergeladenen Datei (optional, Standard: "calendar")
-
Alle Termine exportieren:
index.php?rex-api-call=forcal_ical
-
Nur Termine bestimmter Kategorien:
index.php?rex-api-call=forcal_ical&categories[]=1&categories[]=3
-
Einen einzelnen Termin exportieren:
index.php?rex-api-call=forcal_ical&entry=42
-
Mit angepasstem Dateinamen:
index.php?rex-api-call=forcal_ical&filename=vereinstermine
Die Termine werden immer 10 Jahre rückwirkend bis maximal 10 Jahre in die Zukunft exportiert.
Die Datei implementiert auch die korrekte Behandlung von wiederholenden Terminen mit RRULE, sodass Kalender-Programme die Wiederholungen korrekt darstellen können.
// Datum und Uhrzeit für Termin-Link holen und vorbereiten
$entry_start_time = $event->entry_start_time;
$entry_start_time_date = new DateTime($entry_start_time);
$start_time = $entry_start_time_date->format('H:i');
$entry_end_time = $event->entry_end_time;
$entry_end_time_date = new DateTime($entry_end_time);
$end_time = $entry_end_time_date->format('H:i');
// Daten und Uhrzeiten formatieren
$from_datetime = rex_formatter::format(date_timestamp_get($event->entry_start_date),'strftime','%Y-%m-%d').' '.$start_time;
$to_datetime = rex_formatter::format(date_timestamp_get($event->entry_end_date),'strftime','%Y-%m-%d').' '.$end_time;
$from = DateTime::createFromFormat('Y-m-d H:i', $from_datetime);
$to = DateTime::createFromFormat('Y-m-d H:i', $to_datetime);
$link = forCalLink::create(rex_escape($event->entry_name), $from, $to)
->description($event->entry_teaser) // Auskommentieren, falls kein Teaser vorhanden
->address($location); // Auskommentieren, falls keine Location vorhanden
echo '<a href="'.$link->google().'">Google Calendar</a><br>';
echo '<a href="'.$link->yahoo().'">Yahoo</a><br>';
echo '<a href="'.$link->webOutlook().'">Outlook</a><br>';
echo '<a href="'.$link->ics().'">ICS</a>';
Du hast einen Fehler gefunden oder ein nettes Feature parat? Lege ein Issue an. Bevor du ein neues Issue erstellst, suche bitte ob bereits eines mit deinem Anliegen existiert und lese die Issue Guidelines (englisch) von Nicolas Gallagher.
siehe LICENSE
Friends Of REDAXO
Development-Team
Mit freundlicher Unterstützung durch:
Deutsche Fußball-Route NRW e.V.