GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Test Setup Failed
Push — master ( fe4962...3aa77f )
by Thijs
04:04
created

SoapClient::createHeaders()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 9
rs 9.6666
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
namespace WebservicesNl\Protocol\Soap\Client;
4
5
use GuzzleHttp\Client as httpClient;
6
use GuzzleHttp\Exception\ClientException;
7
use GuzzleHttp\Exception\ConnectException;
8
use GuzzleHttp\Psr7\Request;
9
use Psr\Log\LoggerAwareTrait;
10
use Psr\Log\LoggerInterface;
11
use Psr\Log\LogLevel;
12
use WebservicesNl\Common\Endpoint\Manager;
13
use WebservicesNl\Common\Exception\ClientException as WsClientException;
14
use WebservicesNl\Common\Exception\Server\NoServerAvailableException;
15
use WebservicesNl\Connector\Client\ClientInterface;
16
use WebservicesNl\Protocol\Soap\Exception\ConverterInterface;
17
18
/**
19
 * PHP SoapClient with curl for HTTP transport.
20
 *
21
 * Extends the native PHP SoapClient. Adds PSR7 Client (Guzzle) for making the calls for better timeout management.
22
 * Also optional loggerInterface (middleware client) helps with tracing and debugging calls.
23
 */
24
class SoapClient extends \SoapClient implements ClientInterface
25
{
26
    use LoggerAwareTrait;
27
28
    const PROTOCOL = 'soap';
29
    
30
    /**
31
     * @var ConverterInterface
32
     */
33
    private $converter;
34
    
35
    /**
36
     * Guzzle Client for the SOAP calls.
37
     *
38
     * @var HttpClient
39
     */
40
    private $httpClient;
41
42
    /**
43
     * @var Manager
44
     */
45
    private $manager;
46
47
    /**
48
     * Soap settings.
49
     *
50
     * @var SoapSettings;
51
     */
52
    private $settings;
53
    
54
    /**
55
     * Content types for SOAP versions.
56
     *
57
     * @var array(string=>string)
58
     */
59
    protected static $versionToContentTypeMap = [
60
        SOAP_1_1 => 'text/xml; charset=utf-8',
61
        SOAP_1_2 => 'application/soap+xml; charset=utf-8',
62
    ];
63
64
    /**
65
     * SoapClient constructor.
66
     *
67
     * @param SoapSettings $settings
68
     * @param Manager      $manager
69
     * @param              $client
70
     *
71
     * @throws NoServerAvailableException
72
     * @throws \InvalidArgumentException
73
     */
74
    public function __construct(SoapSettings $settings, Manager $manager, $client)
75
    {
76
        $this->settings = $settings;
77
        $this->manager = $manager;
78
        $this->httpClient = $client;
79
80
        // throws an Exception when no endpoint is met
81
        $active = $this->manager->getActiveEndpoint();
82
        $this->log('Initial endpoint is ' . (string)$active->getUri(), LogLevel::INFO);
83
84
        // initiate the native PHP SoapClient for fetching all the WSDL stuff
85
        parent::__construct((string)$active->getUri()->withQuery('wsdl'), $this->settings->toArray());
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SoapClient as the method __construct() does only exist in the following sub-classes of SoapClient: WebservicesNl\Protocol\Soap\Client\SoapClient. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
86
    }
87
88
    /**
89
     * Triggers the SOAP request over HTTP.
90
     * Sent request by cURL instead of native SOAP request.
91
     *
92
     * @param string      $request
93
     * @param string      $location
94
     * @param string      $action
95
     * @param int         $version
96
     * @param string|null $one_way
97
     *
98
     * @return string The XML SOAP response.
99
     * @throws WsClientException
100
     * @throws NoServerAvailableException
101
     * @throws \InvalidArgumentException
102
     * @throws \SoapFault
103
     */
104
    public function __doRequest($request, $location, $action, $version, $one_way = null)
105
    {
106
        $active = $this->manager->getActiveEndpoint();
107
        try {
108
            $response = $this->doHttpRequest($request, (string)$active->getUri(), $action);
109
            $this->manager->updateLastConnected();
110
111
            return $response;
112
        } // when a connection failed try the next server, else return the response
113
        catch (ConnectException $exception) {
114
            $active->setStatus('error');
115
            $this->log('Endpoint is not responding', 'error', ['endpoint' => $active]);
116
117
            return $this->__doRequest($request, $location, $action, $version, $one_way);
118
        }
119
    }
120
121
    /**
122
     * Proxy function to SoapCall
123
     *
124
     * @param array $args
125
     *
126
     * @return mixed
127
     * @throws \Exception
128
     * @throws \SoapFault
129
     */
130
    public function call(array $args = [])
131
    {
132
        $args += ['functionName' => ''];
133
        
134
        $functionName = $args['functionName'];
135
        unset($args['functionName']);
136
137
        return $this->soapCall($functionName, $args);
138
    }
139
140
    /**
141
     * Determine the SOAPHeaders for given version.
142
     *
143
     * @param string $action
144
     *
145
     * @return array
146
     */
147
    private function createHeaders($action)
148
    {
149
        $headers = ['Content-Type' => self::$versionToContentTypeMap[$this->settings->getSoapVersion()]];
150
        if ($this->settings->getSoapVersion() === SOAP_1_1) {
151
            $headers['SOAPAction'] = $action;
152
        }
153
154
        return $headers;
155
    }
156
157
    /**
158
     * Determines methods.
159
     * For Soap it's either GET or POST.
160
     *
161
     * @param mixed $request
162
     *
163
     * @return string
164
     */
165
    private static function determineMethod($request)
166
    {
167
        return ($request === null || (is_string($request) && trim($request) === '')) ? 'GET' : 'POST';
168
    }
169
170
    /**
171
     * Http version of doRequest.
172
     *
173
     * @param mixed  $requestBody
174
     * @param string $location
175
     * @param string $action
176
     *
177
     * @return string
178
     * @throws WsClientException
179
     * @throws \SoapFault
180
     * @throws \InvalidArgumentException
181
     * @todo move exception handler to middleware, find solution error suppressing
182
     */
183
    private function doHttpRequest($requestBody, $location, $action)
184
    {
185
        // get soap details for request
186
        $headers = $this->createHeaders($action);
187
        $method = self::determineMethod($requestBody);
188
189
        // try to fire a request and return it
190
        try {
191
            $requestObj = new Request($method, $location, $headers, $requestBody);
192
            $response = $this->httpClient->send($requestObj);
193
            // Throw a SoapFault if the response was received, but it can't be read into valid XML
194
            if ($response->getStatusCode() > 399 && @simplexml_load_string((string)$response->getBody()) === false) {
195
                throw new \SoapFault('Server', 'Invalid SoapResponse');
196
            }
197
            
198
            return (string)$response->getBody();
199
        } catch (ClientException $e) {
200
            // if a client exception is thrown, the guzzle instance, is configured to throw exceptions
201
            $code = ($e->getResponse() !== null) ? 'Server' : 'Client.Input';
202
            throw new \SoapFault('Client', $e->getMessage(), null, $code);
203
        }
204
    }
205
206
    /**
207
     * @return ConverterInterface
208
     */
209
    public function getConverter()
210
    {
211
        return $this->converter;
212
    }
213
214
    /**
215
     * @param ConverterInterface $converter
216
     */
217
    public function setConverter($converter)
218
    {
219
        $this->converter = $converter;
220
    }
221
222
    /**
223
     * @return httpClient
224
     */
225
    public function getHttpClient()
226
    {
227
        return $this->httpClient;
228
    }
229
230
    /**
231
     * Return this connector over which a connection is established.
232
     *
233
     * @return string
234
     */
235
    public function getProtocolName()
236
    {
237
        return static::PROTOCOL;
238
    }
239
240
    /**
241
     * Log message.
242
     *
243
     * @param string $message
244
     * @param int    $level
245
     * @param array  $context
246
     */
247
    public function log($message, $level, array $context = [])
248
    {
249
        if ($this->logger instanceof LoggerInterface) {
250
            $this->logger->log($level, $message, $context);
251
        }
252
    }
253
254
    /**
255
     * Prepares the soapCall.
256
     *
257
     * @param string     $function_name
258
     * @param array      $arguments
259
     * @param array      $options
260
     * @param array      $input_headers
261
     * @param array|null $output_headers
262
     *
263
     * @return mixed
264
     * @throws \Exception|\SoapFault
265
     */
266
    public function soapCall(
267
        $function_name,
268
        array $arguments = [],
269
        array $options = [],
270
        array $input_headers = [],
271
        &$output_headers = null
272
    ) {
273
        $this->log('Called:' . $function_name, LogLevel::INFO, ['arguments' => $arguments]);
274
275
        try {
276
            return parent::__soapCall($function_name, $arguments, $options, $input_headers, $output_headers);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (__soapCall() instead of soapCall()). Are you sure this is correct? If so, you might want to change this to $this->__soapCall().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
277
        } catch (\SoapFault $fault) {
278
            if ($this->getConverter() !== null) {
279
                throw $this->getConverter()->convertToException($fault);
280
            }
281
            throw $fault;
282
        }
283
    }
284
}
285