Frontend-CRUD für REDAXO YForm Tabellen mit flexiblen CSS-Frameworks
Die YFormDataListRenderer
-Class in den Lib-Ordner des Projekt-AddOns kopieren und bei Bedarf gestalterisch anpassen.
Die YFormDataListRenderer
-Class ist ein flexibles Tool, um Datensätze aus Tabellen, die mit YForm in REDAXO verwaltet werden, anzuzeigen und zu verwalten. Diese Class eignet sich für eine Vielzahl von Anwendungsfällen, wie z. B. Blog-Artikel, News-Einträge, Produkte oder andere Datentypen.
NEU: Fragment/Template-System für CSS-Frameworks Die Class unterstützt jetzt verschiedene CSS-Frameworks über ein flexibles Fragment-System:
- UIKit (Standard)
- Bootstrap 3
- Bootstrap 4
- Bootstrap 5
- Custom CSS (eigene Framework-Definition)
Zusätzlich können verschiedene Anzeigemodi verwendet werden:
- Table (Tabellenansicht)
- Cards (Kartenansicht)
- List (Listenansicht)
// UIKit (Standard)
$renderer->setFramework('uikit');
// Bootstrap 5
$renderer->setFramework('bootstrap5');
// Bootstrap 4
$renderer->setFramework('bootstrap4');
// Bootstrap 3
$renderer->setFramework('bootstrap3');
// Custom CSS
$renderer->setFramework('custom');
// Tabellenansicht (Standard)
$renderer->setDisplayMode('table');
// Kartenansicht
$renderer->setDisplayMode('cards');
// Listenansicht
$renderer->setDisplayMode('list');
// Aktionen anzeigen (Standard)
$renderer->setShowActions(true);
// Aktionen ausblenden (nur Anzeige, keine Bearbeitung)
$renderer->setShowActions(false);
// Einzelne CSS-Klasse überschreiben
$renderer->setCssClass('bootstrap5', 'button_primary', 'btn btn-success btn-lg');
// Komplettes CSS-Template definieren
$customTemplate = [
'alert_success' => 'message success',
'button_primary' => 'button primary large',
'table' => 'data-table zebra hoverable',
// ... weitere Definitionen
];
$renderer->setCssTemplate('myframework', $customTemplate);
Erstellen Sie eine Instanz der YFormDataListRenderer
-Class:
$renderer = new YFormDataListRenderer();
Legen Sie die Tabelle fest, aus der die Datensätze abgerufen werden sollen. Zum Beispiel:
$renderer->setTableName('rex_blog_articles');
Bestimmen Sie die Felder, die in der Liste angezeigt werden sollen:
$renderer->setFields(['title', 'date', 'status', 'author']);
Definieren Sie das URL-Muster für den Bearbeitungslink. {id}
ist dabei der Platzhalter für die Datensatz-ID:
$renderer->setEditLinkPattern(rex_getUrl('', '', ['func' => 'edit', 'id' => '{id}']));
Legen Sie das Standardfeld und die Standardreihenfolge für die Sortierung fest:
$renderer->setDefaultSortField('date');
$renderer->setDefaultSortOrder('DESC');
Fügen Sie Bedingungen für die Auswahl der Datensätze hinzu. Zum Beispiel:
$renderer->addWhereCondition('status', '=', 1);
Definieren Sie Übersetzungen für bestimmte Feldwerte:
$renderer->setTranslations([
'status' => [
'1' => '<span style="color: green; font-weight: bold;">Online</span>',
'0' => '<span style="color: red;">Offline</span>',
]
]);
Legen Sie fest, welcher Status beim Erstellen oder Bearbeiten von Datensätzen gesetzt werden soll:
$renderer->setNewStatus(0); // Neuer Datensatz ist standardmäßig "Offline"
$renderer->setEditStatus(1); // Bearbeiteter Datensatz wird auf "Online" gesetzt
Speichern Sie den aktuellen Benutzer als Autor:
$renderer->setUserField('author');
Legen Sie ein benutzerdefiniertes YForm-Template fest:
$renderer->setFormYtemplate('custom_template');
Fügen Sie Formatierungs-Callbacks für bestimmte Felder hinzu:
$renderer->setFormatCallback('title', function($value) {
return '<strong>' . htmlspecialchars($value) . '</strong>';
});
$renderer->setFormatCallback('date', function($value) {
return date('d.m.Y', strtotime($value));
});
Falls nötig, können Sie ein Identifikationsfeld und dessen Wert setzen:
$renderer->setIdentId('user_id', rex_ycom_auth::getUser()->getId());
user_id ist nur ein Beispiel es kann jedes Feld genommen werden das ein Int annimmt. Hier wird die ycom user id gespeichert (ideal für eine Relation) um den Ersteller zu tracken.
Zum Schluss rendern Sie die Liste und geben sie aus:
if (rex::isFrontend() && rex_ycom_auth::getUser() !== null) {
echo $renderer->render();
}
Hier ein vollständiger Beispielcode, der alle oben genannten Methoden verwendet:
<?php
$renderer = new YFormDataListRenderer();
// Tabelle festlegen
$renderer->setTableName('rex_blog_articles');
// Felder definieren
$renderer->setFields(['title', 'date', 'status', 'author']);
// Bearbeitungslink-Muster festlegen
$renderer->setEditLinkPattern(rex_getUrl('', '', ['func' => 'edit', 'id' => '{id}']));
// Standard-Sortieroptionen festlegen
$renderer->setDefaultSortField('date');
$renderer->setDefaultSortOrder('DESC');
// Bedingungen für die Datenauswahl hinzufügen
$renderer->addWhereCondition('status', '=', 1);
// NEU: Framework konfigurieren (Bootstrap 5 statt UIKit)
$renderer->setFramework('bootstrap5');
// NEU: Anzeigemodus auf Karten setzen
$renderer->setDisplayMode('cards');
// Übersetzungen einrichten
$renderer->setTranslations([
'status' => [
'1' => '<span style="color: green; font-weight: bold;">Online</span>',
'0' => '<span style="color: red;">Offline</span>',
]
]);
// Standardstatus für neue und bearbeitete Datensätze festlegen
$renderer->setNewStatus(0);
$renderer->setEditStatus(1);
// Benutzerfeld festlegen (optional)
$renderer->setUserField('author');
// Optional: Formulartemplate anpassen
// $renderer->setFormYtemplate('custom_template');
// Callbacks für die Formatierung
$renderer->setFormatCallback('title', function($value) {
return '<strong>' . htmlspecialchars($value) . '</strong>';
});
$renderer->setFormatCallback('date', function($value) {
return date('d.m.Y', strtotime($value));
});
// Identifikationsfeld festlegen (optional), bitte achte darauf dass das Feld exitiert
$renderer->setIdentId('user_id', rex_ycom_auth::getUser()->getId());
// Liste rendern und ausgeben
if (rex::isFrontend() && rex_ycom_auth::getUser() !== null) {
echo $renderer->render();
}
?>
$renderer = new YFormDataListRenderer();
$renderer->setTableName('rex_products');
$renderer->setFields(['name', 'price', 'category']);
$renderer->setFramework('bootstrap5');
$renderer->setDisplayMode('cards');
echo $renderer->render();
$renderer = new YFormDataListRenderer();
$renderer->setTableName('rex_news');
$renderer->setFields(['title', 'teaser', 'createdate']);
$renderer->setFramework('bootstrap4');
$renderer->setCssClass('bootstrap4', 'button_primary', 'btn btn-success btn-lg');
$renderer->setCssClass('bootstrap4', 'table', 'table table-dark table-striped');
echo $renderer->render();
$renderer = new YFormDataListRenderer();
$renderer->setTableName('rex_events');
$renderer->setFields(['title', 'date', 'location']);
$renderer->setFramework('bootstrap5');
$renderer->setDisplayMode('list');
$renderer->setShowActions(false); // Keine Bearbeiten/Löschen-Buttons
echo $renderer->render();
$renderer = new YFormDataListRenderer();
$renderer->setTableName('rex_gallery');
$renderer->setFields(['title', 'image', 'description']);
$renderer->setFramework('custom');
// Eigene CSS-Klassen definieren
$customTemplate = [
'alert_success' => 'message success',
'alert_danger' => 'message error',
'button_primary' => 'button primary large',
'button_default' => 'button secondary',
'table' => 'data-table zebra hoverable',
'input' => 'form-field',
// ... weitere CSS-Definitionen
];
$renderer->setCssTemplate('custom', $customTemplate);
echo $renderer->render();
Um die Benutzerfreundlichkeit zu verbessern, können Sie optional JavaScript für Funktionen wie die Live-Suche oder einen Countdown-Timer hinzufügen.
document.addEventListener("DOMContentLoaded", function() {
var liveSearchElement = document.getElementById("live-search");
if (liveSearchElement) {
liveSearchElement.addEventListener("keyup", function() {
var searchValue = this.value.toLowerCase();
var tableRows = document.getElementById("data-table").getElementsByTagName("tr");
for (var i = 0; i < tableRows.length; i++) {
var rowText = tableRows[i].textContent.toLowerCase();
if (rowText.indexOf(searchValue) > -1) {
tableRows[i].style.display = "";
} else {
tableRows[i].style.display = "none";
}
}
});
}
var countdownElement = document.getElementById("countdown");
if (countdownElement) {
var countdown = parseInt(countdownElement.textContent, 10);
var countdownInterval = setInterval(function() {
countdown--;
countdownElement.textContent = countdown;
if (countdown <= 0) {
clearInterval(countdownInterval);
window.location.href = window.location.pathname;
}
}, 1000);
}
});