Passed
Push — master ( 36a5e9...3acde5 )
by Mikaël
07:03 queued 04:44
created

AbstractSoapClientBase   F

Complexity

Total Complexity 74

Size/Duplication

Total Lines 495
Duplicated Lines 0 %

Test Coverage

Coverage 97.84%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 74
eloc 141
c 5
b 0
f 0
dl 0
loc 495
ccs 181
cts 185
cp 0.9784
rs 2.48

28 Methods

Rating   Name   Duplication   Size   Complexity  
A canInstantiateSoapClientWithOptions() 0 7 3
B initSoapClient() 0 19 7
A getOutputHeaders() 0 3 1
A getResult() 0 3 1
A getStreamContextOptions() 0 11 4
A getLastResponseHeaders() 0 3 1
A getDefaultWsdlOptions() 0 30 1
A getSoapClientClassName() 0 7 3
A setResult() 0 4 1
A getLastRequestHeaders() 0 3 1
A __construct() 0 8 1
A getLastError() 0 3 1
A getLastResponse() 0 3 1
A getLastHeaders() 0 7 4
A setLastError() 0 4 1
A getLastErrorForMethod() 0 3 2
A __toString() 0 3 1
A setSoapClient() 0 3 1
A setLocation() 0 6 2
A getStreamContext() 0 3 4
A convertStringHeadersToArray() 0 11 3
C setHttpHeader() 0 51 17
A getFormatedXml() 0 3 1
A getSoapClient() 0 3 1
B setSoapHeader() 0 19 7
A saveLastError() 0 4 1
A getLastXml() 0 7 2
A getLastRequest() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like AbstractSoapClientBase often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractSoapClientBase, and based on these observations, apply Extract Interface, too.

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