AbstractSamlModel::oneElementFromXml()   B
last analyzed

Complexity

Conditions 7
Paths 20

Size

Total Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 9.5839

Importance

Changes 0
Metric Value
dl 0
loc 39
c 0
b 0
f 0
ccs 15
cts 24
cp 0.625
rs 8.3626
cc 7
nc 20
nop 5
crap 9.5839
1
<?php
2
3
/*
4
 * This file is part of the LightSAML-Core package.
5
 *
6
 * (c) Milos Tomic <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace LightSaml\Model;
13
14
use LightSaml\Error\LightSamlXmlException;
15
use LightSaml\Model\Context\DeserializationContext;
16
use LightSaml\Model\Context\SerializationContext;
17
18
abstract class AbstractSamlModel implements SamlElementInterface
19
{
20
    /**
21
     * @param string               $name
22
     * @param null|string          $namespace
23
     * @param \DOMNode             $parent
24
     * @param SerializationContext $context
25
     *
26
     * @return \DOMElement
27
     */
28 27
    protected function createElement($name, $namespace, \DOMNode $parent, SerializationContext $context)
29
    {
30 27
        if ($namespace) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $namespace of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
31 27
            $result = $context->getDocument()->createElementNS($namespace, $name);
32
        } else {
33
            $result = $context->getDocument()->createElement($name);
34
        }
35 27
        $parent->appendChild($result);
36
37 27
        return $result;
38
    }
39
40
    /**
41
     * @param string               $name
42
     * @param \DOMNode             $parent
43
     * @param SerializationContext $context
44
     * @param string|null          $namespace
45
     *
46
     * @throws \LogicException
47
     */
48 27
    private function oneElementToXml($name, \DOMNode $parent, SerializationContext $context, $namespace = null)
49
    {
50 27
        $value = $this->getPropertyValue($name);
51 27
        if (null == $value) {
52 26
            return;
53
        }
54 21
        if ($value instanceof SamlElementInterface) {
55 20
            $value->serialize($parent, $context);
56 10
        } elseif (is_string($value)) {
57 10
            if ($namespace) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $namespace of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
58 10
                $node = $context->getDocument()->createElementNS($namespace, $name, $value);
59
            } else {
60
                $node = $context->getDocument()->createElement($name, $value);
61
            }
62 10
            $parent->appendChild($node);
63
        } else {
64
            throw new \LogicException(sprintf("Element '%s' must implement SamlElementInterface or be a string", $name));
65
        }
66 21
    }
67
68
    /**
69
     * @param array|string[]       $names
70
     * @param \DOMNode             $parent
71
     * @param SerializationContext $context
72
     * @param string|null          $namespace
73
     */
74 27
    protected function singleElementsToXml(array $names, \DOMNode $parent, SerializationContext $context, $namespace = null)
75
    {
76 27
        foreach ($names as $name) {
77 27
            $this->oneElementToXml($name, $parent, $context, $namespace);
78
        }
79 27
    }
80
81
    /**
82
     * @param array|null           $value
83
     * @param \DOMNode             $node
84
     * @param SerializationContext $context
85
     * @param null|string          $nodeName
86
     * @param null|string          $namespaceUri
87
     *
88
     * @throws \LogicException
89
     */
90 13
    protected function manyElementsToXml($value, \DOMNode $node, SerializationContext $context, $nodeName = null, $namespaceUri = null)
91
    {
92 13
        if (false == $value) {
93 13
            return;
94
        }
95
96 10
        if (false == is_array($value)) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
97
            throw new \LogicException('value must be array or null');
98
        }
99
100 10
        foreach ($value as $object) {
101 10
            if ($object instanceof SamlElementInterface) {
102 10
                if ($nodeName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nodeName of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
103
                    throw new \LogicException('nodeName should not be specified when serializing array of SamlElementInterface');
104
                }
105 10
                $object->serialize($node, $context);
106 6
            } elseif ($nodeName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nodeName of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
107 6
                if ($namespaceUri) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $namespaceUri of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
108 6
                    $child = $context->getDocument()->createElementNS($namespaceUri, $nodeName, (string) $object);
109
                } else {
110
                    $child = $context->getDocument()->createElement($nodeName, (string) $object);
111
                }
112 6
                $node->appendChild($child);
113
            } else {
114 10
                throw new \LogicException('Can handle only array of AbstractSamlModel or strings with nodeName parameter specified');
115
            }
116
        }
117 10
    }
118
119
    /**
120
     * @param \DOMElement            $node
121
     * @param DeserializationContext $context
122
     * @param string                 $nodeName
123
     * @param string|null            $namespacePrefix
124
     * @param string                 $class
125
     * @param string                 $methodName
126
     *
127
     * @throws \LogicException
128
     */
129 47
    protected function manyElementsFromXml(\DOMElement $node, DeserializationContext $context, $nodeName, $namespacePrefix, $class, $methodName)
130
    {
131 47
        if ($namespacePrefix) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $namespacePrefix of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
132 47
            $query = sprintf('%s:%s', $namespacePrefix, $nodeName);
133
        } else {
134
            $query = sprintf('%s', $nodeName);
135
        }
136
137 47
        foreach ($context->getXpath()->query($query, $node) as $xml) {
138
            /* @var \DOMElement $xml */
139 44
            if ($class) {
140
                /** @var SamlElementInterface $object */
141 44
                $object = new $class();
142 44
                if (false == $object instanceof SamlElementInterface) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
143
                    throw new \LogicException(sprintf("Node '%s' class '%s' must implement SamlElementInterface", $nodeName, $class));
144
                }
145 44
                $object->deserialize($xml, $context);
146 44
                $this->{$methodName}($object);
147
            } else {
148 34
                $object = $xml->textContent;
149 44
                $this->{$methodName}($object);
150
            }
151
        }
152 47
    }
153
154
    /**
155
     * @param string      $name
156
     * @param \DOMElement $element
157
     *
158
     * @throws \LogicException
159
     *
160
     * @return bool True if property value is not empty and attribute was set to the element
161
     */
162 27
    protected function singleAttributeToXml($name, \DOMElement $element)
163
    {
164 27
        $value = $this->getPropertyValue($name);
165 27
        if (null !== $value && '' !== $value) {
166 27
            if (is_bool($value)) {
167 1
                $element->setAttribute($name, $value ? 'true' : 'false');
168
            } else {
169 27
                $element->setAttribute($name, $value);
170
            }
171
172 27
            return true;
173
        }
174
175 27
        return false;
176
    }
177
178
    /**
179
     * @param array|string[] $names
180
     * @param \DOMElement    $element
181
     */
182 27
    protected function attributesToXml(array $names, \DOMElement $element)
183
    {
184 27
        foreach ($names as $name) {
185 27
            $this->singleAttributeToXml($name, $element);
186
        }
187 27
    }
188
189
    /**
190
     * @param \DOMNode $node
191
     * @param string   $expectedName
192
     * @param string   $expectedNamespaceUri
193
     */
194 64
    protected function checkXmlNodeName(\DOMNode &$node, $expectedName, $expectedNamespaceUri)
195
    {
196 64
        if ($node instanceof \DOMDocument) {
197 47
            $node = $node->firstChild;
198
        }
199 64
        while ($node && $node instanceof \DOMComment) {
200 2
            $node = $node->nextSibling;
201
        }
202 64
        if (null === $node) {
203
            throw new LightSamlXmlException(sprintf(
204
                "Unable to find expected '%s' xml node and '%s' namespace",
205
                $expectedName,
206
                $expectedNamespaceUri
207
            ));
208 64
        } elseif ($node->localName != $expectedName || $node->namespaceURI != $expectedNamespaceUri) {
209 4
            throw new LightSamlXmlException(sprintf(
210 4
                "Expected '%s' xml node and '%s' namespace but got node '%s' and namespace '%s'",
211 4
                $expectedName,
212 4
                $expectedNamespaceUri,
213 4
                $node->localName,
214 4
                $node->namespaceURI
215
            ));
216
        }
217 62
    }
218
219
    /**
220
     * @param \DOMElement $node
221
     * @param string      $attributeName
222
     */
223 62
    protected function singleAttributeFromXml(\DOMElement $node, $attributeName)
224
    {
225 62
        $value = $node->getAttribute($attributeName);
226 62
        if ('' !== $value) {
227 54
            $setter = 'set'.$attributeName;
228 54
            if (method_exists($this, $setter)) {
229 54
                $this->{$setter}($value);
230
            }
231
        }
232 62
    }
233
234
    /**
235
     * @param \DOMElement            $node
236
     * @param DeserializationContext $context
237
     * @param string                 $elementName
238
     * @param string                 $class
239
     * @param string                 $namespacePrefix
240
     *
241
     * @throws \LogicException
242
     */
243 62
    protected function oneElementFromXml(\DOMElement $node, DeserializationContext $context, $elementName, $class, $namespacePrefix)
244
    {
245 62
        if ($namespacePrefix) {
246 62
            $query = sprintf('./%s:%s', $namespacePrefix, $elementName);
247
        } else {
248
            $query = sprintf('./%s', $elementName);
249
        }
250 62
        $arr = $context->getXpath()->query($query, $node);
251 62
        $value = $arr->length > 0 ? $arr->item(0) : null;
252
253 62
        if ($value) {
254 50
            $setter = 'set'.$elementName;
255 50
            if (false == method_exists($this, $setter)) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
256
                throw new \LogicException(sprintf(
257
                    "Unable to find setter for element '%s' in class '%s'",
258
                    $elementName,
259
                    get_class($this)
260
                ));
261
            }
262
263 50
            if ($class) {
264
                /** @var AbstractSamlModel $object */
265 41
                $object = new $class();
266 41
                if (false == $object instanceof \LightSaml\Model\SamlElementInterface) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
267
                    throw new \LogicException(sprintf(
268
                        "Specified class '%s' for element '%s' must implement SamlElementInterface",
269
                        $class,
270
                        $elementName
271
                    ));
272
                }
273
274 41
                $object->deserialize($value, $context);
275
            } else {
276 16
                $object = $value->textContent;
277
            }
278
279 50
            $this->{$setter}($object);
280
        }
281 62
    }
282
283
    /**
284
     * @param \DOMElement            $node
285
     * @param DeserializationContext $context
286
     * @param array                  $options elementName=>class
287
     */
288 62
    protected function singleElementsFromXml(\DOMElement $node, DeserializationContext $context, array $options)
289
    {
290 62
        foreach ($options as $elementName => $info) {
291 62
            $this->oneElementFromXml($node, $context, $elementName, $info[1], $info[0]);
292
        }
293 62
    }
294
295
    /**
296
     * @param \DOMElement $node
297
     * @param array       $attributeNames
298
     */
299 62
    protected function attributesFromXml(\DOMElement $node, array $attributeNames)
300
    {
301 62
        foreach ($attributeNames as $attributeName) {
302 62
            $this->singleAttributeFromXml($node, $attributeName);
303
        }
304 62
    }
305
306
    /**
307
     * @param string $name
308
     *
309
     * @return mixed
310
     *
311
     * @throws \LogicException
312
     */
313 27
    private function getPropertyValue($name)
314
    {
315 27
        if (false !== ($pos = strpos($name, ':'))) {
316
            $name = substr($name, $pos + 1);
317
        }
318 27
        $getter = 'get'.$name.'String';
319 27
        if (false == method_exists($this, $getter)) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
320 27
            $getter = 'get'.$name;
321
        }
322 27
        if (false == method_exists($this, $getter)) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
323
            throw new \LogicException(sprintf(
324
                "Unable to find getter method for '%s' on '%s'",
325
                $name,
326
                get_class($this)
327
            ));
328
        }
329 27
        $value = $this->{$getter}();
330
331 27
        return $value;
332
    }
333
}
334