Passed
Push — feature/issue-32 ( 6f5839...dcb804 )
by Mikaël
01:22
created

AbstractSoapClientBase::setHttpHeader()   C

Complexity

Conditions 17
Paths 17

Size

Total Lines 51
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 22.6378

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 17
eloc 27
c 3
b 0
f 0
nc 17
nop 2
dl 0
loc 51
ccs 19
cts 26
cp 0.7308
crap 22.6378
rs 5.2166

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
3
declare(strict_types=1);
4
5
namespace WsdlToPhp\PackageBase;
6
7
use DOMDocument;
8
use SoapClient;
9
use SoapFault;
10
use SoapHeader;
11
12
abstract class AbstractSoapClientBase implements SoapClientInterface
13
{
14
    /**
15
     * SoapClient called to communicate with the actual SOAP Service
16
     * @var SoapClient|null
17
     */
18
    private ?SoapClient $soapClient = null;
19
20
    /**
21
     * Contains Soap call result
22
     * @var mixed
23
     */
24
    private $result;
25
26
    /**
27
     * Contains last errors
28
     * @var array
29
     */
30
    private array $lastError = [];
31
32
    /**
33
     * Contains output headers
34
     * @var array
35
     */
36
    protected array $outputHeaders = [];
37
38 64
    public function __construct(array $wsdlOptions = [])
39
    {
40 64
        $this->initSoapClient($wsdlOptions);
41 64
    }
42
43 56
    public function getSoapClient(): ?SoapClient
44
    {
45 56
        return $this->soapClient;
46
    }
47
48 52
    public function setSoapClient(SoapClient $soapClient): SoapClient
49
    {
50 52
        return ($this->soapClient = $soapClient);
51
    }
52
53 64
    public function initSoapClient(array $options): void
54
    {
55 64
        $wsdlOptions = [];
56 64
        $defaultWsdlOptions = static::getDefaultWsdlOptions();
57 64
        foreach ($defaultWsdlOptions as $optionName => $optionValue) {
58 64
            if (array_key_exists($optionName, $options) && !is_null($options[$optionName])) {
59 56
                $wsdlOptions[str_replace(self::OPTION_PREFIX, '', $optionName)] = $options[$optionName];
60 64
            } elseif (!is_null($optionValue)) {
61 64
                $wsdlOptions[str_replace(self::OPTION_PREFIX, '', $optionName)] = $optionValue;
62
            }
63
        }
64 64
        if (self::canInstantiateSoapClientWithOptions($wsdlOptions)) {
65 52
            $wsdlUrl = null;
66 52
            if (array_key_exists(str_replace(self::OPTION_PREFIX, '', self::WSDL_URL), $wsdlOptions)) {
67 48
                $wsdlUrl = $wsdlOptions[str_replace(self::OPTION_PREFIX, '', self::WSDL_URL)];
68 48
                unset($wsdlOptions[str_replace(self::OPTION_PREFIX, '', self::WSDL_URL)]);
69
            }
70 52
            $soapClientClassName = $this->getSoapClientClassName();
71 52
            $this->setSoapClient(new $soapClientClassName($wsdlUrl, $wsdlOptions));
72
        }
73 64
    }
74
75
    /**
76
     * Checks if the provided options are sufficient to instantiate a SoapClient:
77
     *  - WSDL-mode : only the WSDL is required
78
     *  - non-WSDL-mode : URI and LOCATION are required, WSDL url can be empty then
79
     * @param array $wsdlOptions
80
     * @return bool
81
     */
82 64
    protected static function canInstantiateSoapClientWithOptions(array $wsdlOptions): bool
83
    {
84
        return (
85 64
            array_key_exists(str_replace(self::OPTION_PREFIX, '', self::WSDL_URL), $wsdlOptions) ||
86
            (
87 16
                array_key_exists(str_replace(self::OPTION_PREFIX, '', self::WSDL_URI), $wsdlOptions) &&
88 64
                array_key_exists(str_replace(self::OPTION_PREFIX, '', self::WSDL_LOCATION), $wsdlOptions)
89
            )
90
        );
91
    }
92
93
    /**
94
     * Returns the SoapClient class name to use to create the instance of the SoapClient.
95
     * Be sure that this class inherits from the native PHP SoapClient class and this class has been loaded or can be loaded.
96
     * The goal is to allow the override of the SoapClient without having to modify this generated class.
97
     * Then the overriding SoapClient class can override for example the SoapClient::__doRequest() method if it is needed.
98
     * @param string|null $soapClientClassName
99
     * @return string
100
     */
101 56
    public function getSoapClientClassName(?string $soapClientClassName = null): string
102
    {
103 56
        $className = self::DEFAULT_SOAP_CLIENT_CLASS;
104 56
        if (!empty($soapClientClassName) && is_subclass_of($soapClientClassName, SoapClient::class)) {
105 56
            $className = $soapClientClassName;
106
        }
107
108 56
        return $className;
109
    }
110
111
    /**
112
     * Method returning all default SoapClient options values
113
     * @return array
114
     */
115 64
    public static function getDefaultWsdlOptions(): array
116
    {
117
        return [
118 64
            self::WSDL_AUTHENTICATION => null,
119 64
            self::WSDL_CACHE_WSDL => WSDL_CACHE_NONE,
120 64
            self::WSDL_CLASSMAP => null,
121 64
            self::WSDL_COMPRESSION => null,
122 64
            self::WSDL_CONNECTION_TIMEOUT => null,
123 64
            self::WSDL_ENCODING => null,
124 64
            self::WSDL_EXCEPTIONS => true,
125 64
            self::WSDL_FEATURES => SOAP_SINGLE_ELEMENT_ARRAYS | SOAP_USE_XSI_ARRAY_TYPE,
126 64
            self::WSDL_LOCAL_CERT => null,
127 64
            self::WSDL_LOCATION => null,
128 64
            self::WSDL_LOGIN => null,
129 64
            self::WSDL_PASSPHRASE => null,
130 64
            self::WSDL_PASSWORD => null,
131 64
            self::WSDL_PROXY_HOST => null,
132 64
            self::WSDL_PROXY_LOGIN => null,
133 64
            self::WSDL_PROXY_PASSWORD => null,
134 64
            self::WSDL_PROXY_PORT => null,
135 64
            self::WSDL_SOAP_VERSION => null,
136 64
            self::WSDL_SSL_METHOD => null,
137 64
            self::WSDL_STREAM_CONTEXT => null,
138 64
            self::WSDL_STYLE => null,
139 64
            self::WSDL_TRACE => true,
140 64
            self::WSDL_TYPEMAP => null,
141 64
            self::WSDL_URL => null,
142 64
            self::WSDL_URI => null,
143 64
            self::WSDL_USE => null,
144 64
            self::WSDL_USER_AGENT => null,
145
        ];
146
    }
147
148
    /**
149
     * Allows to set the SoapClient location to call
150
     * @param string $location
151
     * @return AbstractSoapClientBase
152
     */
153 2
    public function setLocation(string $location): self
154
    {
155 2
        if ($this->getSoapClient() instanceof SoapClient) {
156 2
            $this->getSoapClient()->__setLocation($location);
157
        }
158
159 2
        return $this;
160
    }
161
162
    /**
163
     * Returns the last request content as a DOMDocument or as a formatted XML String
164
     * @param bool $asDomDocument
165
     * @return DOMDocument|string|null
166
     */
167 4
    public function getLastRequest(bool $asDomDocument = false)
168
    {
169 4
        return $this->getLastXml('__getLastRequest', $asDomDocument);
170
    }
171
172
    /**
173
     * Returns the last response content as a DOMDocument or as a formatted XML String
174
     * @param bool $asDomDocument
175
     * @return DOMDocument|string|null
176
     */
177 4
    public function getLastResponse(bool $asDomDocument = false)
178
    {
179 4
        return $this->getLastXml('__getLastResponse', $asDomDocument);
180
    }
181
182
    /**
183
     * @param string $method
184
     * @param bool $asDomDocument
185
     * @return DOMDocument|string|null
186
     */
187 8
    protected function getLastXml(string $method, bool $asDomDocument = false)
188
    {
189 8
        $xml = null;
190 8
        if ($this->getSoapClient() instanceof SoapClient) {
191 8
            $xml = static::getFormattedXml($this->getSoapClient()->$method(), $asDomDocument);
192
        }
193
194 8
        return $xml;
195
    }
196
197
    /**
198
     * Returns the last request headers used by the SoapClient object as the original value or an array
199
     * @param bool $asArray allows to get the headers in an associative array
200
     * @return null|string|string[]
201
     */
202 4
    public function getLastRequestHeaders(bool $asArray = false)
203
    {
204 4
        return $this->getLastHeaders('__getLastRequestHeaders', $asArray);
205
    }
206
207
    /**
208
     * Returns the last response headers used by the SoapClient object as the original value or an array
209
     * @param bool $asArray allows to get the headers in an associative array
210
     * @return null|string|string[]
211
     */
212 4
    public function getLastResponseHeaders(bool $asArray = false)
213
    {
214 4
        return $this->getLastHeaders('__getLastResponseHeaders', $asArray);
215
    }
216
217
    /**
218
     * @param string $method
219
     * @param bool $asArray allows to get the headers in an associative array
220
     * @return null|string|string[]
221
     */
222 8
    protected function getLastHeaders(string $method, bool $asArray)
223
    {
224 8
        $headers = $this->getSoapClient() instanceof SoapClient ? $this->getSoapClient()->$method() : null;
225 8
        if (is_string($headers) && $asArray) {
226 4
            return static::convertStringHeadersToArray($headers);
227
        }
228
229 4
        return $headers;
230
    }
231
232
    /**
233
     * Returns a XML string content as a DOMDocument or as a formatted XML string
234
     * @param string|null $string
235
     * @param bool $asDomDocument
236
     * @return DOMDocument|string|null
237
     */
238 8
    public static function getFormattedXml(?string $string, bool $asDomDocument = false)
239
    {
240 8
        return Utils::getFormattedXml($string, $asDomDocument);
241
    }
242
243
    /**
244
     * Returns an associative array between the headers name and their respective values
245
     * @param string $headers
246
     * @return string[]
247
     */
248 4
    public static function convertStringHeadersToArray(string $headers): array
249
    {
250 4
        $lines = explode("\r\n", $headers);
251 4
        $headers = [];
252 4
        foreach ($lines as $line) {
253 4
            if (strpos($line, ':')) {
254 4
                $headerParts = explode(':', $line);
255 4
                $headers[$headerParts[0]] = trim(implode(':', array_slice($headerParts, 1)));
256
            }
257
        }
258
259 4
        return $headers;
260
    }
261
262
    /**
263
     * Sets a SoapHeader to send
264
     * For more information, please read the online documentation on {@link http://www.php.net/manual/en/class.soapheader.php}
265
     * @param string $namespace SoapHeader namespace
266
     * @param string $name SoapHeader name
267
     * @param mixed $data SoapHeader data
268
     * @param bool $mustUnderstand
269
     * @param string|null $actor
270
     * @return AbstractSoapClientBase
271
     */
272 6
    public function setSoapHeader(string $namespace, string $name, $data, bool $mustUnderstand = false, ?string $actor = null): self
273
    {
274 6
        if ($this->getSoapClient()) {
275 6
            $defaultHeaders = (isset($this->getSoapClient()->__default_headers) && is_array($this->getSoapClient()->__default_headers)) ? $this->getSoapClient()->__default_headers : [];
276 6
            foreach ($defaultHeaders as $index => $soapHeader) {
277 2
                if ($soapHeader->name === $name) {
278 2
                    unset($defaultHeaders[$index]);
279 2
                    break;
280
                }
281
            }
282 6
            $this->getSoapClient()->__setSoapheaders(null);
283 6
            if (!empty($actor)) {
284 2
                array_push($defaultHeaders, new SoapHeader($namespace, $name, $data, $mustUnderstand, $actor));
285
            } else {
286 4
                array_push($defaultHeaders, new SoapHeader($namespace, $name, $data, $mustUnderstand));
287
            }
288 6
            $this->getSoapClient()->__setSoapheaders($defaultHeaders);
289
        }
290 6
        return $this;
291
    }
292
293
    /**
294
     * Sets the SoapClient Stream context HTTP Header name according to its value
295
     * If a context already exists, it tries to modify it
296
     * It the context does not exist, it then creates it with the header name and its value
297
     * @param string $headerName
298
     * @param mixed $headerValue
299
     * @return bool
300
     */
301 12
    public function setHttpHeader(string $headerName, $headerValue): bool
302
    {
303 12
        $state = false;
304 12
        if ($this->getSoapClient() && !empty($headerName)) {
305 12
            $streamContext = $this->getStreamContext();
306 12
            if ($streamContext === null) {
307
                $options = [];
308
                $options['http'] = [];
309
                $options['http']['header'] = '';
310
            } else {
311 12
                $options = stream_context_get_options($streamContext);
312 12
                if (!array_key_exists('http', $options) || !is_array($options['http'])) {
313
                    $options['http'] = [];
314
                    $options['http']['header'] = '';
315 12
                } elseif (!array_key_exists('header', $options['http'])) {
316
                    $options['http']['header'] = '';
317
                }
318
            }
319 12
            if (count($options) && array_key_exists('http', $options) && is_array($options['http']) && array_key_exists('header', $options['http']) && is_string($options['http']['header'])) {
320 12
                $lines = explode("\r\n", $options['http']['header']);
321
                /**
322
                 * Ensure there is only one header entry for this header name
323
                 */
324 12
                $newLines = [];
325 12
                foreach ($lines as $line) {
326 12
                    if (!empty($line) && strpos($line, $headerName) === false) {
327 12
                        array_push($newLines, $line);
328
                    }
329
                }
330
                /**
331
                 * Add new header entry
332
                 */
333 12
                array_push($newLines, "$headerName: $headerValue");
334
                /**
335
                 * Set the context http header option
336
                 */
337 12
                $options['http']['header'] = implode("\r\n", $newLines);
338
                /**
339
                 * Create context if it does not exist
340
                 */
341 12
                if ($streamContext === null) {
342
                    $state = ($this->getSoapClient()->_stream_context = stream_context_create($options)) ? true : false;
0 ignored issues
show
Bug introduced by
The property _stream_context does not seem to exist on SoapClient.
Loading history...
343
                } else {
344
                    /**
345
                     * Set the new context http header option
346
                     */
347 12
                    $state = stream_context_set_option($this->getSoapClient()->_stream_context, 'http', 'header', $options['http']['header']);
348
                }
349
            }
350
        }
351 12
        return $state;
352
    }
353
354
    /**
355
     * Returns current SoapClient::_stream_context resource or null
356
     * @return resource|null
357
     */
358 14
    public function getStreamContext()
359
    {
360 14
        return ($this->getSoapClient() && isset($this->getSoapClient()->_stream_context) && is_resource($this->getSoapClient()->_stream_context)) ? $this->getSoapClient()->_stream_context : null;
361
    }
362
363
    /**
364
     * Returns current SoapClient::_stream_context resource options or empty array
365
     * @return array
366
     */
367 2
    public function getStreamContextOptions(): array
368
    {
369 2
        $options = [];
370 2
        $context = $this->getStreamContext();
371 2
        if ($context !== null) {
372 2
            $options = stream_context_get_options($context);
373 2
            if (isset($options['http']['header']) && is_string($options['http']['header'])) {
374 2
                $options['http']['header'] = array_filter(array_map('trim', explode(PHP_EOL, $options['http']['header'])));
375
            }
376
        }
377 2
        return $options;
378
    }
379
380
    /**
381
     * Method returning last errors occurred during the calls
382
     * @return array
383
     */
384 2
    public function getLastError(): array
385
    {
386 2
        return $this->lastError;
387
    }
388
389
    /**
390
     * Method saving the last error returned by the SoapClient
391
     * @param string $methodName the method called when the error occurred
392
     * @param SoapFault $soapFault the fault
393
     * @return AbstractSoapClientBase
394
     */
395 6
    public function saveLastError(string $methodName, SoapFault $soapFault): SoapClientInterface
396
    {
397 6
        $this->lastError[$methodName] = $soapFault;
398
399 6
        return $this;
400
    }
401
402
    /**
403
     * Method getting the last error for a certain method
404
     * @param string $methodName method name to get error from
405
     * @return SoapFault|null
406
     */
407 2
    public function getLastErrorForMethod(string $methodName): ?SoapFault
408
    {
409 2
        return array_key_exists($methodName, $this->lastError) ? $this->lastError[$methodName] : null;
410
    }
411
412
    /**
413
     * Method returning current result from Soap call
414
     * @return mixed
415
     */
416 2
    public function getResult()
417
    {
418 2
        return $this->result;
419
    }
420
421
    /**
422
     * Method setting current result from Soap call
423
     * @param mixed $result
424
     * @return AbstractSoapClientBase
425
     */
426 6
    public function setResult($result): SoapClientInterface
427
    {
428 6
        $this->result = $result;
429
430 6
        return $this;
431
    }
432
433
    /**
434
     * @return array
435
     */
436 2
    public function getOutputHeaders(): array
437
    {
438 2
        return $this->outputHeaders;
439
    }
440
441
    /**
442
     * Default string representation of current object. Don't want to expose any sensible data
443
     * @return string
444
     */
445 2
    public function __toString(): string
446
    {
447 2
        return get_called_class();
448
    }
449
}
450