dbxapp Knowledge dbxDB, DD & FD

dbxDB, DD & FD

On this page
  1. Understand the data flow at a glance
  2. Classification in the Golden Path
  3. Interaction
  4. dbxDB and dbxDD as stable facades
  5. A complete DD
  6. FD: a form view of the DD
  7. Read dbxDB
  8. Write dbxDB
  9. Tree data
  10. Read the DD model
  11. Syncing DD and Database
  12. Database systems
  13. Central query performance
  14. Binding rules
  15. Real references

dbxDB, DD and FD form the database of dbxapp. Technical code does not work directly with PDO and normally does not know a physical table name. He uses a DD reference such as dbxWorkflow|workflowDefinition.

Understand the data flow at a glance

Before DD synchronization

The DD defines the intended state; fields or indexes may still be missing from the physical table.

After controlled synchronization

dbxDD displayed and applied the confirmed differences. Domain access still goes through dbxDB.

Classification in the Golden Path

Mandatory module manual shows the same data pipeline in a complete module. This chapter is the in-depth reference for queries, writing, DD/FD and schema matching.

Interaction

Building block Responsibility Typical location
dbxDB Reading, Writing, Rights, Owner Filter, Trace and DB Abstraction dbx/include/dbxDB.class.php
dbxDD Read DD model and synchronize DD and physical DB dbx/include/dbxDD.class.php
DD Table, fields, indices, rights, defaults, validation dbx/modules/{modul}/dd/*.dd.php
FD Form view on DD fields: Order, template, label, options dbx/modules/{modul}/fd/*.fd.php
Modulcode -> DD-Referenz -> dbxDB -> konfigurierter Server -> physische Tabelle
-> dbxForm -> FD/DD -> Eingabe und Validierung
-> dbxDD -> Schema-Vergleich und Synchronisation

An explicit reference consists of module and DD name:

$dd = 'dbxWorkflow|workflowDefinition';

Without a module prefix, dbxapp searches first in the active module and then in the core module dbx. In reusable technical code, the explicit reference is usually more understandable and prevents name collisions.

dbxDB and dbxDD as stable facades

dbxDB is great because connection, DD resolution, rights, owner filter, transactions, trace, error and DB abstraction must work the same in each module. dbxDD This facade is extended by schema, backup, restore and transfer processes.

Classes are not divided by number of lines. An internal extraction is only useful if an independent responsibility is proven with tests and compatible public API. Domain modules continue to use dbxDB/dbxDD as the only entry and know no internal helpers.

A complete DD

The following pattern corresponds to the DD format exported by dbxapp. Table, fields and indexes are directly in the sections TABLE, FIELDS and INDEXES. Each field is fully visible and is subsequently $fields[] = $field attached. Local $addField-Closures or other auxiliary abstractions do not belong in a DD.

<?php
/* =========================================================
TABLE
========================================================= */
$table['server']='myTasks|myTasks.db3';
$table['table']='my_task';
$table['datadic']='myTask';
$table['primary']='id';
$table['language']='0';
$table['version']='1.0';
$table['autosync']='1';
$table['cache']='0';
$table['trash']='0';
$table['trace']='0';
$table['update_sql']='';
$table['default_sort']='title ASC';
$table['form-dd-table']='';
$table['read']='admin';
$table['create']='admin';
$table['update']='admin';
$table['delete']='admin';
$table['read_owner']='admin,owner';
$table['create_owner']='admin,owner';
$table['update_owner']='admin,owner';
$table['delete_owner']='admin,owner';
/* =========================================================
FIELDS
========================================================= */
$field['name']='id';
$field['type']='int';
$field['index']='PRI';
$field['length']='11';
$field['default']='';
$field['label']='ID';
$field['rules']='int';
$field['tooltip']='';
$field['errormsg']='';
$field['placeholder']='';
$field['convert']='';
$field['protect']='0';
$field['group']='';
$field['mask']='';
$field['data']='';
$field['options']='';
$field['tpl']='hidden';
$field['js']='';
$field['prompt']='';
$fields[]=$field;
$field['name']='title';
$field['type']='varchar';
$field['index']='MUL';
$field['length']='160';
$field['default']='';
$field['label']='Titel';
$field['rules']='*|min=2|max=160';
$field['tooltip']='Kurzer, verständlicher Titel.';
$field['errormsg']='';
$field['placeholder']='Aufgabe benennen';
$field['convert']='';
$field['protect']='0';
$field['group']='';
$field['mask']='';
$field['data']='';
$field['options']='';
$field['tpl']='text-label';
$field['js']='';
$field['prompt']='';
$fields[]=$field;
$field['name']='status';
$field['type']='varchar';
$field['index']='MUL';
$field['length']='24';
$field['default']='open';
$field['label']='Status';
$field['rules']='parameter|max=24';
$field['tooltip']='';
$field['errormsg']='';
$field['placeholder']='';
$field['convert']='';
$field['protect']='0';
$field['group']='';
$field['mask']='';
$field['data']='';
$field['options']='open=Offen&working=In Arbeit&done=Erledigt';
$field['tpl']='select-single-label';
$field['js']='';
$field['prompt']='';
$fields[]=$field;
/* =========================================================
INDEXES
========================================================= */
$index['name']='pk_my_task';
$index['type']='PRIMARY';
$index['fields']='id';
$index['unique']='1';
$index['comment']='from field index PRI';
$indexes[]=$index;
$index['name']='idx_my_task_title';
$index['type']='INDEX';
$index['fields']='title';
$index['unique']='0';
$index['comment']='from field index MUL';
$indexes[]=$index;
$index['name']='idx_my_task_status';
$index['type']='INDEX';
$index['fields']='status';
$index['unique']='0';
$index['comment']='from field index MUL';
$indexes[]=$index;

Binding real examples are dbx/modules/dbx/dd/dbxMissing.dd.php and the two DDs of the myInvoicesreference modules.

Important table attributes

Attribute Meaning
Servers Configured DB server or module related SQLite file
Table table Physical table name
Primary primary key; standard is: id
Language 0 neutral, voice code fixed or * Dynamics
Autosync Table may be synchronized from the DD
Trash Recycle basket/trace behavior of the table
traceability Changes are logged traceably via the DB pipeline
read/create/update/delete Group rights for each operation
read owner/update_owner Owner-based rights; dbxDB complements the owner filter

Owner, timestamp and Trash are not mandatory for every table. However, they should be used together and explicitly if property, traceability or soft delete are technically needed.

Are create date, create uid, Owner, update date and update uid present in the DD, sets dbxDB it automatically. A domain module must not reconstruct this logic in the form or before insert(), Update() or save() Reconstruction.

Local service per DD

$table['server' is the delivered standard, not a global determination for the whole system. An installation can be any DD in config.local.php Bind individually to a DB3 file or an active SQL server. dbxDB resolves this binding centrally; Domain modules remain unchanged.

$config['dd_server_bindings'] = array(
'dbx|dbxUser' => 'dbxInstall',
'dbxShop|shopOrder' => 'dbxShop|dbxShop.db3',
);

Invalid explicit bindings are rejected and do not fall unnoticed to the DD standard. Installation, migration, backup and rollback are under Installation, Updates and DD Service Connections Mandatory description.

Field attributes

Attribute Meaning
Name, Type, length Database field and data type
Index e.g. B. PRI, UNI or MUL
Description Default for new or empty records
Rules Validator rules, e.g. B. int, Parameters, email, min min, max
tpl Standard field template for dbxForm
Options Selection values, usually value=Label&wert2=Label2
Data template data, e.g. B. rows=6
converter Output/input conversion

FD: a form view of the DD

The DD describes the technical data structure. A FD selects the form fields, assigns them and can overwrite display properties. Thus, edit, search and quick form can represent the same DD differently.

<?php
$messages = array();
$messages['save_success'] = 'Daten wurden gespeichert';
$messages['save_success'] = $messages['save_success'];
$messages['save_error'] = 'Daten konnten nicht gespeichert werden';
$field = array();
$field['name'] = 'title';
$field['type'] = 'varchar';
$field['tpl'] = 'text-label';
$field['default'] = '';
$field['label'] = 'Aufgabe';
$field['rules'] = '*|min=2|max=160';
$field['placeholder'] = 'Was ist zu tun?';
$fields[] = $field;
$field = array();
$field['name'] = 'status';
$field['type'] = 'varchar';
$field['tpl'] = 'select-single-label';
$field['default'] = 'open';
$field['label'] = 'Status';
$field['rules'] = 'parameter|max=24';
$field['options'] = 'open=Offen&working=In Arbeit&done=Erledigt';
$fields[] = $field;
$field = array();
$field['name'] = 'description';
$field['type'] = 'mediumtext';
$field['tpl'] = 'textarea-label';
$field['label'] = 'Beschreibung';
$field['rules'] = '*|max=5000';
$field['data'] = 'rows=6';
$fields[] = $field;
?>

Language versions and messages

A FD contains visible labels, options, placeholders and messages. Therefore, there is a German, English and Spanish version for each FD:

Language File save success save error’
German task-form.fd.php or task-form_de.fd.php Data was stored Data could not be stored
English task-form_en.fd.php Data was saved Data could not be saved
Spanish task-form_es.fd.php Los datos se guardaron Los datos no se pudieron guardar

dbxForm resolves the file via the active language, loads $fields and $messages keep both in the central FD cache. dbxReport inherits exactly the same sequence. The binding key is called save success; save success is only carried as a compatible alias.

A DD, on the other hand, only receives language files if there are actually separate language tables. Visible translations alone are no reason to duplicate a DD.

Options:

  • Only dd put: dbxForm uses DD field information.
  • dd and fd put: The FD determines the specific form view.
  • Complete individual fields manually or specifically DD values with dd: use.
  • For a report an own Selection-FD with dbx rwhere, dbx rsort, dbx rdesc, dbx rrows and optional dbx rselect use.

Read dbxDB

$db = dbx()->get_system_obj('dbxDB');
$dd = 'myTasks|myTask';

Reading a record

$task = $db->select1($dd, (int)$rid);

An integer WHERE is resolved against the primary key defined in the DD. Columns may be limited:

$task = $db->select1($dd, array('id' => (int)$rid, 'trash' => 0),
array('id', 'title', 'status'));

select1() does not provide the empty standard structure of the DD for any hit. Therefore, technical code should not only is array() Check, but also the ID:

if ((int)($task['id'] ?? 0) <= 0) {
return dbx()->get_system_obj('dbxTPL')->get_tpl(
'dbx|alert-warning',
array('msg' => 'Nicht gefunden.')
);
}

select1() notes successful individual and blank records requestlocally. The cache key contains the canonical DD name, WHERE, column selection, rights check, and user. insert(), Update(), save() and delete() After successful writing, reject all select1()-Entries exactly this DD. Within a transaction, the cache is bypassed; Commit and rollback discard the affected server’s DD caches. The cache ends with the request and is limited to 1,000 entries.

Lists, sorting and pagination

$rows = $db->select(
$dd,
array('status' => 'open', 'trash' => 0),
array('id', 'title', 'status', 'update_date'),
'update_date',
'DESC',
'',
25,
0
);

The parameters according to $columns are: orderby, ASC|DESC, groupby, max, offset and verify access. If sorting comes from a request, the column name and direction must be checked against fixed allowlists beforehand; They are not free search values.

Safe search

Array-WHEREs validate fields against the DD and escape values centrally:

$where = array(
'trash' => 0,
'search' => array(
'value' => $search,
'like' => array('title', 'description'),
'mode' => 'contains',
),
);
$rows = $db->select($dd, $where, '*', 'title', 'ASC', '', 50, 0);

A structured form is also possible for a single LIKE field:

$rows = $db->select($dd, array(
'title' => array('like' => $search, 'mode' => 'starts_with'),
));

New request searches should use these forms. A string WHERE remains possible for existing and internally built code, but must not be created by uncontrolled concatenation of user inputs.

Counting

$all = $db->count($dd);
$open = $db->count($dd, array('status' => 'open', 'trash' => 0));

Write dbxDB

Automatic system fields

In insert() set dbxDB automatically:

  • create date
  • create uid
  • Owner
  • update date
  • update uid

In Update() set dbxDB Automatic update date and update uid. dbxForm::save_post() uses the same dbxDBpipeline. Automatic is a key advantage of DD usage: All modules receive identical audit and owner values without managing them themselves.

Insert

insert() Delivery 1 if successful. The new ID is then read:

$ok = $db->insert($dd, array(
'title' => 'Dokumentation prüfen',
'status' => 'open',
'description' => 'Beispiele im Browser nachvollziehen.',
));
$rid = ($ok === 1) ? $db->get_insert_id() : 0;

Update

$ok = $db->update($dd, array(
'status' => 'done',
), array('id' => (int)$rid, 'trash' => 0));

Insert or update with save()

$values = array('title' => $title, 'status' => $status);
$ok = $db->save($dd, $values, $rid > 0 ? $rid : 0);
$rid = ($rid > 0) ? $rid : $db->get_insert_id();

save() updates with existing WHERE/RID and adds otherwise. For technically complex storages, separate insert/update branches are often more readable; Used for standard forms dbxForm::save_post() internally this way.

Delete

$ok = $db->delete($dd, array('id' => (int)$rid));

A delete without WHERE is blocked by dbxDB. Whether a table should really be deleted, traced or treated via a domain trash is decided by the module together with the DD. Do not arbitrarily deactivate rights or trace checks.

Parameters for rights, fields, values and trace

The writing methods have infrastructure switches at the end:

$db->insert($dd, $values,
$verify_access, $verify_fields, $verify_values, $trace);
$db->update($dd, $values, $where,
$verify_access, $verify_fields, $verify_values, $trace);
$db->delete($dd, $where, $verify_access, $trace);

In the domain module, all values normally remain 1. Calls with 0 are only intended for clearly limited system paths, such as installation, internal synchronization or already separately protected infrastructure. There are real examples of this in dbxWorkflowEngine, dbxContentLngSync and dbxShopRepository.

Tree data

For parent/child structures, select tree() Normalize folders and optional items together:

$folderDd = \dbx\dbxContent\dbxContentLng::ddFolder();
$contentDd = \dbx\dbxContent\dbxContentLng::ddContent();
$tree = $db->select_tree(
$folderDd,
$contentDd,
array(
'folder_parent' => 'parent_id',
'folder_title' => 'name',
'item_parent' => 'folder',
'item_title' => 'title',
'root' => 0,
)
);
$nodes = $tree['nodes'];
$flat = $tree['flat'];

The specific CMS-DD is voice-dependent on dbxContentLng determined. The example shows the API; CMS code should use the existing resolvers.

Read the DD model

$model = dbx()->get_system_obj('dbxDD')
->get_dd_model('myTasks|myTask');
$table = $model['table'] ?? array();
$fields = $model['fields'] ?? array();

This makes sense for generators, admin tools and workflow bindings. Technical code should not dynamically guess its business logic from field definitions at every request.

Syncing DD and Database

DD-Sync is a step-by-step process. The robust pattern from the current modules resets the process and calls Applicable Until it is finished:

$dd = dbx()->get_system_obj('dbxDD');
$dd->sync_dd_to_db('myTasks', 'myTask', 'reset');
do {
$state = $dd->sync_dd_to_db('myTasks', 'myTask', 'apply');
} while (($state['status'] ?? '') === 'running');
if (($state['status'] ?? '') !== 'finished') {
throw new \RuntimeException((string)($state['message'] ?? 'DD-Sync fehlgeschlagen'));
}

Available modes of use:

  • Plan/check: Show differences without applying the scheme.
  • reset: Reset the stored process state.
  • Applicable: Use planned steps in a controlled manner.
  • Force: Force only in dedicated admin/installation paths.
  • sync db to dd(...): transfer or merge an existing DB structure into a DD.

DB according to DD is not a normal domain action. It belongs in Schema/Wizard tools and must then be tested as a complete, readable DD.

Database systems

dbxDB encapsulates access via PDO. Depending on configuration and PHP drivers, support includes SQLite, MySQL/MariaDB, PostgreSQL, SQL Server, Oracle, Firebird and other PDO drivers. A DD must therefore not force a SQLite-specific technical logic. Differences in schema and limits are dealt with in dbxDB/dbxDD.

Central query performance

If performance timer level on Maintenance or Details stands, measures dbxDB all central query, exec, insert and update paths. Per request, number, unique structures, repetitions, runtime, slow and failed queries are summarized. Off Details In addition, the most expensive normalized SQL structures are stored as fingerprints.

SQL comments and literal values are removed before storage; bound parameters are never logged. The threshold for a slow query is over performance timer slow query ms established. The evaluation is in the admin dashboard. As a result, optimizations are made based on actual request costs and query duplicates, instead of providing individual SQL points with a parallel measurement logic on suspicion.

The persistence is excluded from the measurement so that the performance tables do not produce recursive self-measurements. Domain modules continue to use exclusively dbxDB; Your own query loggers are not allowed.

During the first run after an extension, the Performance service additionally compares its tables with the DD fields and indices. Existing measured values are retained. Query mean values do not incorrectly include historical records without query profile as zero measurements.

Binding rules

  1. Use of specialised modules dbxDB, not directly PDO.
  2. DD is the versionable truth of the table structure.
  3. FD describes a form view and does not unnecessarily duplicate the data model.
  4. Request values are validated; Search conditions prefer Array-WHEREs.
  5. HTML does not belong in database methods and SQL does not belong in templates.
  6. verify access=0 and trace=0 are justified infrastructure exceptions.
  7. DD sync is completed until Finished executed and checked for errors.
  8. Each new table gets its own DD and a unique DD name.
  9. Automatic owner, user and time fields are not duplicated in the module.

Real references

  • dbx/modules/dbxWorkflow/dd/workflowDefinition.dd.php: complete DD.
  • dbx/modules/dbxWorkflow/fd/workflow-definition.fd.php: Form view.
  • dbx/modules/dbxWorkflow/include/dbxWorkflowEngine.class.php: CRUD with array WHEREs and domain persistence.
  • dbx/modules/dbxShop/include/dbxShopRepository.class.php: DD sync and extensive repository access.
  • dbx/modules/dbxContent/include/dbxContentLngSync.class.php: Language-dependent DDs and controlled system write operations.
  • Mandatory module manual — complete, mandatory module flow.
  • DB3-MySQL-DB3 round trip — tested DB3-MySQL-DB3 transfer.