Form System

Keywords: Form Builder Input Field Config Settings Widget Media Linkmap Validation Backend

Übersicht

Form-Builder-System für Backend-Formulare mit Field-Wrappern, Config-Persistierung und Media/Linkmap-Widgets.

Methoden

rex_form_base (Abstract)

Methode Parameter Rückgabe Beschreibung
__construct($fieldset, $name, $method, $debug) string, string, string, bool - Initialisiert Form (default: POST)
addField($tag, $name, $value, $attributes) string, string, mixed, array rex_form_element Generisches Feld hinzufügen
addTextField($name, $value, $attributes) string, mixed, array rex_form_element Text-Input (type=”text”)
addInputField($type, $name, $value, $attributes) string, string, mixed, array rex_form_element Input mit custom type
addHiddenField($name, $value, $attributes) string, mixed, array rex_form_element Hidden-Field
addReadOnlyTextField($name, $value, $attributes) string, mixed, array rex_form_element Readonly Text-Input
addReadOnlyField($name, $value, $attributes) string, mixed, array rex_form_element Paragraph mit Wert
addTextAreaField($name, $value, $attributes) string, mixed, array rex_form_element Textarea (6 rows default)
addSelectField($name, $value, $attributes) string, mixed, array rex_form_select_element Select/Dropdown
addCheckboxField($name, $value, $attributes) string, mixed, array rex_form_checkbox_element Checkbox(en)
addRadioField($name, $value, $attributes) string, mixed, array rex_form_radio_element Radio-Buttons
addMediaField($name, $value, $attributes) string, mixed, array rex_form_widget_media_element Medienpool-Picker (single)
addMedialistField($name, $value, $attributes) string, mixed, array rex_form_widget_medialist_element Medienpool-Liste (multi)
addLinkmapField($name, $value, $attributes) string, mixed, array rex_form_widget_linkmap_element Struktur-Picker (single)
addLinklistField($name, $value, $attributes) string, mixed, array rex_form_widget_linklist_element Struktur-Liste (multi)
addControlField($save, $apply, $delete, $reset, $abort) Element, Element, Element, Element, Element rex_form_control_element Save/Apply/Delete-Buttons
addRawField($html) string rex_form_raw_element Custom HTML einfügen
addFieldset($legend) string void Fieldset-Gruppe hinzufügen
addParam($name, $value) string, string|int|bool void URL-Parameter für Redirects
getParams() - array Alle Form-Params
setUrl($url) string void Form action URL
getUrl() - string URL mit Params
addErrorMessage($code, $message) int, string void Custom Error registrieren
get() - string Rendert komplettes Form-HTML

rex_config_form

Methode Parameter Rückgabe Beschreibung
::factory($namespace, $fieldset) string, string|null rex_config_form Factory mit rex_config-Namespace
getValue($name, $default) string, mixed mixed Liest aus rex_config::get($namespace, $name)
save() - bool Schreibt alle Felder zu rex_config
delete() - bool Löscht Config-Werte

Form Elements

Klasse Beschreibung Verwendung
rex_form_element Basis-Element für Input/Textarea Via addField/addTextField
rex_form_select_element Select-Dropdown mit Options addSelectField()->setSelect()
rex_form_checkbox_element Checkbox(en) mit Optionen addCheckboxField()->addOption()
rex_form_radio_element Radio-Buttons addRadioField()->addOption()
rex_form_prio_element Priority-Sortierung Prio-Feld mit rex_sql_util
rex_form_container_element Container für verschachtelte Felder addContainerField()
rex_form_control_element Save/Apply/Delete-Buttons addControlField()
rex_form_raw_element Raw HTML addRawField(‘<hr>’)
rex_form_widget_media_element Medienpool-Single-Picker addMediaField()
rex_form_widget_medialist_element Medienpool-Multi-Liste addMedialistField()
rex_form_widget_linkmap_element Struktur-Single-Picker addLinkmapField()
rex_form_widget_linklist_element Struktur-Multi-Liste addLinklistField()

Praxisbeispiele

Config-Formular erstellen

// Addon-Settings mit rex_config_form
$form = rex_config_form::factory('myAddon');

// Text-Input
$field = $form->addTextField('api_key');
$field->setLabel('API Key');
$field->setNotice('Hier den API-Schlüssel eintragen');

// Textarea
$field = $form->addTextAreaField('custom_css');
$field->setLabel('Custom CSS');

// Select
$field = $form->addSelectField('environment');
$field->setLabel('Umgebung');
$select = $field->getSelect();
$select->addOption('Development', 'dev');
$select->addOption('Production', 'prod');

// Save-Button wird automatisch hinzugefügt
echo $form->get(); // Rendert komplettes Formular

Werte aus Config abrufen

// rex_config_form getValue nutzt rex_config
$form = rex_config_form::factory('myAddon');

// Liest aus rex_config::get('myAddon', 'api_key')
$apiKey = $form->getValue('api_key', 'default-key');

// Oder direkt:
$apiKey = rex_config::get('myAddon', 'api_key');

Form mit Fieldsets

$form = rex_config_form::factory('myAddon');

// Erstes Fieldset
$form->addFieldset('Allgemeine Einstellungen');
$form->addTextField('site_title');
$form->addTextAreaField('site_description');

// Zweites Fieldset
$form->addFieldset('API-Konfiguration');
$form->addTextField('api_key');
$form->addTextField('api_secret');

// Drittes Fieldset
$form->addFieldset('Design');
$form->addTextAreaField('custom_css');
$form->addCheckboxField('enable_dark_mode');

echo $form->get();

Select mit Optionen

$form = rex_config_form::factory('myAddon');

$field = $form->addSelectField('status');
$field->setLabel('Status');

$select = $field->getSelect();
$select->addOption('Aktiv', 1);
$select->addOption('Inaktiv', 0);
$select->addOption('Wartung', 2);
$select->setSelected(1); // Default-Wert

// Oder aus SQL
$sql = rex_sql::factory();
$select->addDBSqlOptions('SELECT id, name FROM rex_categories ORDER BY name');

echo $form->get();

Checkbox/Radio mit Optionen

$form = rex_config_form::factory('myAddon');

// Checkbox (Mehrfachauswahl)
$field = $form->addCheckboxField('enabled_features');
$field->setLabel('Aktivierte Features');
$field->addOption('Feature A', 'feature_a');
$field->addOption('Feature B', 'feature_b');
$field->addOption('Feature C', 'feature_c');

// Radio (Einzelauswahl)
$field = $form->addRadioField('payment_method');
$field->setLabel('Zahlungsmethode');
$field->addOption('PayPal', 'paypal');
$field->addOption('Kreditkarte', 'creditcard');
$field->addOption('Rechnung', 'invoice');

echo $form->get();

Media-Widget

$form = rex_config_form::factory('myAddon');

// Single Media
$field = $form->addMediaField('logo');
$field->setLabel('Logo');
$field->setNotice('Wählen Sie ein Logo aus dem Medienpool');

// Media-Liste (mehrere Dateien)
$field = $form->addMedialistField('slider_images');
$field->setLabel('Slider-Bilder');
$field->setNotice('Wählen Sie mehrere Bilder für den Slider');

echo $form->get();

Linkmap-Widget (Struktur-Picker)

$form = rex_config_form::factory('myAddon');

// Single Link
$field = $form->addLinkmapField('contact_page');
$field->setLabel('Kontaktseite');

// Link-Liste
$field = $form->addLinklistField('footer_links');
$field->setLabel('Footer-Links');

echo $form->get();

ReadOnly-Felder

$form = rex_config_form::factory('myAddon');

// ReadOnly Text-Input (grau, disabled)
$field = $form->addReadOnlyTextField('installation_date', date('d.m.Y'));
$field->setLabel('Installiert am');

// ReadOnly als Paragraph (nur Anzeige)
$field = $form->addReadOnlyField('version', rex::getVersion());
$field->setLabel('REDAXO Version');

echo $form->get();

Hidden-Fields

$form = rex_config_form::factory('myAddon');

// Hidden für Token/ID
$form->addHiddenField('csrf_token', rex_csrf_token::factory('myAddon')->getToken());
$form->addHiddenField('form_id', 'settings_form');

$form->addTextField('api_key');
$form->addTextField('api_secret');

echo $form->get();

Custom Attributes

$form = rex_config_form::factory('myAddon');

// Input mit Placeholder + Custom Class
$field = $form->addTextField('email', null, [
    'class' => 'form-control custom-input',
    'placeholder' => 'mail@example.com',
    'data-validate' => 'email'
]);
$field->setLabel('E-Mail');

// Number-Input mit Min/Max
$field = $form->addInputField('number', 'max_items', null, [
    'class' => 'form-control',
    'min' => 1,
    'max' => 100,
    'step' => 5
]);
$field->setLabel('Maximale Anzahl');

echo $form->get();

Raw HTML einfügen

$form = rex_config_form::factory('myAddon');

$form->addTextField('api_key');

// Custom HTML zwischen Feldern
$form->addRawField('<hr><p class="alert alert-info">Wichtiger Hinweis...</p>');

$form->addTextField('api_secret');

// Oder komplexe Widgets
$form->addRawField('
    <div class="form-group">
        <label>Custom Widget</label>
        <div id="custom-widget"></div>
        <script>initCustomWidget();</script>
    </div>
');

echo $form->get();

Form URL & Params

$form = rex_config_form::factory('myAddon');

// URL für Form-Action
$form->setUrl('index.php');

// Parameter für Redirects nach Save
$form->addParam('page', 'myAddon/settings');
$form->addParam('subpage', 'advanced');

$form->addTextField('api_key');

echo $form->get();

// Nach Save wird zu index.php?page=myAddon/settings&subpage=advanced redirected

Control-Buttons anpassen

$form = rex_config_form::factory('myAddon');

$form->addTextField('api_key');
$form->addTextAreaField('custom_css');

// Custom Control-Buttons
$form->addControlField(
    $save = new rex_form_element('submit', 'save', 'Speichern'),
    $apply = new rex_form_element('submit', 'apply', 'Übernehmen'),
    $delete = null, // Kein Delete-Button
    $reset = new rex_form_element('reset', 'reset', 'Zurücksetzen'),
    $abort = null
);

echo $form->get();

Validierung & Error-Messages

$form = rex_config_form::factory('myAddon');

// Custom Error-Messages registrieren
$form->addErrorMessage(1, 'API Key darf nicht leer sein');
$form->addErrorMessage(2, 'Ungültiges API Key-Format');

$form->addTextField('api_key');

// Bei save() prüfen
if ($form->save()) {
    echo rex_view::success('Gespeichert');
} else {
    // Fehler anzeigen
    echo rex_view::error('Fehler beim Speichern');
}

Nested/Container-Fields

$form = rex_config_form::factory('myAddon');

// Container für verschachtelte Felder
$container = $form->addContainerField('social_links');
$container->setLabel('Social Media Links');

// Felder im Container
$container->addField('text', 'facebook', null, ['placeholder' => 'Facebook URL']);
$container->addField('text', 'twitter', null, ['placeholder' => 'Twitter URL']);
$container->addField('text', 'instagram', null, ['placeholder' => 'Instagram URL']);

echo $form->get();

Modul-Input mit MForm (ähnliches Konzept)

// In modules/input.php: MForm nutzt ähnliche API
$mform = new MForm();

$mform->addTextField('1.headline', ['label' => 'Überschrift']);
$mform->addTextAreaField('2.text', ['label' => 'Text']);
$mform->addMediaField('3.image', ['label' => 'Bild']);
$mform->addLinkField('4.link', ['label' => 'Link']);

echo $mform->show();

Addon-Settings-Page

// In pages/settings.php
$addon = rex_addon::get('myAddon');
$form = rex_config_form::factory($addon->getName());

// Basis-Einstellungen
$form->addFieldset('Grundeinstellungen');

$field = $form->addTextField('api_key');
$field->setLabel('API Schlüssel');
$field->setAttribute('placeholder', 'Ihr API-Key');

$field = $form->addSelectField('mode');
$field->setLabel('Modus');
$select = $field->getSelect();
$select->addOptions(['Test' => 'test', 'Live' => 'live']);

// Erweiterte Einstellungen
$form->addFieldset('Erweiterte Einstellungen');

$field = $form->addCheckboxField('enable_logging');
$field->addOption('Logging aktivieren', 1);

$field = $form->addTextAreaField('custom_js', null, ['rows' => 10]);
$field->setLabel('Custom JavaScript');

// Fragment-Wrapper für Bootstrap-Layout
$fragment = new rex_fragment();
$fragment->setVar('class', 'edit', false);
$fragment->setVar('title', 'Einstellungen');
$fragment->setVar('body', $form->get(), false);
echo $fragment->parse('core/page/section.php');

Save-Handling überschreiben

// Eigene Config-Form-Klasse
class myAddon_config_form extends rex_config_form
{
    protected function save()
    {
        // Vor dem Speichern validieren
        $apiKey = $this->getValue('api_key');
        if (empty($apiKey)) {
            $this->addErrorMessage(1, 'API Key erforderlich');
            return false;
        }
        
        // API-Key testen
        if (!$this->validateApiKey($apiKey)) {
            $this->addErrorMessage(2, 'API Key ungültig');
            return false;
        }
        
        // Parent save aufrufen
        if (!parent::save()) {
            return false;
        }
        
        // Nach dem Speichern: Cache löschen
        rex_delete_cache();
        
        return true;
    }
    
    private function validateApiKey($key)
    {
        // API-Validierung
        return strlen($key) === 32;
    }
}

// Verwendung
$form = myAddon_config_form::factory('myAddon');

Form in Fragment

$form = rex_config_form::factory('myAddon');
$form->addTextField('setting1');
$form->addTextField('setting2');

// In Bootstrap-Section-Fragment wrappen
$fragment = new rex_fragment();
$fragment->setVar('title', 'Einstellungen');
$fragment->setVar('body', $form->get(), false);
echo $fragment->parse('core/page/section.php');

Conditional Fields (mit JS)

$form = rex_config_form::factory('myAddon');

// Toggle-Field
$field = $form->addCheckboxField('enable_api');
$field->addOption('API aktivieren', 1);
$field->setAttribute('id', 'enable-api-toggle');
$field->setAttribute('onchange', 'toggleApiFields()');

// API-Felder (initial hidden)
$form->addRawField('<div id="api-fields" style="display:none;">');

$field = $form->addTextField('api_key');
$field->setLabel('API Key');

$field = $form->addTextField('api_secret');
$field->setLabel('API Secret');

$form->addRawField('</div>');

// JavaScript
$form->addRawField('<script>
function toggleApiFields() {
    const enabled = document.getElementById("enable-api-toggle").checked;
    document.getElementById("api-fields").style.display = enabled ? "block" : "none";
}
// Initial state
toggleApiFields();
</script>');

echo $form->get();

File-Upload-Field (Custom)

$form = rex_config_form::factory('myAddon');

// Standard Input File
$field = $form->addInputField('file', 'import_file', null, [
    'accept' => '.json,.csv',
    'class' => 'form-control'
]);
$field->setLabel('Datei hochladen');

// Oder mit Media-Widget (empfohlen)
$field = $form->addMediaField('import_file');
$field->setLabel('Datei hochladen');
$field->setNotice('Wählen Sie eine JSON/CSV-Datei aus dem Medienpool');

echo $form->get();

Color-Picker-Field

$form = rex_config_form::factory('myAddon');

$field = $form->addInputField('color', 'primary_color', '#007bff', [
    'class' => 'form-control'
]);
$field->setLabel('Primärfarbe');

$field = $form->addInputField('color', 'secondary_color', '#6c757d', [
    'class' => 'form-control'
]);
$field->setLabel('Sekundärfarbe');

echo $form->get();

Date/Time-Fields

$form = rex_config_form::factory('myAddon');

// Date
$field = $form->addInputField('date', 'event_date', null, [
    'class' => 'form-control'
]);
$field->setLabel('Datum');

// Time
$field = $form->addInputField('time', 'event_time', null, [
    'class' => 'form-control'
]);
$field->setLabel('Uhrzeit');

// Datetime
$field = $form->addInputField('datetime-local', 'event_datetime', null, [
    'class' => 'form-control'
]);
$field->setLabel('Datum & Uhrzeit');

echo $form->get();

Multi-Language Forms

$form = rex_config_form::factory('myAddon');

// Felder pro Sprache
foreach (rex_clang::getAll() as $clang) {
    $form->addFieldset($clang->getName());
    
    $field = $form->addTextField('title_' . $clang->getId());
    $field->setLabel('Titel');
    
    $field = $form->addTextAreaField('description_' . $clang->getId());
    $field->setLabel('Beschreibung');
}

echo $form->get();

Form mit CSRF-Token (automatisch)

$form = rex_config_form::factory('myAddon');

// CSRF-Token wird automatisch von rex_form_base hinzugefügt
// Wird in loadBackendConfig() integriert

$form->addTextField('api_key');

echo $form->get();

// Token-Check erfolgt automatisch bei save()

Delete-Button hinzufügen

$form = rex_config_form::factory('myAddon');

$form->addTextField('api_key');
$form->addTextAreaField('custom_css');

// Control-Field mit Delete
$deleteElement = new rex_form_element('submit', 'delete', 'Alle Einstellungen löschen');
$deleteElement->setAttribute('data-confirm', 'Wirklich alle Einstellungen löschen?');

$form->addControlField(
    null, // Save (null = default Button)
    null, // Apply (null = default Button)
    $deleteElement, // Custom Delete
    null, // Reset
    null  // Abort
);

echo $form->get();

// Im Controller
if (rex_post('delete', 'bool')) {
    rex_config::removeNamespace('myAddon');
    echo rex_view::success('Alle Einstellungen gelöscht');
}

Form-Element manipulieren nach Hinzufügen

$form = rex_config_form::factory('myAddon');

// Element hinzufügen
$field = $form->addTextField('api_key');
$field->setLabel('API Key');
$field->setNotice('32-stelliger Schlüssel');

// Attribute nachträglich setzen
$field->setAttribute('maxlength', 32);
$field->setAttribute('pattern', '[A-Za-z0-9]{32}');
$field->setAttribute('required', 'required');
$field->setAttribute('data-validate', 'api-key');

// CSS-Klassen
$field->setAttribute('class', 'form-control monospace');

echo $form->get();

Prio-Element (Sortierung)

// rex_form_prio_element nutzt rex_sql_util::organizePriorities

class myAddon_form extends rex_form
{
    public function init()
    {
        // Prio-Feld für Sortierung
        $field = $this->addPrioField('prio');
        $field->setLabel('Reihenfolge');
        $field->setLabelField('name'); // Anzeige-Name
        $field->setWhereCondition('category_id = ' . $this->sql->getValue('category_id'));
    }
}

Werte vor Save manipulieren

class myAddon_config_form extends rex_config_form
{
    protected function save()
    {
        // Werte vor Save manipulieren
        $apiKey = $this->getValue('api_key');
        
        // Trimmen
        $apiKey = trim($apiKey);
        
        // Zurückschreiben (über rex_config)
        rex_config::set($this->namespace, 'api_key', $apiKey);
        
        // Parent save überspringen, da wir manuell speichern
        // oder: parent::save() aufrufen
        
        return true;
    }
}

Formular ohne Config-Persistierung

// Eigene Form-Klasse ohne rex_config
class myAddon_import_form extends rex_form_base
{
    public function __construct()
    {
        parent::__construct('Import', 'import-form', 'POST');
        
        // Felder hinzufügen
        $this->addMediaField('import_file');
        $this->addSelectField('format');
        
        $this->addControlField();
    }
    
    protected function save()
    {
        // Custom Save-Logik (z.B. Datei-Import)
        $file = $this->getValue('import_file');
        $format = $this->getValue('format');
        
        // Import durchführen
        // ...
        
        return true;
    }
}

// Verwendung
$form = new myAddon_import_form();
if ($form->save()) {
    echo rex_view::success('Import erfolgreich');
}
echo $form->get();