XmlAccessor::getChild()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 8
c 1
b 0
f 0
nc 2
nop 3
dl 0
loc 16
ccs 8
cts 8
cp 1
crap 2
rs 10
1
<?php
2
3
/**
4
 * Copyright MediaCT. All rights reserved.
5
 * https://www.mediact.nl
6
 */
7
8
declare(strict_types=1);
9
10
namespace Mediact\CodingStandard\PhpStorm;
11
12
use InvalidArgumentException;
13
use SimpleXMLElement;
14
15
class XmlAccessor implements XmlAccessorInterface
16
{
17
    /**
18
     * Get a child node, create it when it does not exist.
19
     *
20
     * @param SimpleXMLElement $element
21
     * @param string           $name
22
     * @param array            $attributes
23
     *
24
     * @return SimpleXMLElement
25
     */
26 2
    public function getChild(
27
        SimpleXMLElement $element,
28
        string $name,
29
        array $attributes = []
30
    ): SimpleXMLElement {
31 2
        $xpath = $name . $this->getAttributesXpath($attributes);
32
33 2
        $result = $element->xpath($xpath);
34 2
        if (empty($result)) {
35 1
            $node = $element->addChild($name);
36 1
            $this->setAttributes($node, $attributes);
37
        } else {
38 1
            $node = reset($result);
39
        }
40
41 2
        return $node;
42
    }
43
44
    /**
45
     * Get a descendant, create it when it does not exist.
46
     *
47
     * @param SimpleXMLElement $element
48
     * @param array            $path
49
     *
50
     * @return SimpleXMLElement
51
     * @throws InvalidArgumentException When the descendant path is invalid.
52
     */
53 2
    public function getDescendant(
54
        SimpleXMLElement $element,
55
        array $path
56
    ): SimpleXMLElement {
57 2
        foreach ($path as $childProperties) {
58
            if (
59 2
                !is_array($childProperties)
60 2
                || empty($childProperties)
61
            ) {
62 1
                throw new InvalidArgumentException('Invalid descendant path');
63
            }
64
65 1
            $name       = array_shift($childProperties);
66 1
            $attributes = count($childProperties)
67 1
                ? array_shift($childProperties)
68 1
                : [];
69
70 1
            $element = $this->getChild($element, $name, $attributes);
71
        }
72
73 1
        return $element;
74
    }
75
76
    /**
77
     * Set the attributes of a node.
78
     *
79
     * @param SimpleXMLElement $element
80
     * @param array            $attributes
81
     *
82
     * @return void
83
     */
84 1
    public function setAttributes(
85
        SimpleXMLElement $element,
86
        array $attributes
87
    ): void {
88 1
        $storage = $element->attributes();
89 1
        foreach ($attributes as $key => $value) {
90 1
            if (isset($storage->{$key})) {
91 1
                $storage->{$key} = $value;
92
            } else {
93 1
                $element->addAttribute($key, $value);
94
            }
95
        }
96 1
    }
97
98
    /**
99
     * Get an xpath for attributes.
100
     *
101
     * @param array $attributes
102
     *
103
     * @return string
104
     */
105 2
    private function getAttributesXpath(array $attributes): string
106
    {
107 2
        $xpath = '';
108 2
        if (!empty($attributes)) {
109 2
            $parts = [];
110 2
            foreach ($attributes as $key => $value) {
111 2
                $parts[] = '@' . $key . '="' . $value . '"';
112
            }
113
114 2
            $xpath .= '[' . implode(' and ', $parts) . ']';
115
        }
116
117 2
        return $xpath;
118
    }
119
}
120