# YOrm (ORM = Object-relational mapping = Objektrelationale Abbildung) YOrm erleichtert den Umgang mit in YForm Table Manager angemeldeten Tabellen und deren Daten. So ist es möglich mittels eigener Modelclasses die Daten zu verarbeiten und aufbereitet auszugeben. Werden im Table Manager neue Felder hinzugefügt oder entfernt, passen sich über YOrm ausgegegebene Formulare sofort darauf an. Die übliche PIPE oder PHP-Programmierung entfällt. Formulare müssen meist nur durch wenige Parameter ergänzt werden um sofort zu funktionieren. [Im Rahmen einer REDAXOHour ist eine Video Einführung entstanden, die viele Punkte dieses Kapitels erklärt.](https://www.youtube.com/watch?v=o88DHxsOLOs) ## YOrm ohne eigene Model Class verwenden Hole alle Daten der Tabelle `rex_my_table` und zeige das Objekt. ```php query()->find(); dump($items); ``` ## YOrm mit eigener Model Class verwenden > Hinweis: Eine eigene Model Class ist nicht zwingend erforderlich, vereinfacht das Ansprechen der Tabelle mittels der OO-Notation. Es stehen folgende Klassen zur Verfügung: - `rex_yform_manager_dataset` - `rex_yform_manager_collection` - `rex_yform_manager_query` ### Klasse erstellen Zunächst wird eine Klasse erstellt und in das `project` AddOn im Ordner `lib` abgelegt ```php ### Klasse registrieren Jetzt muss die erstellte Klasse noch registiert werden. Dazu öffnet man die Datei `boot.php` des `project` AddOns und fügt nachfolgenden Code ein. Wird das theme-Addon verwendet, den Code in die Datei `functions.php` einfügen. ```php find(); ``` ## Praxis-Beispiele ```php alias('t') ->joinRelation('relation_id', 'r') ->select('r.name', 'relation_name') ->where('t.status', '1') ->orderBy('t.name') ->find(); ``` ```php setValue('user_id', 5) ->setValue('article_id', 6) ->save(); ``` ```php where('user_id', 5) ->where('article_id', 6) ->find() ->delete(); ``` ```php query() ->joinRelation('category_id', 'c') // Join auf rex_data_product_category gemäß Relationsfeld category_id, mit Alias 'c' für weitere Verwendung ->select('c.name', 'category_name') // Aus der gejointen Tabelle den Kategorienamen mit auslesen mit dem Alias 'category_name' ->where('status', 1) ->find(); foreach ($products as $product) { echo $product->name; echo $product->category_name; // Value aus der gejointen Tabelle, siehe oben // Alternativ das komplette Objekt für die Kategorie auslesen $category = $product->getRelatedDataset('category_id'); echo $category->name; } ``` ### Datensatz abfragen ```php

title ?>

text ?>

``` **Beispiel:** Datensatz auslesen und YForm-Formular bereitstellen ```php getForm(); // Parameter festlegen $yform->setObjectparams('form_method','get'); // Ziel des Formulars, sonst erhält man nur Index.php ... $yform->setObjectparams('form_action',rex_getUrl(REX_ARTICLE_ID)); // Sollen die Daten des Datensatzes ausgelesen werden? (true = ja , false = nein) $yform->setObjectparams('getdata',true); $yform->setActionField('showtext',array('','Gespeichert')); // Ausgabe des Formulars echo $dataset->executeForm($yform); } ?> ``` ### Datensatz ändern ```php title = 'REDAXO-Tag in Wackershofen (am Grundbach)'; $post->text = '...'; if ($post->save()) { echo 'Gespeichert!'; } else { echo implode('
', $post->getMessages()); } ``` ### Datensatz erstellen ```php title = 'REDAXO-Tag in Wackershofen (am Grundbach)'; $post->text = '...'; if ($post->save()) { echo 'Gespeichert!'; } else { echo implode('
', $post->getMessages()); } ``` **_Beispiel_** Neuen Datensatz erstellen und Formular bereitstellen\*\*\* ```php getForm(); // Parameter festlegen $yform->setObjectparams('form_action',rex_getUrl(REX_ARTICLE_ID)); // Ziel des Formulars, sonst erhält man nur Index.php ... $yform->setObjectparams('form_action',rex_getUrl()); $yform->setActionField('showtext',array('','Gespeichert')); echo $dataset->executeForm($yform); } ?> ``` ### Eigene Modelklassen ```php first_name.' '.$this->last_name; } } ``` ```php getFullName(); ``` ### Query-Klasse ```php where('status', 1) ->where('created', $date, '>') ->orderBy('created', 'desc') ; $posts = $query->find(); // $post = $query->findOne(); ``` ### Collection-Klasse ```php ... $posts = $query->find(); foreach ($posts as $post) { echo $post->title; echo $post->text; } ``` ```php isEmpty(); $posts->getIds(); $posts->toKeyIndex(); $posts->toKeyValue('title', 'text'); $posts->getValues('title'); $posts->groupBy('author_id'); $posts->setValue('author_id', $authorId); $posts->save(); $posts->delete(); ``` ### Relationen ````php getRelatedDataset('author_id'); echo 'Autor: '.$author->getFullName(); echo $post->title; } $posts = $author->getRelatedCollection('posts'); ```` ```php joinRelation('author_id', 'a') ->selectRaw( 'CONCAT(a.first_name, " ", a.last_name)', 'author_name' ); $posts = $query->find(); foreach ($posts as $post) { echo 'Autor: '.$post->author_name; } ``` ### Paginierung **Beispiel 1** ```php ... $posts = $query->paginate($pager); foreach ($posts as $post) { // ... } $pager->getRowCount(); $pager->getCurrentPage(); $pager->getLastPage(); $pager->getPageCount(); ``` **Beispiel 2** ```php query() ->paginate($pager); $fragment = new rex_fragment(); $fragment->setVar('urlprovider', rex_article::getCurrent()); $fragment->setVar('pager', $pager); echo $fragment->parse('core/navigations/pagination.php'); foreach ($ergebnisse as $erg) { echo "ID: ".$erg->id; } echo $pager->getRowCount(); echo $pager->getCurrentPage(); echo $pager->getLastPage(); echo $pager->getPageCount(); ``` ### Formulare ```php getForm(); // $yform->setHiddenField(); // $yform->setObjparams(); echo $post->executeForm($yform) ``` ## Methoden-Referenz ### collection-Methoden - delete - executeForm - filter - first - getForm - getIds - getTable - getTableName - getUniqueValue - getValues - groupBy - isEmpty - isValid - isValueUnique - last - map - populateRelation - save - setData - setValue - shuffle - slice - sort - split - toKeyIndex - toKeyValue ### query-Methoden - Alias - alias - getTableAlias - count - exists (liefert true oder false zurück. Optimal für große Abfragen.) - Find - find - findId - findIds - findOne (liefert einen Datensatz als Objekt zurück.) - Get - get - getAll - Group By - groupBy - groupByRaw - resetGroupBy - Join - joinRaw - joinRelation - joinType - joinTypeRelation - leftJoin - leftJoinRelation - resetJoins - Limit - limit - resetLimit - Order By - orderBy - orderByRaw - resetOrderBy - paginate ([Beispiel](#beispiel-paginate)) - Query - query - queryOne - save - Select - resetSelect - select - selectRaw (lässt individuelle Argumente zu, wie z. B. `CONCAT, SUM`) - Table - getTable - getTableName - Where - resetWhere - setWhereOperator - where - whereNot - whereNull - whereNotNull - whereBetween - whereNotBetween - whereNested - whereRaw - whereListContains - Having - resetHaving - setHavingOperator - having - havingNot - havingNull - havingNotNull - havingBetween - havingNotBetween - havingRaw - havingListContains Beispiel für whereListContains ```php // Entweder kann nach einem einzelnen Wert gesucht werden $query->whereListContains('my_column', 5); $query->whereListContains('my_column', 'my_value'); // Oder mit einem Array von Werten, ob mindestens einer davon enthalten ist // dann aber nur mit integer-Werten! $query->whereListContains('my_column', [3, 5, 9]); ``` Beispiel für resetSelect() // resetSelect() ermöglicht es im Anschluss bestehende SELECTS zurückzusetzen und nur die Felder des Datensatzes zu erhalten, die man wirklich benötigt. ```php $dataset = rex_yform_manager_query::get('rex_yf_example') ->resetSelect() // Alle bisherigen SELECT-Definitionen werden entfernt. ->select('id') // *** id muss angegeben werden ***, da auch dieses default SELECT entfernt wurde ->select('title') ->select('name') ->findId($id); ``` ### dataset-Methoden - create - get - getAll - getData (liefert Felder als Array zurück) - getForm (liefert Formular zurück - EXPERIMENTELL!) - getId - getMessages - getRaw - getRelatedCollection - getRelatedDataset - getTable - getTableName - getValue - hasValue - isValid - loadData ## Debugging > Hinweis: Diese Vorgehensweise wird in zukünftigen Versionen optimiert. Beteilige dich aktiv an der Entwicklung auf [github.com/yakamara/redaxo_yform/](http://github.com/yakamara/redaxo_yform/)! ### Variante 1 Wichtig ist nur der Part mit `rex_sql` ```php alias('t') ->joinRelation('relation_id', 'r') ->select('r.name', 'relation_name') ->where('t.status', '1') ->orderBy('t.name') $items = rex_sql::factory()->setDebug()->getArray($query->getQuery(), $query->getParams()); $items = $query->find(); ``` ### Variante 2 Datei `/redaxo/src/addons/yform/plugins/manager/lib/yform/manager/dataset.php` und die Variable `private static $debug = false;` auf `true` setzen ## Tricks ### Dataset als YForm-Formular editieren / absenden ```php // Datensatz aus Tabelle mit ID 2 $dataset = rex_yform_manager_dataset::get(2,Tabelle); // Formular auslesen $yform = $dataset->getForm(); // Parameter festlegen $yform->setObjectparams('form_method','get'); // Ziel des Formulars, sonst erhält man nur Index.php ... $yform->setObjectparams('form_action',rex_getUrl(13)); // Sollen die Daten des Datensatzes ausgelesen werden? (true = ja , false = nein) $yform->setObjectparams("getdata",true); echo $dataset->executeForm($yform); } ?> ``` ### Aus dem Dataset ungewollte Felder (z. B. für's Frontend) herausfiltern ```php getTable()->getFields($filter); if (rex::isBackend()) { return $fields; } foreach ($fields as $i => $field) { if ('interne_links' == $field->getName()) { // hebt das Feld auf, es wird später im Formular auch nicht gezeigt. unset($fields[$i]); } if ('user' == $field->getName()) { unset($fields[$i]); } } return $fields; } } ``` Model-Class in boot.php z. B. im project Addon registrieren ```php setWhereOperator('OR') ->where('foo', 1) ->where('bar', 2) ; ``` Nachteil: Nun hat man die gleiche Schwierigkeit mit AND, die man vorher mit OR hatte. setWhereOperator bezieht sich immer auf alle(!) where()-Aufrufe, auch auf die vorherigen. **Möglichkeit 2:** Mit `whereRaw` arbeiten. ``` $query->whereRaw('(foo = :foo OR bar = :bar)', ['foo' => 1, 'bar' => 2]); ``` **Möglichkeit 3:** Mit whereNested in der Array-Notation arbeiten: ``` $query->whereNested(['foo' => 1, 'bar' => 2], 'OR'); ``` Nachteil: Man kann keine anderen Operatoren als = verwenden. **Möglichkeit 4:** Mit `whereNested` in der Callback-Notation arbeiten: ``` $query->whereNested(function (rex_yform_manager_query $query) { $query ->where('foo', 1) ->where('bar', 2) ; }, 'OR'); ``` Nachteil: Recht umständlich zu schreiben. Vorteil: Flexibel, und man kann die unterschiedlichen Methoden whereNull, whereBetween etc. in dem Sub-Query-Objekt nutzen. --- in meinem text oben fehlt übrigens noch eine variante. wenn foo und bar gleich sind, also `"foo = 1 OR foo = 2"`, dann sollte man das nutzen: ``` ->where('foo', [1, 2]) ``` (daraus wird dann foo IN (1, 2))