JsonToDocumentMapper   B
last analyzed

Complexity

Total Complexity 44

Size/Duplication

Total Lines 304
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 44
eloc 158
dl 0
loc 304
rs 8.8798
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
C editDocument() 0 72 15
B parseXpathString() 0 30 6
F getMetadataFromJson() 0 106 19
A getDocument() 0 51 4

How to fix   Complexity   

Complex Class

Complex classes like JsonToDocumentMapper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use JsonToDocumentMapper, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace EWW\Dpf\Services\Api;
3
4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
 * It is free software; you can redistribute it and/or modify it under
8
 * the terms of the GNU General Public License, either version 2
9
 * of the License, or any later version.
10
 *
11
 * For the full copyright and license information, please read the
12
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
 * The TYPO3 project - inspiring people to share!
15
 */
16
17
use EWW\Dpf\Domain\Model\Document;
18
use EWW\Dpf\Services\ProcessNumber\ProcessNumberGenerator;
19
use JsonPath\JsonObject;
20
21
class JsonToDocumentMapper
22
{
23
    /**
24
     * objectManager
25
     *
26
     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
27
     * @TYPO3\CMS\Extbase\Annotation\Inject
28
     */
29
    protected $objectManager;
30
31
    /**
32
     * documentTypeRepository
33
     *
34
     * @var \EWW\Dpf\Domain\Repository\DocumentTypeRepository
35
     * @TYPO3\CMS\Extbase\Annotation\Inject
36
     */
37
    protected $documentTypeRepository = null;
38
39
    /**
40
     * documentRepository
41
     *
42
     * @var \EWW\Dpf\Domain\Repository\DocumentRepository
43
     * @TYPO3\CMS\Extbase\Annotation\Inject
44
     */
45
    protected $documentRepository = null;
46
47
    /**
48
     * Replaces the data from the document with the data from the json
49
     * @param Document $document
50
     * @param $jsonData
51
     * @return Document
52
     */
53
    public function editDocument(Document $document, $jsonData)
54
    {
55
        $metaData = $this->getMetadataFromJson($jsonData, $document->getDocumentType());
56
        $xmlData = $document->getXmlData();
57
58
        $domDocument = new \DOMDocument();
59
        $domDocument->loadXML($xmlData);
60
61
        $xpath = \EWW\Dpf\Helper\XPath::create($domDocument);
62
63
        foreach ($metaData as $groupKey => $group) {
64
            $groupMapping = $group['mapping'];
65
            $groupNode = $xpath->query($groupMapping);
66
            if ($group['values']) {
67
                if ($groupNode->length > 0) {
68
                    foreach ($groupNode as $nodeItem) {
69
                        $domDocument->documentElement->removeChild($nodeItem);
70
                    }
71
                }
72
            } else {
73
                foreach ($groupNode as $nodeItem) {
74
                    $domDocument->documentElement->removeChild($nodeItem);
75
                }
76
            }
77
        }
78
79
        foreach ($metaData['mods'] as $groupKey => $group) {
80
            $groupMapping = $group['mapping'];
81
            $groupChild = null;
82
            //if ($group['values']) {
83
                $parent = $domDocument->childNodes->item(0);
84
                $path = $this->parseXpathString($groupMapping);
85
                foreach ($path as $pathItem) {
86
                    $groupChild = $domDocument->createElement($pathItem['node']);
87
                    foreach ($pathItem['attributes'] as $attrName => $attrValue) {
88
                        $attributeElement = $domDocument->createAttribute($attrName);
89
                        $attributeElement->nodeValue = $attrValue;
90
                        $groupChild->appendChild($attributeElement);
91
                    }
92
                    $parent->appendChild($groupChild);
93
                    $parent = $groupChild;
94
                }
95
96
                if ($groupChild) {
97
                    if ($group['values']) {
98
                        foreach ($group['values'] as $fieldKey => $field) {
99
                            $parent = $groupChild;
100
                            $path = $this->parseXpathString($field['mapping']);
101
                            foreach ($path as $pathItem) {
102
                                $child = $domDocument->createElement($pathItem['node']);
103
                                foreach ($pathItem['attributes'] as $attrName => $attrValue) {
104
                                    $attributeElement = $domDocument->createAttribute($attrName);
105
                                    $attributeElement->nodeValue = $attrValue;
106
                                    $child->appendChild($attributeElement);
107
                                }
108
                                $parent->appendChild($child);
109
                                $parent = $child;
110
                            }
111
                            if ($field['value']) {
112
                                $child->nodeValue = $field['value'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $child does not seem to be defined for all execution paths leading up to this point.
Loading history...
113
                            }
114
115
                        }
116
                    }
117
                }
118
            //}
119
        }
120
121
        $xmlData = $domDocument->saveXML();
122
        $document->setXmlData($xmlData);
123
124
        return $document;
125
    }
126
127
    /**
128
     * Creates a document from the given json data
129
     *
130
     * @param string $jsonData
131
     * @return Document $document
132
     */
133
    public function getDocument($jsonData)
134
    {
135
        $jsonObject = new JsonObject($jsonData);
136
        $publicationType = $jsonObject->get('$.publicationType');
137
138
        if ($publicationType && is_array($publicationType)) {
139
            $publicationType = $publicationType[0];
140
        }
141
142
        $documentType = $this->documentTypeRepository->findOneByName($publicationType);
0 ignored issues
show
Bug introduced by
The method findOneByName() does not exist on EWW\Dpf\Domain\Repository\DocumentTypeRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

142
        /** @scrutinizer ignore-call */ 
143
        $documentType = $this->documentTypeRepository->findOneByName($publicationType);
Loading history...
143
        if (!$documentType) {
144
            return null;
145
        }
146
147
        /** @var Document $document */
148
        $document = $this->objectManager->get(Document::class);
149
150
        $document->setDocumentType($documentType);
151
152
        $processNumberGenerator = $this->objectManager->get(ProcessNumberGenerator::class);
153
        $processNumber = $processNumberGenerator->getProcessNumber();
154
        $document->setProcessNumber($processNumber);
155
156
        $metaData = $this->getMetadataFromJson($jsonData);
157
158
        $exporter = new \EWW\Dpf\Services\ParserGenerator();
159
160
        $documentData['documentUid'] = 0;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$documentData was never initialized. Although not strictly required by PHP, it is generally a good practice to add $documentData = array(); before regardless.
Loading history...
161
        $documentData['metadata']    = $metaData;
162
        $documentData['files']       = array();
163
164
        $exporter->buildXmlFromForm($documentData);
165
166
        $internalXml = $exporter->getXMLData();
167
        $document->setXmlData($internalXml);
168
169
        $internalFormat = new \EWW\Dpf\Helper\InternalFormat($internalXml);
170
171
        $document->setTitle($internalFormat->getTitle());
172
        $document->setAuthors($internalFormat->getAuthors());
173
        $document->setDateIssued($internalFormat->getDateIssued());
174
        //$document->setEmbargoDate($formMetaData['embargo']);
175
176
        $internalFormat->setDocumentType($documentType->getName());
0 ignored issues
show
Bug introduced by
The method getName() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

176
        $internalFormat->setDocumentType($documentType->/** @scrutinizer ignore-call */ getName());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
177
        $internalFormat->setProcessNumber($document->getProcessNumber());
178
179
        $document->setXmlData($internalFormat->getXml());
180
181
        $document->setState(\EWW\Dpf\Domain\Workflow\DocumentWorkflow::STATE_REGISTERED_NONE);
182
183
        return $document;
184
    }
185
186
187
    public function getMetadataFromJson($jsonData, $documentType = null)
188
    {
189
        $jsonData = empty($jsonData)? null: $jsonData;
190
        $jsonObject = new JsonObject($jsonData);
191
192
        if ($documentType) {
193
            $publicationType = $documentType;
0 ignored issues
show
Unused Code introduced by
The assignment to $publicationType is dead and can be removed.
Loading history...
194
        } else {
195
            $publicationType = $jsonObject->get('$.publicationType');
196
            if ($publicationType && is_array($publicationType)) {
197
                $publicationType = $publicationType[0];
198
            }
199
200
            /** @var \EWW\Dpf\Domain\Model\DocumentType $documentType */
201
            $documentType = $this->documentTypeRepository->findOneByName($publicationType);
202
        }
203
204
        $resultData = [];
205
206
        if (empty($documentType)) {
207
            // default type
208
            $documentType = $this->documentTypeRepository->findOneByName('article');
209
        }
210
211
        foreach ($documentType->getMetadataPage() as $metadataPage) {
212
213
            foreach ($metadataPage->getMetadataGroup() as $metadataGroup) {
214
215
                // Group mapping
216
                $jsonDataObject = new JsonObject($jsonData);
217
                $jsonGroupMapping = $metadataGroup->getJsonMapping();
218
                $groupItems = [];
219
                if ($jsonGroupMapping) {
220
                    $groupItems = $jsonDataObject->get($jsonGroupMapping);
221
                }
222
223
                if (empty($groupItems)) {
224
                    $groupItems = [];
225
                }
226
227
                foreach ($groupItems as $groupItem) {
228
229
                    $resultGroup = [
230
                        'attributes' => [],
231
                        'values' => []
232
                    ];
233
                    $resultGroup['mapping'] = $metadataGroup->getRelativeMapping();
234
                    $resultGroup['modsExtensionMapping'] = $metadataGroup->getRelativeModsExtensionMapping();
235
                    $resultGroup['modsExtensionReference'] = trim($metadataGroup->getModsExtensionReference(), " /");
236
                    $resultGroup['groupUid'] = $metadataGroup->getUid();
237
238
                    foreach ($metadataGroup->getMetadataObject() as $metadataObject) {
239
240
                        $json = json_encode($groupItem);
241
242
                        $jsonObject = new JsonObject($json);
243
244
                        $fieldItems = [];
245
                        $jsonFieldMapping = $metadataObject->getJsonMapping();
246
247
                        if ($jsonFieldMapping) {
248
                            $fieldItems = $jsonObject->get($jsonFieldMapping);
249
                            if (empty($fieldItems)) {
250
                                $fieldItems = [];
251
                            }
252
                        }
253
254
                        foreach ($fieldItems as $fieldItem) {
255
                            $resultField = [];
256
257
                            if (!is_array($fieldItem)) {
258
                                $value = $fieldItem;
259
                            } else {
260
                                $value = implode("; ", $fieldItem);
261
                            }
262
263
                            if ($metadataObject->getDataType() == \EWW\Dpf\Domain\Model\MetadataObject::INPUT_DATA_TYPE_DATE) {
264
                                $date = date_create_from_format('d.m.Y', trim($value));
265
                                if ($date) {
266
                                    $value = date_format($date, 'Y-m-d');
267
                                }
268
                            }
269
270
                            //if ($value) {
271
                                $value = str_replace('"', "'", $value);
272
                                $fieldMapping = $metadataObject->getRelativeMapping();
273
                                $resultField['modsExtension'] = $metadataObject->getModsExtension();
274
                                $resultField['mapping'] = $fieldMapping;
275
                                $resultField['value']   = $value;
276
277
                                if (strpos($fieldMapping, "@") === 0) {
278
                                    $resultGroup['attributes'][] = $resultField;
279
                                } else {
280
                                    $resultGroup['values'][] = $resultField;
281
                                }
282
                            //}
283
                        }
284
                    }
285
286
                    $resultData[] = $resultGroup;;
287
                }
288
289
            }
290
        }
291
292
        return $resultData;
293
    }
294
295
    protected function parseXpathString($xpathString)
296
    {
297
        $result = [];
298
299
        $regex = '/[a-zA-Z:]+|[<=>]|[@][a-zA-Z][a-zA-Z0-9_\-\:\.]*|\[|\'.*?\'|".*?"|\]|\//';
300
        preg_match_all($regex, $xpathString, $matches);
301
        $path = [];
302
        $i = 0;
303
        foreach ($matches[0] as $item) {
304
            if ($item != "/") {
305
                $path[$i] .= $item;
306
            } else {
307
                $i++;
308
            }
309
        }
310
311
        foreach ($path as $key => $pathItem) {
312
            $nodeName = explode("[", $pathItem);
313
            $result[$key]["node"] = $nodeName[0];
314
            if (preg_match_all("/\[@(.*?)\]/", $pathItem, $match)) {
315
                foreach ($match[1] as $attr) {
316
                    list($attrName, $attrValue) = explode("=", $attr);
317
                    $result[$key]["attributes"][$attrName] = trim($attrValue, '"');
318
                }
319
            } else {
320
                $result[$key]["attributes"] = [];
321
            }
322
        }
323
324
        return $result;
325
    }
326
327
}
328