Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

YOrm Query-Builder berücksichtigen #382

Open
gharlan opened this issue Mar 7, 2023 · 1 comment
Open

YOrm Query-Builder berücksichtigen #382

gharlan opened this issue Mar 7, 2023 · 1 comment

Comments

@gharlan
Copy link
Member

gharlan commented Mar 7, 2023

Wie gewünscht ein paar Infos zum Query-Builder von YOrm (YForm).

Der Query-Builder ist komplett in dieser Klasse abgebildet: https://github.com/yakamara/redaxo_yform/blob/master/plugins/manager/lib/yform/manager/query.php

Ein Beispiel:

$datasets = rex_yform_manager_query::get('my_table')
    ->where('col1', 'foo') // =
    ->where('col2', [1, 2, 3]) // IN
    ->where('col3', 5, '>')
    ->whereRaw('col4 = :col4 OR col4 IS NULL', ['col4' => $col4])
    ->joinRelation('other_id', 'o') // die in yform hinterlegte Relation auf dem other_id Feld wird verknüpft mit Alias o
    ->select('o.foo') // zusätzliches Feld aus der Relation abfragen
    ->orderBy('o.name')
    ->orderByRaw('IF(col1 = 1, col2, col3)')
    ->find();

Einstieg

Es gibt diese Wege, um das Query-Objekt zu erzeugen:

rex_yform_manager_query::get($table);
rex_yform_manager_table::get($table)->query();
rex_yform_manager_dataset::query($table);

// MyModel extends rex_yform_manager_dataset
// hier kann der $table param weggelassen werden
// Es wurde dann irgendwo `rex_yform_manager_dataset::setModelClass($table, MyModel::class)` aufgerufen
MyModel::query();

// Hier wird an einem Dataset zu einer in yform hinterlegten Relation ein Query-Objekt erzeugt
// hier wird es für rexstan schwer, zu wissen, welche Table dahinter steckt
$dataset->getRelatedQuery($key);

$table ist also jeweils ein Tabellenname. (Wobei nur Tabellen zugelassen sind, die vom YForm Table Manager verwaltet werden)

Fluent API

Hier gibt es recht viele Methoden. Die meisten haben eine Variante mit Escaping und eine Raw-Variante, z.B. where() und whereRaw.
Am besten mal die Klasse selbst durchschauen, welche Methoden da alle existieren.

Hier ein paar Infos zu den verwendeten Parametern in den Methoden, die sich anhand des Namens gruppieren lassen:

Param Hinweis
$table Tabellenname, wird escaped mit Backsticks
$column, $column1, $column2, $keyColumn Spaltenname, wird escaped mit Backsticks.

Aber es gibt hier ein Sonderhandling, es ist auch table.column oder alias.column erlaubt. Dazu gibt es eine abgewandelte quoteIdentifier-Methode in der Klasse.

Teils kann es auch ein Alias sein, z.B. ->select('COUNT(1)', 'count')->orderBy('count'), da wird an $column in orderBy also ein vorher gesetzer Alias übergeben

Bei joinRelation/leftJoinRelation/joinTypeRelation kann es auch ein virtueller Name sein für eine in YForm hinterlegte Relation
$alias Alias-Name für Tabelle oder Spalte. Werden neuerdings auch escaped.
$operator Bei manchen Methoden wird 'AND' oder 'OR' erwartet (dort als Type auch definiert). Wird aber nicht geprüft, kommt letztlich also raw in die Query rein).

Bei anderen Methoden (z.B. where()) ist es ein beliebiger SQL-Operator (=, LIKE, NOT IN etc.). Landet auch raw in der Query.
$type Bei den Join-Methoden der Join-Type ('INNER' etc.). Aktuell auch ohne Validierung und landet raw in der Query.
$expression, $where, $condition Raw SQL-Schnipsel
$value, $from, $to Werte, die escaped werden (per prepared Query-Params)
$nested Parameter bei whereNested(). Wenn es ein Array ist, dann sind die Keys Column-Namen, nach der gleichen Logik wie oben bei $column erläutert. Auch verschachtelte Arrays möglich. Werte wie bei $value.

Abschluss

Dann gibt es noch diverse Abschluss-Methoden, also um die Query auszuführen und ein Ergebnis zu bekommen:
Alle find*-Methoden, getIterator, paginate, count, exists


Kannst du damit so was anfangen? Ansonsten gerne weiter fragen, z.B. wenn ich zu bestimmten Methoden noch Beispiele liefern soll oder so.

@christophboecker
Copy link
Member

christophboecker commented Mar 8, 2023

Beispiele, wo ich den QueryBuilder statt SQL bzw. rex_sql nutze:

EP YFORM_DATA_LIST_QUERY:

Seit YForm 4 wird die Datensatzliste als YForm-Query erstellt. Das macht es deutlich einfacher, die Query (früher SQL-Statement) anzupassen.

Typische Anpassungen sind ...

Sortierung

YForm-Standardist ein Feld; zwei/drei können durch Yorm-Anpassung aktiviert werden. Beispiel hier im Geolocation-Addon
https://github.com/FriendsOfREDAXO/geolocation/blob/b8c1d0a9d4deb216f90b75e7f77f4b0a3f32f291/lib/yform/dataset/Layer.php#L367-L383

Zusätzliche Felder für die Liste

Die Liste wird im EP YFORM_DATA_LIST angepasst. Will man zusätzliche Spalten mit (aggregierten) Informationen aus anderen Tabellen haben, setzen viele ein CustomFormat (=Callback) auf die Spalte, rufen im Callback die Daten ab und verarbeiten sie. Das bedeutet zusätzliche zur Haupt-Query n weitere SQL-Abfrage. Überflüssig, wenn man die Hauptquery geschickt ergänzt hat.

Daten aus be_manager_relation verlinkten Datensätze aufbereiten / aggregieren

Aus Sicht einer "Dokumenten"-Tabelle; Der Join geht auf eine "Historie"-Tabelle, die die im Dokument erwähnten Boote enthält. In der Tabellenzeile wird das Feld anzahl_boote ausgegeben.

rex_extension::register(
    'YFORM_DATA_LIST_QUERY', 
    static function (rex_extension_point $ep)
    {
        $query = $ep->getSubject();
        $alias = $query->getTableAlias();

        // Join auf die Boote/Historie und daraus die Anzahl Boote ermitteln
        $query->selectRaw('COUNT(DISTINCT a.id)', 'anzahl_boote');
        $query->joinRelation('do_id_historie','a');

        // Sortieren nach Dokumententyp und Datum
        $query->orderBy($alias.'.do_id_doktyp');
        $query->orderBy($alias.'.do_datum');

        // Wegen der Joins mit Aggregat-Funktion: Gruppieren nach id des Hauptsatzes
        $query->groupBy($alias.'.id');
    }

Delete nur wenn zulässig (eingehende Referenzen prüfen)

Aus Sicht einer "Scan"-Tabelle. Scans sind in Dokumenten als Nachweis verlinkt (SET, kommaseparierte ID-Liste).
Wenn in der Tabellenzeile das Feld im_dokument > 0 ist, wird der Delete-Button entfernt (EP YFORM_DATA_LIST)

rex_extension::register(
    'YFORM_DATA_LIST_QUERY', 
    static function (rex_extension_point $ep)
    {
        $query = $ep->getSubject();
        $alias = $query->getTableAlias();

        // Join auf die Dokumente und ermitteln, ob der Scan irgendwo verlinkt ist
        $query->selectRaw('(0 < COUNT(a.id) )', 'im_dokument');
        $query->joinRaw('LEFT', 'rex_kv30_dokument', 'a', 'FIND_IN_SET('.$alias.'.id, a.do_id_scan)');

        // Wegen der Joins mit Aggregat-Funktion: Gruppieren nach id des Hauptsatzes
        $query->groupBy($alias.'.id');
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants