Passed
Pull Request — master (#21)
by Jaime Pérez
02:09
created

XPath::setNamespaces()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XMLSecurity\XML\ds;
6
7
use DOMElement;
8
use SimpleSAML\XML\Exception\InvalidDOMElementException;
9
use Webmozart\Assert\Assert;
10
11
/**
12
 * Class implementing the XPath element.
13
 *
14
 * @package simplesamlphp/xml-security
15
 */
16
class XPath extends AbstractDsElement
17
{
18
    /**
19
     * The XPath expression.
20
     *
21
     * @var string
22
     */
23
    protected string $expression;
24
25
    /**
26
     * A key-value array with namespaces, indexed by the prefixes used in the XPath expression.
27
     *
28
     * @var string[]
29
     */
30
    protected array $namespaces = [];
31
32
33
    /**
34
     * Construct an XPath element.
35
     *
36
     * @param string $expression The XPath expression itself.
37
     * @param string[] $namespaces A key - value array with namespace definitions.
38
     */
39
    public function __construct(string $expression, array $namespaces = null)
40
    {
41
        $this->setExpression($expression);
42
        $this->setNamespaces($namespaces);
43
    }
44
45
46
    /**
47
     * Get the actual XPath expression.
48
     *
49
     * @return string
50
     */
51
    public function getExpression(): string
52
    {
53
        return $this->expression;
54
    }
55
56
57
    /**
58
     * Set the xpath expression itself.
59
     *
60
     * @param string $expression
61
     */
62
    private function setExpression(string $expression): void
63
    {
64
        $this->expression = $expression;
65
    }
66
67
68
    /**
69
     * Get the list of namespaces used in this XPath expression, with their corresponding prefix as
70
     * the keys of each element in the array.
71
     *
72
     * @return string[]
73
     */
74
    public function getNamespaces(): array
75
    {
76
        return $this->namespaces;
77
    }
78
79
80
    /**
81
     * Set the list of namespaces used in this XPath expression.
82
     *
83
     * @param string[] $namespaces
84
     */
85
    private function setNamespaces(?array $namespaces): void
86
    {
87
        if ($namespaces === null) {
0 ignored issues
show
introduced by
The condition $namespaces === null is always false.
Loading history...
88
            return;
89
        }
90
        Assert::allString($namespaces);
91
        Assert::allString(array_keys($namespaces));
92
        $this->namespaces = $namespaces;
93
    }
94
95
96
    /**
97
     * Convert XML into a class instance
98
     *
99
     * @param DOMElement $xml
100
     * @return self
101
     *
102
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
103
     *   If the qualified name of the supplied element is wrong
104
     */
105
    public static function fromXML(DOMElement $xml): object
106
    {
107
        Assert::same($xml->localName, 'XPath', InvalidDOMElementException::class);
108
        Assert::same($xml->namespaceURI, self::NS, InvalidDOMElementException::class);
109
110
        $namespaces = [];
111
        $xpath = new \DOMXPath($xml->ownerDocument);
0 ignored issues
show
Bug introduced by
It seems like $xml->ownerDocument can also be of type null; however, parameter $document of DOMXPath::__construct() does only seem to accept DOMDocument, 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

111
        $xpath = new \DOMXPath(/** @scrutinizer ignore-type */ $xml->ownerDocument);
Loading history...
112
        /** @var \DOMNode $ns */
113
        foreach ($xpath->query('namespace::*', $xml) as $ns) {
114
            if ($xml->getAttributeNode($ns->nodeName)) {
115
                $namespaces[str_replace('xmlns:', '', $ns->nodeName)] =
116
                    $xml->getAttribute($ns->nodeName);
117
            }
118
        }
119
120
        return new self($xml->textContent, $namespaces);
121
    }
122
123
124
    /**
125
     * @param DOMElement|null $parent
126
     * @return DOMElement
127
     */
128
    public function toXML(DOMElement $parent = null): DOMElement
129
    {
130
        $e = $this->instantiateParentElement($parent);
131
        $e->textContent = $this->expression;
132
133
        foreach ($this->namespaces as $prefix => $namespace) {
134
            $e->setAttribute('xmlns:' . $prefix, $namespace);
135
        }
136
        return $e;
137
    }
138
}