Export von Dateien

Mit dem Plugin mam/export wir dem Benutzer eine einfache Benutzeroberfläche angeboten, um Dateien, deren Feldwerte und die Ordnerstruktur aus dem MAM zu exportieren. Mam/export erweitert die Navigation um den Eintrag Export, über den die Benutzeroberfläche aufgerufen wird.

Zunächst muss mindestens ein Ordner  gewählt werden, dessen Inhalte exportiert werden sollen (eine Mehrfachauswahl ist möglich).

Über die Checkboxen Dateien  und Struktur  kann festgelegt werden, ob nur die Dateien des Ordners / der Ordner exportiert werden sollen, und / oder nur die Struktur und Datensatz-Informationen. Sämtliche Dateien werden komprimiert in einem einzigen Zip-Archiv ausgeliefert und nach dem Export direkt über den Browser heruntergeladen. Die Dateien werden hierbei wahlweise direkt ohne Unterordner in einer flachen Liste im Archiv angelegt oder mit der bestehenden Ordnerstruktur der Quelldateien (Ordnerstruktur mit exportieren). 

Aufbau der Struktur-Datei

Zum aktuellen Zeitpunkt ist XML das einzige unterstützte Ausgabeformat. Dieses besteht aus 5 Bereichen:

Bereich

Beschreibung

Bereich

Beschreibung

settings

Meta-Informationen zum Export-Zeitpunkt sowie dem Mandanten und der Domain der Dateien.

languages

Der Index der vorhandenen Sprachen. Die Dateien verweisen jeweils über ein Attribut languageID auf einen der language-Nodes.

folders

Der Index der Ordner-Struktur. Mittels Attribut id werde die Ordner indiziert und enthalten als Nodes die Felder mamFolder-Datensatzes.
Die Dateien verweisen mittels des Nodes folderID auf einen der hier gelisteten Ordner

fields

Der Index der Felder mit den Feldern der Datensätze (mamFileField).

files

Die eigentlichen Dateien mit sämtlichen Feldern des mamFile-Datensatzes. Der Knoten folderID verweist auf den Ordner aus dem Index.

Sämtliche Feldwerte des mamFile-Datensatzes sind im Unterknoten fields aufgelistet. Diese sind über das Attribut id zum jeweiligen Feld des Index zugeordnet.
Die Werte sind pro Sprache über das Attribut languageID aufgelistet.


Eine beispielhafte XML-Datei ist wie folgt aufgebaut:

<?xml version="1.0"?> <mamExport> <settings> <exportTime>1525333474</exportTime> <clientID>1</clientID> <domainID>1</domainID> </settings> <languages> <language id="1">de</language> <language id="2">en</language> </languages> <folders> <folder id="1"> <createTime>1525077772</createTime> <changeTime>1525077772</changeTime> <mamFolderPath> Zweiter-Testordner/Unterordner-des-Testordners/ </mamFolderPath> <mamFolderColor>#274e13</mamFolderColor> <mamFolderIsSystemFolder>0</mamFolderIsSystemFolder> </folder> <...> </folders> <fields> <field id="2"> <changeTime>1525080455</changeTime> <createTime>1525080455</createTime> <userID>1</userID> <mamFileFieldIdentifier> <value languageID="1">Test-Identifier</value> <value languageID="2">Test-Identifier</value> </mamFileFieldIdentifier> <mamFileFieldLabel> <value languageID="1">Test-Label</value> <value languageID="2">Test-Label</value> </mamFileFieldLabel> <mamFileFieldType>rte</mamFileFieldType> <mamFileFieldEntries> <value languageID="1"></value> <value languageID="2"></value> </mamFileFieldEntries> <mamFileFieldPredefined> <value languageID="1"></value> <value languageID="2"></value> </mamFileFieldPredefined> <mamFileFieldTooltip> <value languageID="1"></value> <value languageID="2"></value> </mamFileFieldTooltip> <mamFileFieldGroupChildFields> <value languageID="1"></value> <value languageID="2"></value> </mamFileFieldGroupChildFields> <mamFileFieldResultColumn>0</mamFileFieldResultColumn> <mamFileFieldSort>0</mamFileFieldSort> <mamFileFieldConstraint></mamFileFieldConstraint> <mamFileFieldRelation> <value languageID="1"></value> <value languageID="2"></value> </mamFileFieldRelation> <mamFileFieldFeatureForm> <value languageID="1"></value> <value languageID="2"></value> </mamFileFieldFeatureForm> </field> <...> </fields> <files> <file id="1"> <folderID>4</folderID> <createTime>1525078573</createTime> <changeTime>1525247400</changeTime> <userID>1</userID> <mamFilePath> Zweiter-Testordner/Unterordner-des-Testordners/sample-image-1.jpg </mamFilePath> <mamFileFileSize>5259440</mamFileFileSize> <mamFileResX>3648</mamFileResX> <mamFileResY>2432</mamFileResY> <mamFileMimeType>image/jpeg</mamFileMimeType> <mamStatus>0</mamStatus> <mamFileMetaData>image/jpeg</mamFileMetaData> <fields> <field id="2"> <value languageID="1">Der Wert des Feldes für Sprache 1</value> <value languageID="2">Der Wert des Feldes für Sprache 2</value> </field> <...> </fields> </file> <...> </files> </mamExport>

Technische Umsetzung

Für den Export der Struktur der Datensätze mamFile, mamFolder und mamFileField müssen diese serialisiert in Textform (XML-Struktur) gebracht werden. Hierfür kommt die Symfony-Komponente Serializer (4.0.9) zum Einsatz. Diese ist in zwei Bereichen gegliedert: Normalisieren und Encoden. Das Normalisieren wandelt eine Struktur (z.B. Objekte bzw. Entities) in ein Array um, welches dann vom Encoder verwendet werden kann. Hierbei können zusätzliche Converter implementiert werden, um zB. Formatierungsregeln anzuwenden oder Werte und Properties umzubenennen. Das Array muss auf ganz bestimmte Art aufgebaut sein, damit es später vom Encoder zu einer gültigen XML serialisiert werden kann.

Im Fall des fields-Knotens eines file-Knotens sieht die Struktur beispielhaft wie folgt aus:

'fields' => [ 'field' => [ [ '@id' => 1, 'value' => [ [ '@languageID' => '1', '#' => 'Wert für Sprache 1' ], [ '@languageID' => '2', '#' => 'Wert für Sprache 2' ] ] ], [ '@id' => 2, 'value' => [ [ '@languageID' => '1', '#' => 'Wert 2 für Sprache 1' ], [ '@languageID' => '2', '#' => 'Wert 2 für Sprache 2' ] ] ], ... ] ]

Als XML serialisiert ergibt das folgende Ausgabe:

<fields> <field id=1> <value languageID="1">Wert für Sprache 1</value> <value languageID="2">Wert für Sprache 2</value> </field> <field id=2> <value languageID="1">Wert 2 für Sprache 1</value> <value languageID="2">Wert 2 für Sprache 2</value> </field> </fields>

Grundsätzlich verwendet der Encoder assoziative Arrays, z.B. ['field' => 'value'] wird zu <field>value</field> serialisiert. Probleme gibt es hierbei, wenn mehrere field-Knoten nacheinander stehen sollen, da der Key in assoziativen Arrays immer eindeutig sein muss. Das Folgende Array ist daher nicht möglich: ['field' => 'value', 'field' => 'value2']. Um dies zu erzielen wird folgendes geschrieben: ['field' => ['value', 'value2']]. Um dem Knoten field ein Attribut id zu geben muss dieses mittels @attributsname angegeben werden (siehe im oberen XML-Beispiel field und value mit den Attributen id und languageID). Hierbei wird die Struktur dann schnell recht komplex und unübersichtlich. Die falsche Verwendung von nummerischen und assoziativen Arrays führt schnell zu einem völlig anderen Ergebnis in der XML-Ausgabe.

Ein weiteres Problem ergibt sich mit den Sonderzeichen @ und #. Die Eingabedaten werden in brandbox als entities aufgebaut, jeder Knoten und dessen Wert ist als Objekt-Attribut angelegt. Die Zeichen @ und # sind allerdings als Zeichen für Objekt-Attribute in PHP nicht zulässig. Daher findet hier mittels der Klasse lib\converter\nameConverter eine Umwandung von Objekt-Attributen zur Array-Struktur statt. Das Objekt-Attribut wird dabei mit Prefix attribute_ versehen, gefolgt vom Namen des XML-Attributes. Das PHP-Objekt-Attribut public $attribute_id wird zu einem Array-Key @id normalisiert. Der Hashtag # verfährt analog dazu mittels dem Prefix value_.

Symfony bietet weitere Encoder, die auch in Json und andere Formate kodieren können. Vor der Implementierung dieser Encoder muss aber die Normalisierung (besondern die Attribute mit # und @) angepasst werden. Eine Kodierung in json kann derzeit nicht ohne Weiteres vorgenommen werden.



Weitere Informationen zur Symfony Serializer Komponente

http://symfony.com/doc/current/components/serializer.html