Skip to content

V1 Grid & Field Management — Vollständige Analyse

Erstellt: 2026-03-15 | Branch: claude/analyze-grid-fieldmanagement-NbNVF

Inhaltsverzeichnis

  1. Übersicht
  2. Datenbank-Struktur
  3. Field Categories & Types
  4. Type Interpreter — Rendering-Pipeline
  5. Default Value System
  6. Grid Column Rendering (GridColumn.php)
  7. Form Rendering (ActiveForm.php)
  8. Zugriffskontrolle & Visibility
  9. Datenfluss-Diagramm
  10. Key Files Referenz

1. Übersicht

Das V1-Feldsystem ist ein konfigurationsgetriebenes Metadaten-Framework, das bestimmt: - Welche Felder in Grid/Edit/View/Mobile angezeigt werden - Wie Felder gerendert werden (Widget-Typ, Filter, Editable-Config) - Welche Defaultwerte bei Neuerstellung gesetzt werden - Welche Felder je nach Kategorie/Status überschrieben werden

Kern-Architektur:

field_configuration (Basis-Metadaten)
  └─→ additional_field (Overrides per Category/Status)
  └─→ AdminUserRolesField (Zugriffsbeschränkungen per Rolle)

InventoryHelper::getTableFields()  → Feld-Laden
GridColumn::getColumn()            → Grid-Rendering
ActiveForm::getFormField()         → Form-Rendering
InventoryHelper::setDefaultValue() → Default-Wert-Anwendung


2. Datenbank-Struktur

2.1 field_configuration Tabelle

Spalte Typ Zweck
column_name VARCHAR(50) Feldname (z.B. I4201, C2303, K4601)
table_name VARCHAR(50) Tabellenname (inventory, customers, calibration, etc.)
field_type VARCHAR(50) Display-Typ: Date, DateTime, TextArea, YesNo, Text-1..Text-254, Decimal, Integers, AverageValue, Parameter, Tags, DataTags, Link, Star, HtmlEditor, CounterField, Time
field_category VARCHAR(500) Verhaltenskategorie: Select Field Type, RequiredDatabase, RequiredList, PickDatabase, PickList, StatusDatabase
field_options VARCHAR(500) Konfiguration: Dropdown-Werte, Datenbank-Links, etc.
default_value VARCHAR(255) Standardwert (statisch oder Template mit Variablen)
edit_visible TINYINT(1) In Edit-Formularen anzeigen
edit_mandatory TINYINT(1) Pflichtfeld beim Bearbeiten
view_visible TINYINT(1) In Detailansicht anzeigen
small_view_visible TINYINT(1) In QR-Code/Mobile-Ansicht anzeigen
grid_available TINYINT(1) Für Grid-Spalten verfügbar
grid_show_default TINYINT(1) Standardmäßig im Grid anzeigen
display_order INT Reihenfolge in Formularen
display_order_grid INT Reihenfolge im Grid
audit TINYINT(1) Änderungen im Audit-Log tracken
security_message TINYINT(1) Sicherheitswarnung bei Bearbeitung
allow_copy TINYINT(1) Wert beim Duplizieren kopieren
link_table_note VARCHAR(255) Notiz für verknüpfte Datenbankfelder
is_user_defined TINYINT(1) Benutzerdefiniertes Feld

2.2 additional_field Tabelle (Category/Status-Overrides)

Spalte Typ Zweck
column_name VARCHAR(50) Feldname
table_name VARCHAR(50) Tabellenname
type VARCHAR(20) 'category' oder 'status'
object_uID VARCHAR(50) UUID der Kategorie/des Status
default_value VARCHAR(255) Überschriebener Defaultwert
edit_visible TINYINT(1) Überschriebene Sichtbarkeit
edit_mandatory TINYINT(1) Überschriebene Pflichtfeld-Eigenschaft
view_visible TINYINT(1) Überschriebene View-Sichtbarkeit
display_order INT Überschriebene Reihenfolge

Override-Hierarchie:

field_configuration.default_value (Basis)
  → additional_field (type='category')  (Category-Override)
    → additional_field (type='status')  (Status-Override, höchste Priorität)


3. Field Categories & Types

3.1 Sechs Field Categories

Kategorie Bedeutung field_options-Format
Select Field Type Standard-Typen, Rendering durch field_type bestimmt Dropdown: 0:N#1:Y#2:Maybe
RequiredDatabase Pflichtfeld, verknüpft mit anderer Tabelle TABLE=customers\|FIELD=K4602
RequiredList Pflichtfeld, feste Optionsliste Option1#Option2#Option3
PickDatabase Optional, verknüpft mit anderer Tabelle TABLE=types\|FIELD=T4101
PickList Optional, feste Optionsliste value1:label1#value2:label2
StatusDatabase Status-Feld mit spezieller Formatierung Lowercase Status-Typ-Name

3.2 Alle 31 Field Types

Text-1, Text-3, Text-8, Text-16, Text-20, Text-32, Text-44, Text-48, Text-55, Text-64,
Text-80, Text-128, Text-254, TextArea, YesNo, Tags, DataTags, Parameter, CounterField,
HtmlEditor, Decimal, Date, DateLast, DateNext, Time, DateTime, Integers,
AverageValue, Link, Star

3.3 Spezielle field_options Keywords

Keyword Auflösung
SI(Symbol) Physikalische SI-Präfixe
UNIT(Symbol) Physikalische Einheiten
Support(Type) Support-Ticket-Typen
Support(Risk1) Ticket-Versionen
Support(Risk2) Milestones
Support(Risk3) Risk3-Werte
Support(Priority) Ticket-Prioritäten
Support(Category) Ticket-Kategorien

4. Type Interpreter — Rendering-Pipeline

4.1 Komplettes Type→Rendering Mapping

Field Type Grid Editable Grid Filter Form Widget Speicherformat
Text-* text Text-Input textFieldGroup (maxlength=N) String (max N Zeichen)
TextArea textarea Text-Input textAreaGroup (rows=3) Multiline String
Date date datepicker datePickerGroup Y-m-d
DateLast date dateRangeFilterLast datePickerGroup Y-m-d
DateNext date dateRangeFilterNext datePickerGroup Y-m-d
DateTime datetime dateTimePickerGroup Y-m-d H:i:s
Time time timePickerGroup H:i:s
YesNo select (0/1) Dropdown (Yes/No) dropDownListGroup 0 oder 1
Tags select2 (multiple) KTbSelect2 (multiple) CSV (Komma-separiert)
DataTags select2 (multiple) KTbSelect2 (multiple) CSV (Komma-separiert)
Parameter custom (additionalType: 'parameter') Custom
AverageValue custom (additionalType: 'average') averageField
Link text Text URL String
Star select (0/1) Dropdown (Yes/No) 0 oder 1
HtmlEditor CKEditor / Markdown Editor HTML/Markdown String
Integers text Text-Input numberFieldGroup (type=number) Numeric String
Decimal text Text-Input numberFieldGroup (type=number) Numeric String
CounterField text Auto-Nummer

4.2 Category→Rendering Mapping

Category Editable Type Datenschwelle UI-Verhalten
RequiredList select Dropdown, keine Leer-Option
PickList select Dropdown, mit Leer-Option
RequiredDatabase select (≤10) / typeaheadjs (>10) 10 Einträge Remote AJAX wenn >10
PickDatabase select (≤10) / typeaheadjs (>10) 10 Einträge Remote AJAX wenn >10, mit Leer-Option
StatusDatabase select Custom statusFormat() JS mit Farben

4.3 Rendering-Entscheidungsbaum (GridColumn::getColumn)

field_category == 'Select Field Type'?
├── YES → Branch auf field_type:
│   ├── Date/DateLast/DateNext → KTbEditableColumn, type='date', datepicker
│   ├── DateTime → KTbEditableColumn, type='datetime'
│   ├── TextArea → KTbEditableColumn, type='textarea'
│   ├── YesNo → KTbEditableColumn, type='select', getFlagSource()
│   ├── AverageValue → KTbEditableColumn, additionalType='average'
│   ├── Parameter → KTbEditableColumn, additionalType='parameter'
│   ├── Tags/DataTags → KTbEditableColumn, type='select2', multiple=true
│   ├── Link → KTbEditableColumn oder getStretchedLink()
│   ├── Star → KTbEditableColumn, type='select', getStarIcon()
│   ├── field_options vorhanden → KTbEditableColumn, type='select' (Dropdown)
│   └── Default → KTbEditableColumn, type='text'
├── field_category == 'StatusDatabase'?
│   └── YES → KTbEditableColumn, type='select', statusFormat() JS
├── field_category in ['RequiredList', 'PickList']?
│   └── YES → KTbEditableColumn, type='select', field_options parsen
└── field_category in ['RequiredDatabase', 'PickDatabase']?
    └── YES → getPickDatabaseOptions()
        ├── >10 Einträge → type='typeaheadjs' (Remote AJAX)
        └── ≤10 Einträge → type='select' (Local)

4.4 field_options Parsing

Dropdown-Format (# als Separator):

value1#value2#value3              → Einfache Liste
value1:label1#value2:label2       → Key:Value Paare
0:N#1:Y                           → Boolean (N→No, Y→Yes automatisch übersetzt)

Database-Link-Format:

TABLE=customers|FIELD=K4602       → Werte aus customers.K4602
TABLE=types|FIELD=T4101           → Werte aus types.T4101
FIELD=column_name                 → Werte aus gleichem Feld der Tabelle
[I4201]                           → Feld-Referenz
Inventory(I4201)                  → Table(Field) Syntax


5. Default Value System

5.1 Verfügbare Platzhalter

Definiert in config/constants.phpfield_configuration_default_value:

Platzhalter Auflösung Beispiel
[CURRENT_DATE] Aktuelles Datum 2026-03-15
[CURRENT_TIME] Aktuelle Uhrzeit 14:30:00
[CURRENT_DATETIME] Datum+Uhrzeit 2026-03-15 14:30:00
[CURRENT_USER] Angemeldeter Benutzer Vollname oder User-ID (für Location-Tabellen)
[STATUS_NAME] Status-Titel Active
[STATUS_SHORT] Status-Kürzel ACT
[STATUS_COUNT] Status-Zähler (+1) 42
[CATEGORY_NAME] Kategorie-Name Oscilloscope
[CATEGORY_SHORT] Kategorie-Kürzel OSC
[CATEGORY_COUNT] Kategorie-Zähler (+1) 17
[DUE_DATE] Fälligkeitsdatum
[GLOBAL_COUNTER_1] Globaler Zähler 1 (+1) 1001
[GLOBAL_COUNTER_2] Globaler Zähler 2 (+1) 2001
[YYYY], [MM], [DD] Datumskomponenten 2026, 03, 15
[LASTMONTH_STARTDAY] Erster Tag Vormonat 2026-02-01
[LASTMONTH_ENDDAY] Letzter Tag Vormonat 2026-02-28
[CURRENTMONTH_STARTDAY] Erster Tag akt. Monat 2026-03-01
[CURRENTMONTH_ENDDAY] Letzter Tag akt. Monat 2026-03-31
[CURRENTYEAR_STARTDAY] Erster Tag akt. Jahr 2026-01-01
[CURRENTYEAR_ENDDAY] Letzter Tag akt. Jahr 2026-12-31

5.2 Erweiterte Default-Value-Syntax

Feld-Referenzen:

[I4201]                → Wert aus Feld I4201 der gleichen Tabelle
[C2301]                → Wert aus Kalibrierungsfeld C2301

Datum-Arithmetik:

[CURRENT_DATE]+[14D]   → Heute + 14 Tage
[CURRENT_DATE]-[2M]    → Heute - 2 Monate
[CURRENT_DATE]+[1Y]    → Heute + 1 Jahr

Datumskomponenten-Format:

[YYYY]-[MM]-[DD+14]    → 2026-03-29
[DD+5].[MM+1].[YYYY]   → 20.04.2026

Pipe-Format für Datumsfelder:

[I4201|YYYY-MM-DD]     → Wert aus I4201, formatiert als Datum

Kombinierte Templates:

[CATEGORY_SHORT]-[STATUS_COUNT]    → OSC-42
[YYYY][MM]-[GLOBAL_COUNTER_1]      → 202603-1001

5.3 Parsing-Engine (InventoryHelper::getDefaultValueFromString)

Datei: InventoryHelper.php, Zeilen 1401-1579

Algorithmus: 1. Tokenisierung: preg_split('/([\[\]]+)/', $defaultValue) → Tokens zwischen [ und ] 2. Für jeden Token: - Pipe-Datum (I4201|YYYY-MM-DD): Feld-Wert mit Datumsformat - Sonderzeichen (-, /, .): Direkt anhängen - Datumsformat (YYYY, MM, DD): PHP date() Konvertierung - Bekannte Konstante (CURRENT_USER, etc.): Über getDefinedValueByUser() auflösen - Feld-Referenz (I4201): Wert aus Attributen oder rekursiv auflösen - Numerisch: Direkt anhängen - Sonst: Über getDefaultValueRelation() als DB-Relation versuchen

5.4 Rekursive Auflösung

Datei: AdminFieldConfiguration.php, Zeilen 1534-1560

public static function resolveDefaultValue($defaultValue, $tableName, $attributes, $level = 1)

Löst kaskadierende Feld-Referenzen bis max. 5 Ebenen tief auf:

[FIELD_A] → [FIELD_B] → [FIELD_C] → "actual value"

5.5 Anwendung bei Record-Erstellung (setDefaultValue)

Datei: InventoryHelper.php, Zeilen 2465-2701

Ablauf: 1. Lade alle field_configuration Einträge für die Tabelle 2. Lade additional_field Overrides für aktuelle Kategorie/Status 3. Für jedes Feld mit default_value: - Prüfe ob Feld leer ist (is_empty($model->{$columnName})) - Prüfe Rollenbeschränkungen (AdminUserRolesField::getLimitColumnNames) - Prüfe Ignore-Liste - Wenn Template mit [...]: Volle Parsing-Engine aufrufen - Wenn einfache Konstante: getDefinedValueByUser() aufrufen - Wenn leer aber RequiredList: Erste Option als Default 4. Nachbearbeitung: Verbliebene [FIELD]-Referenzen rekursiv auflösen

5.6 Counter-Felder (CounterField)

Erkennung:

$field->field_type == 'CounterField' || hasCounterVariable($field->default_value)

field_options für Counter-Felder:

STATUS_NAME=Active       → Counter nur wenn Status = "Active"
STATUS_SHORT=ACT         → Counter nur wenn Status-Kürzel = "ACT"
CATEGORY_NAME=Scope      → Counter nur wenn Kategorie = "Scope"
CATEGORY_SHORT=SCP       → Counter nur wenn Kategorie-Kürzel = "SCP"

Zähler-Logik: - [STATUS_COUNT] → Bisheriger Status-Zähler + 1 - [CATEGORY_COUNT] → Bisheriger Kategorie-Zähler + 1 - [GLOBAL_COUNTER_1] / [GLOBAL_COUNTER_2] → Gespeichert in FrontendProperty, inkrementiert bei Verwendung


6. Grid Column Rendering

6.1 Einstiegspunkt

Datei: GridColumn.phpGridColumn::getColumn($name, $table, $idGridView, $params)

6.2 Rendering-Ablauf

  1. Feld-Metadaten laden aus field_configuration
  2. Sichtbarkeit prüfen: User-Berechtigung für edit auf Tabelle
  3. Spezialfälle behandeln:
  4. Current-Record-Flags (C2339, R3246, L2815)
  5. Kunden-Felder (Rendering mit KTAG, K4602)
  6. Status-Felder (Custom Formatting)
  7. Category/Type-basiertes Rendering (siehe Entscheidungsbaum oben)
  8. KTbEditableColumn Config generieren:
  9. type: raw oder Standard
  10. value: PHP-Expression für aktuelle Zelle
  11. filter: Dropdown-Optionen für Spalten-Filter
  12. editable: Inline-Editing-Konfiguration (type, url, placement, success callback)

6.3 Editable-Column Standard-Struktur

array(
    'class' => 'KTbEditableColumn',
    'header' => $header,
    'headerHtmlOptions' => $headerHtmlOptions,
    'htmlOptions' => $htmlOptions,
    'name' => $name,
    'type' => 'raw',
    'value' => '$data->getAttribute("' . $name . '")',
    'filter' => $filterEditable,
    'editable' => array(
        'type' => 'text',             // text|textarea|date|datetime|select|select2|typeaheadjs
        'htmlOptions' => array(),
        'emptytext' => 'Empty',
        'url' => $url,                // AJAX-Endpoint zum Speichern
        'placement' => 'top',
        'success' => 'js: function(response, newValue) { ... }'
    )
)

6.4 getDefaultColumn (Fallback)

Datei: GridColumn.php, Zeilen 10394-10489

Generiert eine Standard-Spalte ohne Editable:

array(
    'name' => $name,
    'type' => 'raw',
    'value' => '!is_empty($data->getAttribute("...")) ? $data->getAttribute("...") : "<span class=\"empty-text\">Empty</span>"',
    'visible' => true,
    'filter' => null
)


7. Form Rendering

7.1 Einstiegspunkt

Datei: ActiveForm.phpActiveForm::getFormField($model, $name, $field, $options)

7.2 Widget-Zuordnung

Field Type Widget-Methode Besonderheiten
Text-* textFieldGroup() maxlength=N, size=min(N,20)
TextArea textAreaGroup() rows=3, class=resize-vertical
Date* datePickerGroup() Format: yyyy-mm-dd, Calendar-Icon
DateTime dateTimePickerGroup() Format: yyyy-mm-dd hh:ii:ss
Time timePickerGroup() 24h, mit Sekunden
YesNo dropDownListGroup() getFlagSource()
Tags/DataTags KTbSelect2 Widget multiple=true, tokenSeparators: ,
AverageValue averageField() data-toggle=average
HtmlEditor ckEditorGroup() / markdownEditorGroup() Je nach $model->useMarkdown
Integers/Decimal numberFieldGroup() HTML5 <input type="number">

8. Zugriffskontrolle & Visibility

8.1 Sichtbarkeits-Modi

Modus Bedingung Verwendung
'edit' edit_visible = 1 Edit-Formulare
'view' view_visible = 1 Detail-Ansicht
'edit_view' edit_visible = 1 OR view_visible = 1 Beides
'available' grid_available = 1 Verfügbar für Grid
'show_default' grid_show_default = 1 Standard-Grid-Spalten
'edit_mandatory' edit_mandatory = 1 Pflichtfelder

8.2 Rollen-basierte Einschränkungen

AdminUserRolesField::getLimitColumnNames($table, $mode)

Liefert Liste von Feldern, die für die aktuelle Benutzerrolle nicht zugänglich sind. Wird in drei Kontexten verwendet: - Grid-Rendering: Spalten werden ausgeblendet - Edit-Formulare: Felder werden ausgeblendet - Default-Value-Anwendung: Felder werden übersprungen

8.3 Additional Field Override-Logik

// InventoryHelper.php, Zeilen 695-707
foreach ($fields as $field) {
    foreach ($additional_fields as $additional_field) {
        if ($field->column_name == $additional_field->column_name) {
            $field->default_value  = $additional_field->default_value;
            $field->edit_visible   = $additional_field->edit_visible;
            $field->edit_mandatory = $additional_field->edit_mandatory;
            $field->view_visible   = $additional_field->view_visible;
        }
    }
}

9. Datenfluss-Diagramm

┌─────────────────────────────────────────────────────────────────┐
│  Database Tables (inventory, customers, calibration, etc.)      │
└───────────┬─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│  field_configuration (Basis-Metadaten per table_name)           │
│  ├── column_name, field_type, field_category, field_options     │
│  ├── edit_visible, view_visible, grid_available, etc.           │
│  └── default_value (Template mit Variablen)                     │
└───────────┬─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│  additional_field (Overrides per Category/Status)               │
│  ├── type = 'category' → Override per Kategorie                 │
│  └── type = 'status'   → Override per Status (höchste Prio)     │
└───────────┬─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│  InventoryHelper::getTableFields($table, $mode)                 │
│  ├── Filtert nach Modus (edit/view/available/show_default)      │
│  ├── Merged additional_field Overrides                          │
│  └── Entfernt rollenbasiert eingeschränkte Felder               │
└───────────┬──────────────────────┬──────────────────────────────┘
            │                      │
     ┌──────▼──────┐        ┌─────▼──────┐
     │ Grid-Ansicht│        │ Edit-Form  │
     └──────┬──────┘        └─────┬──────┘
            │                      │
            ▼                      ▼
┌───────────────────┐  ┌────────────────────┐
│ GridColumn::       │  │ ActiveForm::       │
│ getColumn()        │  │ getFormField()     │
│ ├── field_category │  │ ├── field_type     │
│ ├── field_type     │  │ ├── Widget-Typ     │
│ ├── Editable-Conf  │  │ └── Validation     │
│ └── Filter-Conf    │  └────────────────────┘
└───────────────────┘
┌───────────────────────────────────────────────────────────────┐
│  Record-Erstellung: InventoryHelper::setDefaultValue()        │
│  ├── field_configuration.default_value laden                  │
│  ├── additional_field Overrides anwenden                      │
│  ├── Template-Parsing ([CURRENT_USER], [I4201], etc.)         │
│  ├── Rekursive Feld-Referenz-Auflösung (max 5 Ebenen)        │
│  ├── Counter-Felder (STATUS_COUNT, CATEGORY_COUNT, GLOBAL)    │
│  └── RequiredList Fallback (erste Option)                     │
└───────────────────────────────────────────────────────────────┘

10. Key Files Referenz

Datei Zweck Wichtige Zeilen
config/constants.php Platzhalter-Definitionen, Typ-Listen field_configuration_default_value, field_configuration_date_value
modules/adminpanel/models/AdminFieldConfiguration.php Field-Config Model, Konstanten, resolveDefaultValue L27-48 (Konstanten), L432-435 (isCounterField), L1129-1137 (getListDefaultValue), L1534-1560 (resolveDefaultValue)
modules/frontend/models/FrontendAdditionalField.php Category/Status Overrides L1-65 (Model), L109-264 (searchField, getAdditionalFieldCondition)
modules/frontend/components/InventoryHelper.php Feld-Laden, Default-Value-Engine L65-70 (selectFields), L479-519 (getTableFields), L695-707 (Override-Merge), L1026-1072 (getDefaultValuesFromSyntax), L1083-1106 (getDefaultValue), L1401-1579 (getDefaultValueFromString), L1837-1988 (getDefinedValueByUser), L2280-2377 (getAdditionalDefaultValues), L2465-2701 (setDefaultValue)
modules/frontend/components/GridColumn.php Grid-Rendering L9396 (CURRENT_USER check), L9400-9468 (Link/Star), L9681-9691 (field_options parse), L9703-9941 (Type-Rendering), L10084-10127 (StatusDatabase), L10129-10192 (RequiredList/PickList), L10195-10354 (Database-Categories), L10394-10489 (getDefaultColumn)
modules/frontend/components/ActiveForm.php Form-Rendering L1373-1458 (Date), L1462-1519 (DateTime/Time), L1522-1555 (Average/Counter), L1558-1670 (Tags/YesNo), L1788-1891 (Text/Number/HtmlEditor)
modules/adminpanel/controllers/AdminFieldConfigurationController.php Field-Config Management UI L80-144 (SQL-Init aus Schema)
modules/frontend/controllers/FrontendCalibrationController.php Default-Value AJAX-Endpoints L3060-3125 (getDefaultValues), L4433-4505 (getDefaultValuesFromStatus/Category)