Mapping

Müssen Daten von einem Objekt oder Array in ein definiertes Objekt überführt werden spricht man von Mapping. In brandbox wird dieser Vorhang mithilfe eines MapBuilders durchgeführt.

Nicht immer ist ein Mapping sinnvoll - Sollten die Daten bspw. von vornherein bekannt sein und es müssen keine Transformierungen vorgenommen werden, so kann auf das Mapping verzichtet und das Zielobjekt direkt befüllt werden.

Aufbau des Plugins

Die notwendigen Klassen und Interfaces für das Mapping sind im Plugin component/mapping zu finden. Der Vorgang eines Mappings besteht aus vier Informationen - dem Quellobjekt oder Array, dem MapBuilder, einer Mapping-Klasse und einem Zielobjekt. Der MapBuilder und zwei generische Mapping-Klassen werden durch das genannte Plugin zur Verfügung gestellt. Zudem stellt die Klasse \brandbox\admin\plugin\lib\controllerAbstract die Methode map() zur Verfügung. Hier wird eine neue Instanz des MapBuilders geliefert.

MapBuilder

Der MapBuilder ist die Steuerungsklasse eines Mapping-Vorgangs. Hier laufen Informationen wie Quellobjekt oder Array, der Mapping-Klasse und dem Zielobjekt zusammen und werden zentral verarbeitet. Der bereitgestellte MapBuilder ist in der Klasse \brandbox\component\mapping\lib\builder\mapBuilder deklariert implementiert das Interface \brandbox\component\mapping\lib\builder\mapBuilderInterface

Mapping-Klassen

Eine Mapping-Klasse definiert das grundlegende Vorgehen beim Mapping und stellt Informationen über die verfügbaren Properties des Zielobjektes bereit. Das Mapping-Plugin stellt zwei allgemeine Mapping-Klassen bereit. Zum einem \brandbox\component\mapping\lib\map\mapGeneric und zum anderen \brandbox\component\mapping\lib\map\mapEntity. Eine Mapping-Klasse muss das Interface \brandbox\component\mapping\lib\map\mapInterface implementieren.

Die Mapping-Klasse mapGeneric ist die standardmäßig gesetzte Mapping-Klasse des MapBuilders, sie nimmt keinerlei Datentransformation vor, stellt aber eine generische Methode für Mapping-Vorgänge bereit. Diese gibt die Daten unverändert zurück.

Die Mapping-Klasse mapEntity hingegen wird genutzt um Doctrine-Entities zu befüllen. Sie nimmt rudimentäre Transformationen an den Daten vor, damit die Integrität des zu befüllenden Entities erhalten bleibt.

Verwendung

Der einfachste Anwendungsfall überführt Daten von einem Objekt oder Array in ein anderes Objekt. In folgenden Beispiel wird davon ausgegangen, dass man bspw. ein Datenbank-Entity in ein einfaches Objekt überführen möchte, ohne die Daten zu transformieren oder andere Property-Namen zu nutzen.

<?php namespace brandbox\pluginType\pluginName\lib\request { use brandbox\admin\plugin; use brandbox\pluginType\pluginName; class vcard extends plugin\lib\requestAbstract { /** * @param pluginName\lib\entity\pluginNamePerson $person * * @return pluginName\lib\map\vcard */ public function getByEntity($person) { return $this ->map() ->from($person) ->to(pluginName\lib\map\vcard::class) ; } } } ?>

Folgende Methoden wurden in diesem Beispiel genutzt:

Methode

Beschreibung

Methode

Beschreibung

mapBuilderInterface::from($input, $multiple = false)

Legt die Datenquelle fest. Dies kann entweder ein instantiiertes Objekt oder ein Array sein. Wird zusätzlich der Parameter $multiple auf true gesetzt wird als $input ein Array mit Objekten oder Arrays erwartet.

mapBuilderInterface::to($output)

Führt das Mapping auf Basis der festgelegten Informationen durch und gibt das resultierende Objekt, welches über den Parameter $output festgelegt wurde, zurück. Ist der Parameter $multiple im Aufruf von mapBuilderInterface::from($input, $multiple) auf true gesetzt worden, wird ein Array mit den resultierenden Objekten zurückgegeben.

Mapping auf Entities

Muss von einem Array oder Objekt auf ein Datenbank-Entity gemapped werden, so sollte die Mapping-Klasse \brandbox\component\mapping\lib\map\mapEntity genutzt werden. Die wird mithilfe der Methode mapBuilderInterface::withMap($map) festgelegt.

<?php namespace brandbox\pluginType\pluginName\lib\request { use brandbox\admin\plugin; use brandbox\component\mapping; use brandbox\pluginType\pluginName; class vcard extends plugin\lib\requestAbstract { /** * @param pluginName\lib\entity\pluginNamePerson $person * * @return pluginName\lib\map\vcard */ public function getByEntity($person) { return $this ->map() ->from($person) ->withMap(mapping\lib\map\mapEntity::class) ->to(pluginName\lib\map\vcard::class) ; } } } ?>

Mapping auf Entities mit eingeschränkten Entity-Properties

Mit der Mapping-Klasse \brandbox\component\mapping\lib\map\mapEntityAdvanced können nur bestimmte Doctrine-Entity-Properties übertragen werden. Diese lassen sich über eine Black- oder Whitelist einstellen. Sollte Black- bzw. Whitelist erhält man unter anderem durch die Formular-Komponente.

<?php namespace brandbox\pluginType\pluginName\lib\execute { use brandbox\admin\plugin; use brandbox\component\form; use brandbox\component\mapping; use brandbox\pluginType\pluginName; class vcard extends plugin\lib\executeAbstract { /** * @param array $params * * @return void */ public function save($params) { // Ziel-Entity abrufen $person = $this ->getRepository(pluginName\lib\entity\person::class) ->getEntity(0) ; // Black- und Whitelist abrufen $engine = $this->getAppFactory(form\engine::class); $whitelist = $engine->getListedColumnsByEntity($person, '[Formularidentifikator]', $engine::LIST_TYPE_WHITELIST); $blacklist = $engine->getListedColumnsByEntity($person, '[Formularidentifikator]', $engine::LIST_TYPE_BLACKLIST); // Diese Mapping-Klasse muss vorher initialisiert werden $map = mapping\lib\map\mapEntityAdvanced::get($whitelist, $blacklist); $this ->map() ->from($params) ->withMap($map) ->to($person) ; } } } ?>

Beeinflussung des Mapping-Vorgangs

In alle Mapping-Vorgänge kann auf verschiedenste Weise eingegriffen werden. Die folgenden Methoden stehen hierfür zur Verfügung und können vor dem Aufruf von mapBuilderInterface::to($output) eingesetzt werden.

Methode

Beschreibung

Methode

Beschreibung

mapBuilderInterface::withMap($map, $withSource = false)

Setzt die Mapping-Klasse für den aktuellen Mapping-Vorgang. Hier kann entweder ein Klassenname oder ein instantiiertes Objekt angegeben werden. Mapping-Klassen müssen das o.g. mapInterface implementieren und generische oder spezifische Mapping-Methoden bereitstellen.

$withSource kann verwendet werden um in der Mapping-Methode nicht die Property rein gereicht zu bekommen sondern das gesamte Quellobjekt.

mapBuilderInterface::withPropertyMap($target, $source)

Zwischen Quelle und Ziel können sich die Property-Namen unterscheiden, obwohl die gleichen Daten enthalten sein sollen. Hierfür kann diese Methode genutzt werden. Der Parameter $target gibt den Property-Namen im Zielobjekt an und der Parameter $source den Property-Namen im Quellobjekt.

Beispiel



mapBuilderInterface::withStaticMap($target, $value)

Mithilfe dieser Methode können statische Werte in bestimmte Properties im Zielobjekt eingefügt werden. Hierbei wird das eigentliche Mapping umgangen und der angegebene Wert genutzt.

mapBuilderInterface::withCallableMap($target, $callable, $source = null)

Mithilfe dieser Methode kann für eine bestimmte Property Code außerhalb der Mapping-Klasse aufgerufen werden. Auch kann hier, wie bei mapBuilderInterface::withPropertyMap($target, $source) der Property-Name im Quell- und Zielobjekt gemapped werden.

Beispiel



Eigene Mapping-Klassen nutzen

Sollten die bereitgestellten Mapping-Klassen und die Zusatzfunktionen nicht ausreichend sein oder wird ein bestimmtes Mapping-Verhalten mehrfach benötigt, kann es sinnvoll sein eine eigene Mapping-Klasse zu definieren. In den meisten Fällen kann als Grundlage einer eigenen Mapping-Klasse von \brandbox\component\mapping\lib\map\mapGeneric oder \brandbox\component\mapping\lib\map\mapAbstract abgeleitet werden. Zwingend notwendig ist jedoch die Implementation des Interface \brandbox\component\mapping\lib\map\mapInterface. Die eigene Mapping-Klasse kann in einem Mapping-Vorgang mithilfe der Methode mapBuilderInterface::withMap($map) gesetzt werden.

In o.g. Beispiel wurde nun eine Mapping-Klasse angelegt, welche eine Mapping-Funktion für die Property SomeTargetPropertyName bereitstellt. Sollte nun mit dieser Mapping-Klasse auf ein Objekt gemapped werden, welches diese Property besitzt, so wird diese Methode mit dem Wert aus dem Quellobjekt aufgerufen.

In PHP wird bei Methodennamen nicht zwischen Groß- und Kleinschreibung unterschieden. In o.g. Beispiel sind werden auch Properties wie bspw. someTargetPropertyName, SOMETARGETPropertyName, etc. gemapped.