Artikel: Blog
von
Dieser Artikel ist bereits über 2 Jahre alt. Das gezeigte Vorgehen ist vielleicht nicht mehr aktuell.
Copyright bei Patrick Froch und easy Solutions IT. Dieses Werk ist lizenziert unter Creative Commons BY-NC-SA.

Leider sind im Contao-Handbuch bis heute keine Beispiele für die Verwendung der Callbacks enthalten. Vor ca. 3 Jahren habe ich hierzu einen Text eingereicht. Es gab zu dem Thema auch ein Diskussion auf GitHub, aber leider ist es nicht zu einer Veröffentlichung gekommen. Da ich beinahe täglich mit den Callbacks arbeite, finde ich eine Übersicht mit Beispielen eine große Erleichterung. Für alle denen es ähnlich geht, stelle ich hier meine Aufstellung zur Verfügung.

Aktionscallbacks

button_callback

Ermöglicht individuelle Navigationssymbole und wird z.B. in der Seitenstruktur verwenden, um Icons abhängig von den Benutzerrechten zu deaktivieren (erfordert eine zusätzliche Prüfung mittels load_callback).

Dieser Aktionscallback wird folgendermaßen in die Definition der Operationen eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

label_callback

Ermöglicht individuelle Bezeichnungen in der Listenansicht und wird z.B. im Benutzer-Modul verwendet, um die Status-Icons hinzuzufügen.

Dieser Aktionscallback wird folgendermaßen in die Definition des Labels eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

Auflistungscallbacks

child_record_callback

Legt fest, wie die Kindelemente im "Parent View" dargestellt werden.

Dieser Auflistungscallback wird folgendermaßen in die Definition der Sortierung eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

group_callback

Ermöglicht individuelle Gruppennamen in der Listenansicht.

(Wird im Contao-Core scheinbar nicht verwendet, leider habe ich kein Beispiel gefunden!)

paste_button_callback

Ermöglicht individuelle Einfüge-Schaltflächen und wird z.B. in der Seitenstruktur verwenden, um die Icons abhängig von den Benutzerrechten zu deaktivieren (erfordert eine zusätzliche Prüfung mittels load_callback).

Dieser Auflistungscallback wird folgendermaßen in die Definition der Sortierung eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

Feldcallbacks

input_field_callback

Ermöglicht das Erstellen individueller Formularfelder und wird z.B. im Backend-Modul "Persönliche Daten" verwendet, um das "Daten bereinigen"-Feld zu erstellen. Achtung: Eingaben werden nicht automatisch gespeichert!

Dieser Feldcallback wird folgendermaßen in die Felddefinition eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

load_callback

Wird bei der Initialisierung eines Formularfeldes ausgeführt. Ermöglicht z.B. das Laden eines Standardwertes.

Dieser Feldcallback wird folgendermaßen in die Felddefinition eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

options_callback

Ermöglicht das Befüllen eines Drop-Down-Menüs oder einer Checkbox-Liste mittels einer individuellen Funktion. Kann z.B. für bedingte Fremdschlüssel-Relationen verwendet werden.

Dieser Feldcallback wird folgendermaßen in die Felddefinition eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

save_callback

Wird beim Abschicken eines Feldes ausgeführt. Ermöglicht z.B. das Hinzufügen einer individuellen Prüfung.

Dieser Feldcallback wird folgendermaßen in die Felddefinition eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

Globale Callbacks

oncopy_callback

Wird ausgeführt nachdem ein Datensatz dupliziert wurde. Hinzugefügt in Version 2.8.2.

Dieser Callback wird folgendermaßen in die DCA-Definition eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

oncut_callback

Wird ausgeführt nachdem ein Datensatz verschoben wurde. Hinzugefügt in Version 2.8.2.

Dieser Callback wird folgendermaßen in die DCA-Definition eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

ondelete_callback

Wird ausgeführt bevor ein Datensatz aus der Datenbank entfernt wird.

Dieser Callback wird folgendermaßen in die DCA-Definition eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

onload_callback

Wird bei der Initialisierung des DataContainer-Objekts ausgeführt. Ermöglicht z.B. das Prüfen von Zugriffsrechten oder die dynamische Änderung des Data Container Array zur Laufzeit.

Dieser Callback wird folgendermaßen in die DCA-Definition eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

onsubmit_callback

Wird beim Abschicken eines Backend-Formulars ausgeführt. Ermöglicht z.B. die Modifizierung der Formulardaten, bevor diese in die Datenbank geschrieben werden (wird in der Kalender-Erweiterung zur Intervalberechnung eingesetzt).

Dieser Callback wird folgendermaßen in die DCA-Definition eingefügt:

Die Klasse, die den Callback verarbeitet kann dann zum Beispiel so aussehen:

Zurück

Kommentare

Kommentar von Andreas Fieger |

Danke für den Post!

Type: im zweiten Listing: $this-addToUrl($href) muss $this->addToUrl($href) sein (es fehlt das '>').

Antwort von Patrick Froch

Danke für den Hinweis. Das ">" war schon da, leider hat es der SyntaxHighlighter verschluckt. Nun sollte es aber angezeigt werden.

Kommentar von Daniel Jahnsmüller |

Sehr schade das ich erst jetzt drauf stoße. Mich stört auch schon immer die ungenaue Dokumentation und ich schau am Ende immer im Quelltext.

Vielen Dank Patrick! Lesezeichen ist gesetzt.

Kommentar von Mario |

Sehr schöne Auflistung. Danke! :)

Allerdings fehlen einige Callbacks, z.B. der oncreate oder oncreate_version callback. Vielleicht kannst du die noch ergänzen?

Antwort von Patrick Froch

Hallo Mario,

danke für den Hinweis. Als der Artikel entstanden ist, gab es diese Callbacks noch nicht. Insgesamt ist dieser Blog ja quasi mein digitales Gedächtnis. Wenn ich die neuen Callbacks benötige, werde ich die Funktionsweise bestimmt auch hier niederschreiben.

Viele Grüße,
Patrick

Kommentar von Christian Mette |

Ja! Prima Auflistung und immer noch aktuell und praxisrelevant! Vielen Dank!

Der bis heute (meiner Kenntnis nach) wenig oder nicht dokumentierte (seit 2.8) panel_callback zum Generieren von benutzerdefinierten Input-Elementen in einem eigenen Filter-Panel könnte noch ergänzt werden. Position und Aufruf:

list.sorting.panel_callback => ['myFilterName' => ['myClass', 'buildMyFilterInput']] # es kann viele benutzerdefinierte Filter-Felder geben

Signatur:

public function buildMyFilterInput(\DataContainer $dc) {
...
return $html; # returns the filter as html string
}

Das ganze muß noch mit einem eigenen onload_callback kombiniert werden, um die Filter bei jedem Laden zu aktivieren. Der Handler könnte so aussehen:

public function applyAdvancedFilters()
{
# die Session holen
$session = Session::getInstance()->getData();

# testen, ob ein POST gesendet wurde und ob das $_POST vom Filter FORM_SUBMIT kommt
if(isset($_POST) && \Input::post('FORM_SUBMIT')=='tl_filters') {
# wenn ja, hole den Select Value
$postedTimerange = \Input::post('timerange');
# geänderten Wert in der Session merken
$session['filter'][$this_table]['timerange'] = $postedTimerange;
}
# Session wieder schreiben
Session::getInstance()->setData($session);

# Ergebnismenge = Array aus Datensatz-IDs vorbereiten
$arrProjectEventIDs = [0];

# hole alle für diese Tabelle/Ansicht gespeicherten Filter
foreach ($session['filter'][$this_table] as $k => $v) {
# jetzt für jeden Filter ein WHERE bilden
switch ($k) {
# wir haben nur einen Filter
case 'timreange':

switch ($v) {
case 0: # hole alle Datensätze
$where = " WHERE id is not NULL";
break;
case 1: # bis heute
$where = " WHERE startDate <= " . time();
break;
case 2: # nur heute
$where = " WHERE startDate = " . time();
break;
case 3: # ab heute
$where = " WHERE startDate >= " . time();
break;
case 4: # nächste Woche
$where = " WHERE startDate >= " . strtotime("monday");
break;
case 5: # 1. Tag nächster Monat 00:00 Uhr - das Doppelte strtotime setzt auf 00:00 Uhr
$where = " WHERE startDate >= " . strtotime(date('d.m.Y',strtotime("first day of next month")));
break;
case 6:
$where = " WHERE startDate >= " . mktime(0, 0, 0, 1, 1, intval(date("Y", strtotime("+1 year"))));
break; # Neujahrstag nächstes Jahr

default:
$where = "";
break;
}

# jetzt die Abfrage ausführen
$dbResult = \Database::getInstance()->prepare("SELECT id FROM mytable $where")->execute();

# alle IDs der Treffer in das Array laden
$arrProjectEventIDs = $dbResult->fetchEach('id');
break;

default:
break;
}
}

# dieses Konstrukt verhindert den Fehler:
# An exception occurred while executing 'SELECT DISTINCT `field` FROM child_table WHERE pid='nn' AND id IN()'
# denn IN() wird durch das Array abgebildet, daher muss das Array mindestens einen Wert enthalten, hier [0]
if (is_array($arrProjectEventIDs) && empty($arrProjectEventIDs)) {
$arrProjectEventIDs = [0];
}

# die IDs setzen, so dass nur diese Datensätze aufgelistet werden
$GLOBALS['TL_DCA'][$this_table]['list']['sorting']['root'] = $arrProjectEventIDs;
}

Viel Spaß!

Antwort von Patrick Froch

Vielen Dank für den Hinweis. Eine sehr interessanter Callback. Ich lasse ihn hier im Kommentar,  so ist auch die Quelle ersichtlich.

Einen Kommentar schreiben

Bitte addieren Sie 2 und 4.