Magic und DynamicMagic Felder
Table of Contents
Magic
Magic-Felder sind Felder die durch z.B. einem Query generiert werden. Die Felder sind nicht veränderbar! Ein Magic-Feld kann in der column-Config entweder mit dem Query-Node befüllt werden oder mit dem QueryBuilder-Node.
Query
Es kann in der XML-Konfiguration dem dem Magic-Feld ein Query-Node definiert werden.
Bei dem Query der definiert wird, ist zu beachten wofür das Magic-Feld verwendet wird. Falls der Wert einzig und allein im Grid angezeigt werden soll, muss nicht zwingend ein FROM verwendet werden, wenn auf bereits verjointe Tabellen zugegriffen wird. Falls jedoch das Feld auch in der Detailansicht verwendet werden soll, muss entweder eine get{FeldName}() Methode im Trait implementiert werden oder der Query muss als selbstständiger Query funktionieren können.
Beispiel:
<magic name="Name">
<object:column xmlns="http://www.setasign.com/Konquadrat/Grid"
xmlns:object="http://www.setasign.com/Konquadrat/Object"
>
<!-- Funktioniert nur im Grid -->
<query>
CONCAT(`kon2_object_person`.firstname, ' ', `kon2_object_person`.lastname)
</query>
<!-- Funktioniert auch in der Detailansicht -->
<query>
SELECT
CONCAT(kon2_object_person.firstname, ' ', kon2_object_person.lastname)
FROM kon2_object_person
WHERE kon2_object_person.id = `kon2_object`.id
</query>
</object:column>
</magic>
Alle Spalten aus dem Objekt müssen mit dem Tabellennamen angeben werden und mit BACKTICK gequotet sein. Die restlichen Tabellennamen dürfen nicht mit BACKTICK gequotet sein!
Der Grund warum der obere Query nicht in der Detailansicht funktioniert ist folgender: In der Detailansicht wird der Query aus der Konfiguration genommen, alle gequoteten "Tabellen+Spalten"-namen werden ersetzt durch die Werte die in dem Objekt gesetzt sind (als Werte gequotet) und anschließend wird der veränderte Query einzeln abgefragt.
In diesem Fall ist der obere Query auch deutlich einfacher zu beheben indem einfach ein 'SELECT' davor geschrieben wird. In der Feld-Instanz würde dann aus dem Query "SELECT CONCAT('Vorname',' ', 'Nachname')" gemacht werden. Anschließnd würde der Text von mysql mit CONCAT verbunden werden. Deutlich performanter sollte jedoch eine eigene getName()-Methode im Trait sein.
QueryBuilder
Seit Konquadrat 1.10.2.0 gibt es den QueryBuilder. Der QueryBuilder ist entstanden, weil die obere Variante mit den Queries sehr fehleranfällig ist und auch relativ aufwändig, da sämtliche Joins per Hand gemacht werden müssen. Deswegen wurde eine einfachere Art umgesetzt um Queries zu generieren.
Der QueryBuilder wird komplett in XML konfiguriert und die generierten Queries sind sowohl im Grid verwendbar als auch in der Detailansicht. Derzeit gibt es folgende Arten von QueryBuilder:
- referencingObject - Kann verwendet werden um Objekte aufzulösen, die auf dieses Objekt zeigen.
- thisObject - Kann verwendet werden um mehrere Felder aus diesem Objekt zusammenzufassen.
Der Beispiel Query von weiter oben würde mit dem QueryBuilder wie folgt aussehen:
<magic name="Name">
<object:column xmlns="http://www.setasign.com/Konquadrat/Grid"
xmlns:object="http://www.setasign.com/Konquadrat/Object"
>
<queryBuilder>
<thisObject>
<selector>
<concat>
<field>FirstName</field>
<value> </value>
<field>LastName</field>
</concat>
</selector>
</thisObject>
</queryBuilder>
</object:column>
</magic>
Falls man als Feldnamen ein Referenzfeld angibt wird die ID auf die das Referenzfeld zeigt verwendet. Zusätzlich ist es jedoch möglich die Referenzfelder direkt aufzulösen und auf die Felder von dem Ziel zu verwenden (hierbei ist wichtig, dass falls z.B. auf ein ObjectTemplate gezeigt wird sind in jedem Fall nur die Felder aus dem ObjectTemplate verfügbar).
Dafür muss bei der Feldangabe einfach ein Punkt '.' nach dem Feldnamen gemacht werden z.B.
"<field>Country.Name</field>". Dies ist über beliebig viele Ebenen möglich!
Genauso ist es hierüber auch möglich andere Magic-Felder oder MultiLang-Felder zu verwenden (Country.Name ist z.B. meistens ein MultiLangString-Feld)!
Die komplette XML-Dokumentation zu dem QueryBuilder ist hier zu finden.
DynamicMagic
Ein DynamicMagic-Feld generiert beim ConfigReload aus einem Feld mehrere Felder dynamisch. Die generierten Felder sind alle magic also nicht veränderbar. Ähnlich wie bei magic Feldern muss column > query (oder queryBuilder) definiert sein.
TitleQuery definiert welche Spalten es gibt und der Query muss anhand der id der Spalte die Daten der Spalte zurückgeben. Hierfür muss in dem Query der Platzhalter $ID$ verwendet werden. Wenn der QueryBuilder verwendet wird, wird der Query nicht von ihrem ursprünglichen Scope aus ausgeführt, sondern von dem Objekt aus der entsprechenden Spalte (z.B. in der Spalte mit der id 323 zeigt thisObject auf das Objekt mit der id 323).
Es gibt zwei verschiedene Möglichkeiten TitleQuery zu definieren:
Entweder wird der "query"-Node als Child verwendet. Dieser Query muss selbstständig funktionieren! Der Query muss die Spalten "id" (muss eine Objekt-ID sein) und "name" (alternativ "name_{sprache}") zurückgeben. GROß- UND KLEINSCHREIBUNG BEACHTEN!!
Alternativ kann der "list"-Node als Child verwendet werden. Hier wird manuell jede ID einzeln eingetragen mit dem dazugehören Namen. Die eingetragenen IDs müssen gültige Object-Ids sein!
Um dynamicMagic Felder in Grids anzeigen zu können, muss statt "column" -> "columns" verwendet werden. Für dynamicMagic Felder wird "labels" nicht als Ersatz für column > title verwendet! column > title wird standardmäßig für die Unterspalten wie folgt ersetzt: "{title} ({name})". Falls "{0}" im title steht wird stattdessen der Platzhalter mit dem Namen ersetzt.
Die komplette XML-Dokumentation für DynamicMagic-Felder ist hier zu finden!
MagicWithParam
Mit Konquadrat v2.5.0.0 gibt es den Feld-Typen "MagicWithParam". Dieser verhält sich ähnlich wie Magic-Felder, hat jedoch noch zusätzlich Parameter die von Außen mitgegeben werden. Beispiel: Ein übliches Problem ist herauszufinden, ob eine Email mit einem bestimmten Ident bereits verschickt wurde:
<magicWithParam name="WasAlreadySent">
<parameters>
<parameter name="EmailIdent"/>
</parameters>
<column>
<grid:queryBuilder>
<grid:referencingObject type="Email">
<grid:selector>
<grid:ifNull>
<grid:value>
<grid:value>1</grid:value>
</grid:value>
<grid:else>
<grid:value>0</grid:value>
</grid:else>
</grid:ifNull>
</grid:selector>
<grid:filters>
<grid:filter field="Ident" operator="=">
<grid:value>!EmailIdent!</grid:value>
</grid:filter>
</grid:filters>
</grid:referencingObject>
</grid:queryBuilder>
</column>
</magicWithParam>
Die Syntax ist die Selbe wie bei normalen Magic-Feldern, nur dass zusätzlich !PARAMETER_NAME! ersetzt wird, in die individuell mitgegeben Werte ähnlich wie beim ManualQueryBuilder.
Die Verwendung im Code sind dann wie folgt aus:
$this->getMagicWithParam('WasAlreadySent', ['EmailIdent' => $ident]);
Und ein Vorausladen im ObjectSet ist wie folgt möglich:
$objectSet->resolveMagicWithParam([
HasEmailTplObject::NAME => [
['field' => 'WasAlreadySent', 'parameters' => ['EmailIdent' => $ident]]
]
]);
Eine Verwendung im Grid von MagicWithParam-Feldern ist momentan noch nicht möglich.
