Completed
Push — master ( 0d441f...aecd55 )
by Ivo
10:37
created

SoapClient::__construct()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 35
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 20
cts 20
cp 1
rs 8.439
c 0
b 0
f 0
cc 5
eloc 22
nc 12
nop 2
crap 5
1
<?php
2
3
namespace Freshcells\SoapClientBundle\SoapClient;
4
5
use Freshcells\SoapClientBundle\Event\Events;
6
use Freshcells\SoapClientBundle\Event\FaultEvent;
7
use Freshcells\SoapClientBundle\Event\RequestEvent;
8
use Freshcells\SoapClientBundle\Event\ResponseEvent;
9
use Ramsey\Uuid\Uuid;
10
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
11
12
/**
13
 * Class SoapClient
14
 */
15
class SoapClient extends \SoapClient
16
{
17
    /**
18
     * @var array
19
     */
20
    protected $options;
21
    /**
22
     * @var EventDispatcherInterface
23
     */
24
    protected $dispatcher;
25
    /**
26
     * @var array
27
     */
28
    private $mockRequests = [];
29
    /**
30
     * @var array
31
     */
32
    private $mockResponses = [];
33
34
    /**
35
     * SoapClient constructor.
36
     * @param null $wsdl
37
     * @param array|null $options
38
     */
39 9
    public function __construct($wsdl = null, array $options = [])
40
    {
41
42 9
        if (isset($options['mock_requests'])) {
43 9
            $this->setMockRequests($options['mock_requests']);
44 9
            unset($options['mock_requests']);
45
        }
46 9
        if (isset($options['mock_responses'])) {
47 6
            $this->setMockResponses($options['mock_responses']);
48 6
            unset($options['mock_responses']);
49
        }
50
51
        $defaults = array(
52 9
            'compression'        => (SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP),
53 9
            'cache_wsdl'         => WSDL_CACHE_BOTH,
54 9
            'connection_timeout' => 60,
55
            'exceptions'         => true,
56 9
            'features'           => SOAP_SINGLE_ELEMENT_ARRAYS,
57 9
            'soap_version'       => SOAP_1_2,
58
            'trace'              => true,
59 9
            'user_agent'         => 'freshcells/soap-client-bundle',
60
        );
61
62 9
        $options = array_merge($defaults, $options);
63
64 9
        if (!is_null($wsdl)) {
65
            // if option 'location' not set explicit use WSDL URL as service location
66 9
            if (!isset($options['location'])) {
67 9
                $options['location'] = $this->resolveLocation($wsdl);
68
            }
69
        }
70
71 9
        $this->SoapClient($wsdl, $options);
72 9
        $this->options = $options;
73 9
    }
74
75 9
    public function __call($function_name, $arguments)
76
    {
77
        try {
78 9
            $response = parent::__call($function_name, $arguments);
79
            //works only with 'exceptions' => false, we always throw
80 6
            if (is_soap_fault($response)) {
81 6
                throw $response;
82
            }
83 3
        } catch (\Exception $e) {
84 3
            $this->handleFault($function_name, $arguments, $e);
85
        }
86
87 6
        return $response;
88
    }
89
90
    public function __soapCall(
91
        $function_name,
92
        $arguments,
93
        $options = null,
94
        $input_headers = null,
95
        &$output_headers = null
96
    ) {
97
        try {
98
            $response = parent::__soapCall($function_name, $arguments, $options, $input_headers, $output_headers);
99
            //works only with 'exceptions' => false, we always throw
100
            if (is_soap_fault($response)) {
101
                throw $response;
102
            }
103
        } catch (\Exception $e) {
104
            $this->handleFault($function_name, $arguments, $e);
105
        }
106
107
        return $response;
108
    }
109
110
    /**
111
     * @param string $request
112
     * @param string $location
113
     * @param string $action
114
     * @param int $version
115
     * @param null $one_way
116
     * @return bool|string
117
     */
118 6
    public function __doRequest($request, $location, $action, $version, $one_way = null)
119
    {
120 6
        $id = Uuid::uuid1();
121
122 6
        foreach ($this->mockRequests as $key => $mockRequest) {
123 6
            if (is_string($key)) {
124 6
                if (strrpos($action, $key) !== false) {
125 6
                    $request = file_get_contents($mockRequest);
126 6
                    break;
127
                }
128
            }
129
            else {
130
                if (is_callable($mockRequest)) {
131
                    if ($responseFilePath = $mockRequest($request, $location, $action, $version, $one_way)) {
0 ignored issues
show
Unused Code introduced by
$responseFilePath is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
132
                        $request = file_get_contents($mockRequest);
133
                        break;
134
                    }
135
                }
136
            }
137
        }
138
139 6
        $this->preCall($id->toString(), $action, $request);
140
141 6
        foreach ($this->mockResponses as $key => $mockResponse) {
142 6
            if (is_string($key)) {
143 3
                if (strrpos($action, $key) !== false) {
144 3
                    $response = file_get_contents($mockResponse);
145
146 3
                    $this->postCall($id->toString(), $action, $response);
147
148 3
                    return $response;
149
                }
150
            } else {
151 3
                if (is_callable($mockResponse)) {
152 3
                    if ($responseFilePath = $mockResponse($request, $location, $action, $version, $one_way)) {
153 3
                        $response = file_get_contents($responseFilePath);
154
155 3
                        $this->postCall($id->toString(), $action, $response);
156
157 3
                        return $response;
158
                    }
159
                }
160
            }
161
        }
162
163
        /* workaround for working timeout */
164
        $socketTimeout = false;
165
        if (isset($this->options['connection_timeout'])
166
            && (int)$this->options['connection_timeout'] > (int)ini_get('default_socket_timeout')
167
        ) {
168
            $socketTimeout = ini_set('default_socket_timeout', $this->options['connection_timeout']);
169
        }
170
171
        $response = parent::__doRequest($request, $location, $action, $version, $one_way);
172
173
        $this->postCall($id->toString(), $action, $response);
174
175
        if ($socketTimeout !== false) {
176
            ini_set('default_socket_timeout', $socketTimeout);
177
        }
178
179
        return $response;
180
    }
181
182
    /**
183
     * Triggered before a request is executed
184
     *
185
     * @param string $id
186
     * @param string $resource
187
     * @param string $requestContent
188
     */
189 6
    protected function preCall(string $id, string $resource, string $requestContent = null)
190
    {
191 6
        if (null !== $this->dispatcher) {
192 6
            $this->dispatcher->dispatch(Events::REQUEST, new RequestEvent($id, $resource, $requestContent));
193
        }
194 6
    }
195
196
    /**
197
     * @param string $id
198
     * @param string $resource
199
     * @param string $response
200
     */
201 6
    protected function postCall(string $id, string $resource, string $response = null)
202
    {
203 6
        if (null !== $this->dispatcher) {
204 6
            $responseEvent = new ResponseEvent(
205 6
                $id,
206 6
                $resource,
207 6
                $this->__getLastRequest(),
208 6
                $this->__getLastRequestHeaders(),
209 6
                $response,
210 6
                $this->__getLastResponseHeaders()
211
            );
212 6
            $this->dispatcher->dispatch(Events::RESPONSE, $responseEvent);
213
        }
214 6
    }
215
216
    /**
217
     * @param string $id
218
     * @param string $resource
219
     * @param string $requestContent
220
     * @param \Exception $exception
221
     */
222 3
    protected function faultCall(string $id, string $resource, string $requestContent, \Exception $exception)
223
    {
224 3
        if (null !== $this->dispatcher) {
225 3
            $this->dispatcher->dispatch(
226 3
                Events::FAULT,
227 3
                new FaultEvent($id, $exception, new RequestEvent($id, $resource, $requestContent))
228
            );
229
        }
230 3
    }
231
232
    /**
233
     * @param string $wsdl
234
     * @return string
235
     */
236 9
    protected function resolveLocation($wsdl)
237
    {
238 9
        $wsdlUrl = parse_url($wsdl);
239
240 9
        return ((isset($wsdlUrl['scheme'])) ? $wsdlUrl['scheme'].'://' : '')
241 9
            .((isset($wsdlUrl['user'])) ? $wsdlUrl['user']
242 9
                .((isset($wsdlUrl['pass'])) ? ':'.$wsdlUrl['pass'] : '').'@' : '')
243 9
            .((isset($wsdlUrl['host'])) ? $wsdlUrl['host'] : '')
244 9
            .((isset($wsdlUrl['port'])) ? ':'.$wsdlUrl['port'] : '')
245 9
            .((isset($wsdlUrl['path'])) ? $wsdlUrl['path'] : '');
246
    }
247
248
    /**
249
     * @param array $mockRequests
250
     */
251 9
    public function setMockRequests(array $mockRequests)
252
    {
253 9
        $this->mockRequests = $mockRequests;
254 9
    }
255
256
    /**
257
     * @param array $mockResponses
258
     */
259 9
    public function setMockResponses(array $mockResponses)
260
    {
261 9
        $this->mockResponses = $mockResponses;
262 9
    }
263
264
    /**
265
     * @param EventDispatcherInterface $dispatcher
266
     */
267 9
    public function setDispatcher(EventDispatcherInterface $dispatcher)
268
    {
269 9
        $this->dispatcher = $dispatcher;
270 9
    }
271
272
    /**
273
     * @param $function_name
274
     * @param $arguments
275
     * @param $e
276
     */
277 3
    protected function handleFault($function_name, $arguments, $e): void
278
    {
279 3
        $request = $this->__getLastRequest();
280 3
        if ($request === null) { //only dispatch this when no request was fired
281 3
            $request = implode(' ', $arguments);
282 3
            $id      = Uuid::uuid1();
283 3
            $this->faultCall($id->toString(), $function_name, $request, $e);
284
        }
285
286 3
        throw $e;
287
    }
288
}
289