Passed
Push — develop ( 11ded6...afb61e )
by Mikaël
01:35
created

Element   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 275
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 39
eloc 81
c 6
b 0
f 0
dl 0
loc 275
ccs 94
cts 94
cp 1
rs 9.28

25 Methods

Rating   Name   Duplication   Size   Complexity  
A getDom() 0 3 1
A getName() 0 3 1
A appendAttributesToElementToSend() 0 16 5
A getNamespace() 0 3 1
A getNamespacePrefix() 0 17 3
A appendElementToElementToSend() 0 5 2
A getTimestampValue() 0 3 3
A setAttributes() 0 5 1
A setNonceValue() 0 5 1
A getValue() 0 3 1
A __toSend() 0 18 2
A appendValuesToElementToSend() 0 4 2
A appendValueToElementToSend() 0 11 4
A setDom() 0 3 1
A __construct() 0 7 1
A setAttribute() 0 5 1
A hasAttributes() 0 3 1
A setTimestampValue() 0 5 1
A setValue() 0 5 1
A setNamespace() 0 5 1
A getNamespacedName() 0 3 1
A setName() 0 5 1
A getAttributes() 0 3 1
A getNonceValue() 0 3 1
A toSend() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace WsdlToPhp\WsSecurity;
6
7
use DOMDocument;
8
use DOMElement;
9
10
/**
11
 * Base class to represent any element that must be included for a WS-Security header.
12
 * Each element must be named with the actual targeted element tag name.
13
 * The namespace is also mandatory.
14
 * Finally the attributes are optional.
15
 */
16
class Element
17
{
18
    const NS_WSSE = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
19
20
    const NS_WSSE_NAME = 'wsse';
21
22
    const NS_WSSU = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd';
23
24
    const NS_WSSU_NAME = 'wssu';
25
26
    protected string $name = '';
27
28
    /**
29
     * Value of the element.
30
     * It can either be a string value or a Element object.
31
     *
32
     * @var Element|string
33
     */
34
    protected $value = '';
35
36
    /**
37
     * Array of attributes that must contains the element.
38
     */
39
    protected array $attributes = [];
40
41
    /**
42
     * The namespace the element belongs to.
43
     */
44
    protected string $namespace = '';
45
46
    /**
47
     * Nonce used to generate digest password.
48
     */
49
    protected string $nonceValue;
50
51
    /**
52
     * Timestamp used to generate digest password.
53
     */
54
    protected int $timestampValue;
55
56
    /**
57
     * Current DOMDocument used to generate XML content.
58
     */
59
    protected static ?DOMDocument $dom = null;
60
61 18
    public function __construct(string $name, string $namespace, $value = null, array $attributes = [])
62
    {
63
        $this
64 18
            ->setName($name)
65 18
            ->setNamespace($namespace)
66 18
            ->setValue($value)
67 18
            ->setAttributes($attributes)
68
        ;
69 18
    }
70
71
    /**
72
     * Method called to generate the string XML request to be sent among the SOAP Header.
73
     *
74
     * @param bool $asDomElement returns elements as a \DOMElement or as a string
75
     *
76
     * @return DOMElement|string
77
     */
78 18
    protected function __toSend(bool $asDomElement = false)
79
    {
80
        // Create element tag.
81 18
        $element = self::getDom()->createElement($this->getNamespacedName());
82 18
        $element->setAttributeNS('http://www.w3.org/2000/xmlns/', sprintf('xmlns:%s', $this->getNamespacePrefix()), $this->getNamespace());
83
84
        // Define element value, add attributes if there are any
85
        $this
86 18
            ->appendValueToElementToSend($this->getValue(), $element)
87 18
            ->appendAttributesToElementToSend($element)
88
        ;
89
90
        // Returns element content
91 18
        if ($asDomElement) {
92 18
            return $element;
93
        }
94
95 18
        return self::getDom()->saveXML($element);
96
    }
97
98 18
    public function getName(): string
99
    {
100 18
        return $this->name;
101
    }
102
103 18
    public function setName($name): self
104
    {
105 18
        $this->name = $name;
106
107 18
        return $this;
108
    }
109
110 18
    public function getAttributes(): array
111
    {
112 18
        return $this->attributes;
113
    }
114
115 18
    public function setAttributes(array $attributes): self
116
    {
117 18
        $this->attributes = $attributes;
118
119 18
        return $this;
120
    }
121
122 14
    public function setAttribute(string $name, $value): self
123
    {
124 14
        $this->attributes[$name] = $value;
125
126 14
        return $this;
127
    }
128
129 18
    public function hasAttributes(): bool
130
    {
131 18
        return 0 < count($this->attributes);
132
    }
133
134 18
    public function getNamespace(): string
135
    {
136 18
        return $this->namespace;
137
    }
138
139 18
    public function setNamespace(string $namespace): self
140
    {
141 18
        $this->namespace = $namespace;
142
143 18
        return $this;
144
    }
145
146
    /**
147
     * @return Element|string
148
     */
149 18
    public function getValue()
150
    {
151 18
        return $this->value;
152
    }
153
154
    /**
155
     * @param mixed $value
156
     *
157
     * @return Element
158
     */
159 18
    public function setValue($value): self
160
    {
161 18
        $this->value = $value;
162
163 18
        return $this;
164
    }
165
166 16
    public function getNonceValue(): string
167
    {
168 16
        return $this->nonceValue;
169
    }
170
171 18
    public function setNonceValue(string $nonceValue): self
172
    {
173 18
        $this->nonceValue = $nonceValue;
174
175 18
        return $this;
176
    }
177
178
    /**
179
     * @return int|string
180
     */
181 18
    public function getTimestampValue(bool $formatted = false)
182
    {
183 18
        return ($formatted && $this->timestampValue > 0) ? gmdate('Y-m-d\TH:i:s\Z', $this->timestampValue) : $this->timestampValue;
184
    }
185
186 18
    public function setTimestampValue(int $timestampValue): self
187
    {
188 18
        $this->timestampValue = $timestampValue;
189
190 18
        return $this;
191
    }
192
193
    /**
194
     * Returns the element to send as WS-Security header.
195
     */
196 18
    public function toSend(): string
197
    {
198 18
        self::setDom(new DOMDocument('1.0', 'UTF-8'));
199
200 18
        return $this->__toSend();
201
    }
202
203
    /**
204
     * Handle adding value to element according to the value type.
205
     *
206
     * @param mixed $value
207
     *
208
     * @return Element
209
     */
210 18
    protected function appendValueToElementToSend($value, DOMElement $element): self
211
    {
212 18
        if ($value instanceof Element) {
213 18
            $this->appendElementToElementToSend($value, $element);
214 18
        } elseif (is_array($value)) {
215 18
            $this->appendValuesToElementToSend($value, $element);
216 18
        } elseif (!empty($value)) {
217 18
            $element->appendChild(self::getDom()->createTextNode($value));
218
        }
219
220 18
        return $this;
221
    }
222
223 18
    protected function appendElementToElementToSend(Element $value, DOMElement $element): void
224
    {
225 18
        $toSend = $value->__toSend(true);
226 18
        if ($toSend instanceof DOMElement) {
0 ignored issues
show
introduced by
$toSend is always a sub-type of DOMElement.
Loading history...
227 18
            $element->appendChild($toSend);
228
        }
229 18
    }
230
231 18
    protected function appendValuesToElementToSend(array $values, DOMElement $element): void
232
    {
233 18
        foreach ($values as $value) {
234 18
            $this->appendValueToElementToSend($value, $element);
235
        }
236 18
    }
237
238 18
    protected function appendAttributesToElementToSend(DOMElement $element): self
239
    {
240 18
        if (!$this->hasAttributes()) {
241 18
            return $this;
242
        }
243
244 18
        foreach ($this->getAttributes() as $attributeName => $attributeValue) {
245 18
            $matches = [];
246 18
            if (0 === preg_match(sprintf('/(%s|%s):/', self::NS_WSSU_NAME, self::NS_WSSE_NAME), $attributeName, $matches)) {
247 18
                $element->setAttribute($attributeName, (string) $attributeValue);
248
            } else {
249 4
                $element->setAttributeNS(self::NS_WSSE_NAME === $matches[1] ? self::NS_WSSE : self::NS_WSSU, $attributeName, $attributeValue);
250
            }
251
        }
252
253 18
        return $this;
254
    }
255
256
    /**
257
     * Returns the name with its namespace.
258
     */
259 18
    protected function getNamespacedName(): string
260
    {
261 18
        return sprintf('%s:%s', $this->getNamespacePrefix(), $this->getName());
262
    }
263
264 18
    private function getNamespacePrefix(): string
265
    {
266 18
        $namespacePrefix = '';
267
268 18
        switch ($this->getNamespace()) {
269 18
            case self::NS_WSSE:
270 18
                $namespacePrefix = self::NS_WSSE_NAME;
271
272 18
                break;
273
274 18
            case self::NS_WSSU:
275 18
                $namespacePrefix = self::NS_WSSU_NAME;
276
277 18
                break;
278
        }
279
280 18
        return $namespacePrefix;
281
    }
282
283 18
    private static function getDom(): ?DOMDocument
284
    {
285 18
        return self::$dom;
286
    }
287
288 18
    private static function setDom(DOMDocument $dom): void
289
    {
290 18
        self::$dom = $dom;
291 18
    }
292
}
293