V1 Grid & Field Management — Vollständige Analyse¶
Erstellt: 2026-03-15 | Branch:
claude/analyze-grid-fieldmanagement-NbNVF
Inhaltsverzeichnis¶
- Übersicht
- Datenbank-Struktur
- Field Categories & Types
- Type Interpreter — Rendering-Pipeline
- Default Value System
- Grid Column Rendering (GridColumn.php)
- Form Rendering (ActiveForm.php)
- Zugriffskontrolle & Visibility
- Datenfluss-Diagramm
- 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.php → field_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:
Datum-Arithmetik:
[CURRENT_DATE]+[14D] → Heute + 14 Tage
[CURRENT_DATE]-[2M] → Heute - 2 Monate
[CURRENT_DATE]+[1Y] → Heute + 1 Jahr
Datumskomponenten-Format:
Pipe-Format für Datumsfelder:
Kombinierte Templates:
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
Löst kaskadierende Feld-Referenzen bis max. 5 Ebenen tief auf:
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_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.php → GridColumn::getColumn($name, $table, $idGridView, $params)
6.2 Rendering-Ablauf¶
- Feld-Metadaten laden aus
field_configuration - Sichtbarkeit prüfen: User-Berechtigung für
editauf Tabelle - Spezialfälle behandeln:
- Current-Record-Flags (
C2339,R3246,L2815) - Kunden-Felder (Rendering mit
KTAG,K4602) - Status-Felder (Custom Formatting)
- Category/Type-basiertes Rendering (siehe Entscheidungsbaum oben)
- KTbEditableColumn Config generieren:
type:rawoder Standardvalue: PHP-Expression für aktuelle Zellefilter: Dropdown-Optionen für Spalten-Filtereditable: 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.php → ActiveForm::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¶
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) |