Passed
Pull Request — master (#195)
by
unknown
17:55
created

ParserGenerator::customXPath()   D

Complexity

Conditions 17
Paths 97

Size

Total Lines 186
Code Lines 94

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 17
eloc 94
c 3
b 0
f 0
nc 97
nop 4
dl 0
loc 186
rs 4.3042

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace EWW\Dpf\Services;
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\Configuration\ClientConfigurationManager;
18
use EWW\Dpf\Domain\Repository\DocumentTypeRepository;
19
use EWW\Dpf\Helper\XSLTransformator;
20
use TYPO3\CMS\Extbase\Object\ObjectManager;
21
use EWW\Dpf\Services\Transformer\DocumentTransformer;
22
23
/**
24
 * ParserGenerator
25
 */
26
class ParserGenerator
27
{
28
    /**
29
     * clientConfigurationManager
30
     *
31
     * @var \EWW\Dpf\Configuration\ClientConfigurationManager
32
     * @inject
33
     */
34
    protected $clientConfigurationManager;
35
36
    /**
37
     * documentTypeRepository
38
     *
39
     * @var \EWW\Dpf\Domain\Repository\DocumentTypeRepository
40
     */
41
    protected $documentTypeRepository = null;
42
43
    /**
44
     * formData
45
     *
46
     * @var array
47
     */
48
    protected $formData = array();
49
50
    /**
51
     * files from form
52
     * @var array
53
     */
54
    protected $files = array();
55
56
    /**
57
     * metsData
58
     *
59
     * @var  DOMDocument
0 ignored issues
show
Bug introduced by
The type EWW\Dpf\Services\DOMDocument was not found. Did you mean DOMDocument? If so, make sure to prefix the type with \.
Loading history...
60
     */
61
    protected $metsData = '';
62
63
    /**
64
     * xml data
65
     * @var DOMDocument
66
     */
67
    protected $xmlData = '';
68
69
    /**
70
     * xml header
71
     * @var string
72
     */
73
    protected $xmlHeader = '';
74
75
    /**
76
     * xPathXMLGenerator
77
     * @var object
78
     */
79
    protected $parser = null;
80
81
    /**
82
     * ref id counter
83
     */
84
    protected $counter = 0;
85
86
    /**
87
     * namespaces as string
88
     * @var string
89
     */
90
    protected $namespaceString = '';
91
92
93
    /**
94
     * Constructor
95
     */
96
    public function __construct()
97
    {
98
        $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class);
99
        $this->clientConfigurationManager = $objectManager->get(ClientConfigurationManager::class);
100
101
        $this->documentTypeRepository = $objectManager->get(DocumentTypeRepository::class);
102
103
        $namespaceConfigurationString = $this->clientConfigurationManager->getNamespaces();
104
        if (!empty($namespaceConfigurationString)) {
105
                        $namespaceConfiguration = explode(";", $namespaceConfigurationString);
106
                        foreach ($namespaceConfiguration as $value) {
107
                                $namespace = explode("=", $value);
108
                                $this->namespaceString .= ' xmlns:' . $namespace[0] . '="' . $namespace[1] . '"';
109
                            }
110
         }
111
112
        $this->xmlHeader = '<data' . $this->namespaceString . '></data>';
113
114
        $this->xmlData =  new \DOMDocument();
0 ignored issues
show
Documentation Bug introduced by
It seems like new DOMDocument() of type DOMDocument is incompatible with the declared type EWW\Dpf\Services\DOMDocument of property $xmlData.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
115
        $this->xmlData->loadXML($this->xmlHeader);
116
117
        // Parser
118
        include_once 'XPathXMLGenerator.php';
119
120
        $this->parser = new XPathXMLGenerator();
121
    }
122
123
    /**
124
     * returns the mods xml string
125
     * @return string mods xml
126
     */
127
    public function getXMLData()
128
    {
129
        $xml = $this->xmlData->saveXML();
130
        $xml = preg_replace("/eww=\"\d-\d-\d\"/", '${1}${2}${3}', $xml);
131
132
        return $xml;
133
    }
134
135
    public function transformInputXML($xml)
136
    {
137
        $XSLTransformator = new XSLTransformator();
138
        return $XSLTransformator->transformInputXML($xml);
139
    }
140
141
    /**
142
     * @param $document
143
     * @return string The transformed xml
144
     */
145
    public function getTransformedOutputXML($document)
146
    {
147
        $XSLTransformator = new XSLTransformator();
148
        return $XSLTransformator->getTransformedOutputXML($document);
149
    }
150
151
152
    /**
153
     * build mods from form array
154
     * @param array $array structured form data array
155
     */
156
    public function buildXmlFromForm($array)
157
    {
158
        $this->xmlData = $this->xmlData;
159
        // Build xml mods from form fields
160
        // loop each group
161
        foreach ($array['metadata'] as $key => $group) {
162
            //groups
163
            $mapping = $group['mapping'];
164
165
            $values     = $group['values'];
166
            $attributes = $group['attributes'];
167
168
            $attributeXPath     = '';
169
            $extensionAttribute = '';
170
            foreach ($attributes as $attribute) {
171
                if (!$attribute["modsExtension"]) {
172
                    $attributeXPath .= '[' . $attribute['mapping'] . '="' . $attribute['value'] . '"]';
173
                } else {
174
                    $extensionAttribute .= '[' . $attribute['mapping'] . '="' . $attribute['value'] . '"]';
175
                }
176
177
            }
178
179
            // mods extension
180
            if ($group['modsExtensionMapping']) {
181
                $counter = sprintf("%'03d", $this->counter);
182
                $attributeXPath .= '[@ID="QUCOSA_' . $counter . '"]';
183
            }
184
185
            $existsExtensionFlag = false;
186
            $i                   = 0;
187
            // loop each object
188
            if (!empty($values)) {
189
                foreach ($values as $value) {
190
191
                    if ($value['modsExtension']) {
192
                        $existsExtensionFlag = true;
193
                        // mods extension
194
                        $counter            = sprintf("%'03d", $this->counter);
195
                        $referenceAttribute = $extensionAttribute . '[@' . $group['modsExtensionReference'] . '="QUCOSA_' . $counter . '"]';
196
197
                        $path = $group['modsExtensionMapping'] . $referenceAttribute . '%/' . $value['mapping'];
198
199
                        $xml = $this->customXPath($path, false, $value['value']);
0 ignored issues
show
Unused Code introduced by
The assignment to $xml is dead and can be removed.
Loading history...
Bug introduced by
$path of type string is incompatible with the type EWW\Dpf\Services\xpath expected by parameter $xPath of EWW\Dpf\Services\ParserGenerator::customXPath(). ( Ignorable by Annotation )

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

199
                        $xml = $this->customXPath(/** @scrutinizer ignore-type */ $path, false, $value['value']);
Loading history...
200
                    } else {
201
                        $path = $mapping . $attributeXPath . '%/' . $value['mapping'];
202
203
                        if ($i == 0) {
204
                            $newGroupFlag = true;
205
                        } else {
206
                            $newGroupFlag = false;
207
                        }
208
209
                    $this->customXPath($path, $newGroupFlag, $value['value']);
210
                    $i++;
211
212
                    }
213
214
                }
215
            } else {
216
                if (!empty($attributeXPath)) {
217
                    $path = $mapping . $attributeXPath;
218
                    $this->customXPath($path, true, '', true);
219
                }
220
            }
221
            if (!$existsExtensionFlag && $group['modsExtensionMapping']) {
222
                $xPath = $group['modsExtensionMapping'] . $extensionAttribute . '[@' . $group['modsExtensionReference'] . '="QUCOSA_' . $counter . '"]';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $counter does not seem to be defined for all execution paths leading up to this point.
Loading history...
223
                $xml   = $this->customXPath($xPath, true, '', true);
224
            }
225
            if ($group['modsExtensionMapping']) {
226
                $this->counter++;
227
            }
228
        }
229
230
        $this->files = $array['files'];
231
    }
232
233
    /**
234
     * get xml from xpath
235
     * @param  xpath $xPath xPath expression
236
     * @return xml
0 ignored issues
show
Bug introduced by
The type EWW\Dpf\Services\xml was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
237
     */
238
    public function parseXPath($xPath)
239
    {
240
241
        $this->parser->generateXmlFromXPath($xPath);
242
        $xml = $this->parser->getXML();
243
244
        return $xml;
245
    }
246
247
    public function parseXPathWrapped($xPath)
248
    {
249
        $this->parser->generateXmlFromXPath($xPath);
250
        $xml = $this->parser->getXML();
251
252
        $xml = '<data' . $this->namespaceString . '>' . $xml . '</data>';
253
254
        return $xml;
255
    }
256
257
    /**
258
     * Customized xPath parser
259
     * @param  xpath  $xPath xpath expression
260
     * @param  string $value form value
261
     * @return xml    created xml
262
     */
263
    public function customXPath($xPath, $newGroupFlag = false, $value = '', $attributeOnly = false)
264
    {
265
        if (!$attributeOnly) {
266
            // Explode xPath
267
            $newPath = explode('%', $xPath);
268
269
            $praedicateFlag = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $praedicateFlag is dead and can be removed.
Loading history...
270
            $explodedXPath  = explode('[', $newPath[0]);
271
            if (count($explodedXPath) > 1) {
272
                // praedicate is given
273
                if (substr($explodedXPath[1], 0, 1) == "@") {
274
                    // attribute
275
                    $path = $newPath[0];
276
                } else {
277
                    // path
278
                    $path = $explodedXPath[0];
279
                }
280
281
                $praedicateFlag = true;
282
            } else {
283
                $path = $newPath[0];
284
            }
285
286
            if (!empty($value)) {
287
                $newPath[1] = $newPath[1] . '="' . $value . '"';
288
            }
289
290
            $modsDataXPath = \EWW\Dpf\Helper\XPath::create($this->xmlData);
291
292
            if (!$newGroupFlag && $modsDataXPath->query('/data/' . $newPath[0])->length > 0) {
293
                // first xpath path exist
294
295
                // build xml from second xpath part
296
                $xml = $this->parseXPath($newPath[1]);
297
298
                // check if xpath [] are nested
299
                $search = '/(\/\w*:\w*)\[(.*)\]/';
300
                preg_match($search, $newPath[1], $match);
301
                preg_match($search, $match[2], $secondMatch);
302
                // first part nested xpath
303
                if ($match[2] && $secondMatch[2]) {
304
                    $nested = $match[2];
305
306
                    $nestedXml = $this->parseXPath($nested);
307
308
                    // object xpath without nested element []
309
                    $newPath[1] = str_replace('['.$match[2].']', '', $newPath[1]);
310
311
                    $xml = $this->parseXPath($newPath[1]);
312
313
                }
314
315
                // FIXME: XPATHXmlGenerator XPATH does not generate any namespaces,
316
                // which DOMDocument cannot cope with. Actually, namespaces should not be necessary here,
317
                // since it is about child elements that are then added to the overall XML.
318
                libxml_use_internal_errors(true);
319
                $docXML = new \DOMDocument();
320
                $docXML->loadXML($xml);
321
                libxml_use_internal_errors(false);
322
323
                $domXPath = \EWW\Dpf\Helper\XPath::create($this->xmlData);
324
325
                // second part nested xpath
326
                if ($match[2] && $secondMatch[2]) {
327
328
                    // import node from nested
329
                    // FIXME: XPATHXmlGenerator XPATH does not generate any namespaces,
330
                    // which DOMDocument cannot cope with. Actually, namespaces should not be necessary here,
331
                    // since it is about child elements that are then added to the overall XML.
332
                    libxml_use_internal_errors(true);
333
                    $docXMLNested = new \DOMDocument();
334
                    $docXMLNested->loadXML($nestedXml);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $nestedXml does not seem to be defined for all execution paths leading up to this point.
Loading history...
335
                    libxml_use_internal_errors(false);
336
337
                    $xPath = \EWW\Dpf\Helper\XPath::create($docXML);
338
339
                    $nodeList = $xPath->query($match[1]);
340
                    $node = $nodeList->item(0);
341
342
                    $importNode = $docXML->importNode($docXMLNested->getElementsByTagName("mods")->item(0)->firstChild, true);
0 ignored issues
show
Bug introduced by
It seems like $docXMLNested->getElemen...')->item(0)->firstChild can also be of type null; however, parameter $node of DOMDocument::importNode() does only seem to accept DOMNode, maybe add an additional type check? ( Ignorable by Annotation )

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

342
                    $importNode = $docXML->importNode(/** @scrutinizer ignore-type */ $docXMLNested->getElementsByTagName("mods")->item(0)->firstChild, true);
Loading history...
343
344
                    $node->appendChild($importNode);
345
                }
346
347
                $domNode = $domXPath->query('/data/' . $path);
348
                $node = $docXML->documentElement;
349
350
                $nodeAppendModsData = $this->xmlData->importNode($node, true);
351
                $domNode->item($domNode->length - 1)->appendChild($nodeAppendModsData);
352
            } else {
353
                // first xpath doesn't exist
354
                // parse first xpath part
355
                $xml1 = $this->parseXPathWrapped($newPath[0]);
356
357
                $doc1 = new \DOMDocument();
358
                $doc1->loadXML($xml1);
359
360
                $domXPath = \EWW\Dpf\Helper\XPath::create($doc1);
361
362
                $domNode = $domXPath->query('//' . $path);
363
364
                // parse second xpath part
365
                $xml2 = $this->parseXPathWrapped($path . $newPath[1]);
366
367
                // check if xpath [] are nested
368
                $search = '/(\/\w*:?\w*)\[(.*)\]/';
369
                preg_match($search, $newPath[1], $match);
370
                preg_match($search, $match[2], $secondMatch);
371
372
                // first part nested xpath
373
                if ($match[2] && $secondMatch[2]) {
374
                    $nested = $match[2];
375
376
                    $nestedXml = $this->parseXPathWrapped($nested);
377
378
                    // object xpath without nested element []
379
                    $newPath[1] = str_replace('['.$match[2].']', '', $newPath[1]);
380
381
                    $xml2 = $this->parseXPathWrapped($path . $newPath[1]);
382
                }
383
384
                $doc2 = new \DOMDocument();
385
                $doc2->loadXML($xml2);
386
387
                $domXPath2 = \EWW\Dpf\Helper\XPath::create($doc2);
388
389
                  // second part nested xpath
390
                if ($match[2] && $secondMatch[2]) {
391
                    // import node from nested
392
                    $docXMLNested = new \DOMDocument();
393
                    $docXMLNested->loadXML($nestedXml);
394
395
                    $xPath = \EWW\Dpf\Helper\XPath::create($doc2);
396
                    $nodeList = $xPath->query('//' . $path . $match[1]);
397
                    $node = $nodeList->item(0);
398
399
                    $importNode = $doc2->importNode($docXMLNested->documentElement, true);
400
401
                    $node->appendChild($importNode);
402
                }
403
                $domNode2 = $domXPath2->query('//' . $path)->item(0)->childNodes->item(0);
404
405
                // merge xml nodes
406
                $nodeToBeAppended = $doc1->importNode($domNode2, true);
407
                $domNode->item(0)->appendChild($nodeToBeAppended);
408
409
                // add to modsData (merge not required)
410
                // get mods tag
411
                foreach ($this->xmlData->childNodes as $childNode) {
412
                    // Skip comments inside the xml.
413
                    if ($childNode instanceof \DOMElement) {
414
                        $firstChild = $childNode;
415
                        break;
416
                    }
417
                }
418
                //$firstChild = $this->xmlData->childNodes->item(0);
419
                $firstItem = $doc1->documentElement->firstChild;
420
                $nodeAppendModsData = $this->xmlData->importNode($firstItem, true);
421
                $firstChild->appendChild($nodeAppendModsData);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $firstChild does not seem to be defined for all execution paths leading up to this point.
Loading history...
422
423
                return $doc1->saveXML();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $doc1->saveXML() returns the type string which is incompatible with the documented return type EWW\Dpf\Services\xml.
Loading history...
424
            }
425
        } else {
426
            // attribute only
427
            $xml = $this->parseXPath($xPath);
428
429
            // FIXME: XPATHXmlGenerator XPATH does not generate any namespaces,
430
            // which DOMDocument cannot cope with. Actually, namespaces should not be necessary here,
431
            // since it is about child elements that are then added to the overall XML.
432
            libxml_use_internal_errors(true);
433
            $docXML = new \DOMDocument();
434
            $docXML->loadXML($xml);
435
            libxml_use_internal_errors(false);
436
437
            $domXPath = \EWW\Dpf\Helper\XPath::create($this->xmlData);
438
            $domNode  = $domXPath->query('/data');
439
440
            $node = $docXML->documentElement;
441
442
            $nodeAppendModsData = $this->xmlData->importNode($node, true);
443
            $domNode->item($domNode->length - 1)->appendChild($nodeAppendModsData);
444
445
            return $docXML->saveXML();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $docXML->saveXML() returns the type string which is incompatible with the documented return type EWW\Dpf\Services\xml.
Loading history...
446
        }
447
448
        return $this->xmlData->saveXML();
449
    }
450
451
    public function setXML($value = '') {
452
        $domDocument = new \DOMDocument();
453
        if (is_null(@$domDocument->loadXML($value))) {
454
            throw new \Exception("Couldn't load MODS data");
455
        }
456
        $this->xmlData = $domDocument;
0 ignored issues
show
Documentation Bug introduced by
It seems like $domDocument of type DOMDocument is incompatible with the declared type EWW\Dpf\Services\DOMDocument of property $xmlData.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
457
    }
458
459
    /**
460
     * sets the file data and generates file xml
461
     * @param string $value
462
     */
463
    public function setFileData($value = '')
464
    {
465
        $this->files = $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like $value of type string is incompatible with the declared type array of property $files.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
466
        $this->generateFileXML();
467
    }
468
469
    /**
470
     * generates the internal xml format for files
471
     */
472
    public function generateFileXML() {
473
474
        $fileXpathConfiguration = $this->clientConfigurationManager->getFileXpath();
475
476
        foreach ($this->files as $key => $fileGrp) {
477
            foreach ($fileGrp as $file) {
478
479
                $this->customXPath($fileXpathConfiguration . '/href', true, $file["path"]);
0 ignored issues
show
Bug introduced by
$fileXpathConfiguration . '/href' of type string is incompatible with the type EWW\Dpf\Services\xpath expected by parameter $xPath of EWW\Dpf\Services\ParserGenerator::customXPath(). ( Ignorable by Annotation )

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

479
                $this->customXPath(/** @scrutinizer ignore-type */ $fileXpathConfiguration . '/href', true, $file["path"]);
Loading history...
480
                $this->customXPath($fileXpathConfiguration . '%mimetype', false, $file["type"]);
481
                $this->customXPath($fileXpathConfiguration . '%title', false, $file["title"]);
482
                $this->customXPath($fileXpathConfiguration . '%download', false, $file["download"]);
483
                $this->customXPath($fileXpathConfiguration . '%archive', false, $file["archive"]);
484
                $this->customXPath($fileXpathConfiguration . '%use', false, $file["use"]);
485
                $this->customXPath($fileXpathConfiguration . '%id', false, $file["id"]);
486
                $this->customXPath($fileXpathConfiguration . '%hasFLocat', false, $file["hasFLocat"]);
487
488
            }
489
        }
490
    }
491
492
}
493