Completed
Push — master ( 0b57e6...7953da )
by Ivo
16s
created

SoapClient::getOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
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 implements SoapClientInterface
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 18
    public function __construct($wsdl = null, array $options = [])
40
    {
41
42 18
        if (isset($options['mock_requests'])) {
43 12
            $this->setMockRequests($options['mock_requests']);
44 12
            unset($options['mock_requests']);
45
        }
46 18
        if (isset($options['mock_responses'])) {
47 9
            $this->setMockResponses($options['mock_responses']);
48 9
            unset($options['mock_responses']);
49
        }
50
51
        $defaults = array(
52 18
            'compression'        => (SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP),
53 18
            'cache_wsdl'         => WSDL_CACHE_BOTH,
54 18
            'connection_timeout' => 60,
55
            'exceptions'         => true,
56 18
            'features'           => SOAP_SINGLE_ELEMENT_ARRAYS,
57 18
            'soap_version'       => SOAP_1_2,
58
            'trace'              => true,
59 18
            'user_agent'         => 'freshcells/soap-client-bundle',
60
        );
61
62 18
        $options = array_merge($defaults, $options);
63
64 18
        if (!is_null($wsdl)) {
65
            // if option 'location' not set explicit use WSDL URL as service location
66 18
            if (!isset($options['location'])) {
67 18
                $options['location'] = $this->resolveLocation($wsdl);
68
            }
69
        }
70
71 18
        $this->SoapClient($wsdl, $options);
72 18
        $this->options = $options;
73 18
    }
74
75 6
    public function getOptions(): array
76
    {
77 6
        return $this->options;
78
    }
79
80 9
    public function __call($function_name, $arguments)
81
    {
82
        try {
83 9
            $response = parent::__call($function_name, $arguments);
84
            //works only with 'exceptions' => false, we always throw
85 6
            if (is_soap_fault($response)) {
86 6
                throw $response;
87
            }
88 3
        } catch (\Exception $e) {
89 3
            $this->handleFault($function_name, $arguments, $e);
90
        }
91
92 6
        return $response;
93
    }
94
95
    public function __soapCall(
96
        $function_name,
97
        $arguments,
98
        $options = null,
99
        $input_headers = null,
100
        &$output_headers = null
101
    ) {
102
        try {
103
            $response = parent::__soapCall($function_name, $arguments, $options, $input_headers, $output_headers);
104
            //works only with 'exceptions' => false, we always throw
105
            if (is_soap_fault($response)) {
106
                throw $response;
107
            }
108
        } catch (\Exception $e) {
109
            $this->handleFault($function_name, $arguments, $e);
110
        }
111
112
        return $response;
113
    }
114
115
    /**
116
     * @param string $request
117
     * @param string $location
118
     * @param string $action
119
     * @param int $version
120
     * @param null $one_way
121
     * @return bool|string
122
     */
123 6
    public function __doRequest($request, $location, $action, $version, $one_way = null)
124
    {
125 6
        $id = Uuid::uuid1();
126
127 6
        foreach ($this->mockRequests as $key => $mockRequest) {
128 6
            if (is_string($key)) {
129 6
                if (strrpos($action, $key) !== false) {
130 6
                    $request = file_get_contents($mockRequest);
131 6
                    break;
132
                }
133
            } else {
134
                if (is_callable($mockRequest)) {
135
                    if ($requestFilePath = $mockRequest($request, $location, $action, $version, $one_way)) {
136
                        $request = file_get_contents($requestFilePath);
137
                        break;
138
                    }
139
                }
140
            }
141
        }
142
143 6
        $this->preCall($id->toString(), $action, $request);
144
145 6
        foreach ($this->mockResponses as $key => $mockResponse) {
146 6
            if (is_string($key)) {
147 3
                if (strrpos($action, $key) !== false) {
148 3
                    $response = file_get_contents($mockResponse);
149
150 3
                    $this->postCall($id->toString(), $action, $response);
151
152 3
                    return $response;
153
                }
154
            } else {
155 3
                if (is_callable($mockResponse)) {
156 3
                    if ($responseFilePath = $mockResponse($request, $location, $action, $version, $one_way)) {
157 3
                        $response = file_get_contents($responseFilePath);
158
159 3
                        $this->postCall($id->toString(), $action, $response);
160
161 3
                        return $response;
162
                    }
163
                }
164
            }
165
        }
166
167
        /* workaround for working timeout */
168
        $socketTimeout = false;
169
        if (isset($this->options['connection_timeout'])
170
            && (int)$this->options['connection_timeout'] > (int)ini_get('default_socket_timeout')
171
        ) {
172
            $socketTimeout = ini_set('default_socket_timeout', $this->options['connection_timeout']);
173
        }
174
175
        $response = parent::__doRequest($request, $location, $action, $version, $one_way);
176
177
        $this->postCall($id->toString(), $action, $response);
178
179
        if ($socketTimeout !== false) {
180
            ini_set('default_socket_timeout', $socketTimeout);
181
        }
182
183
        return $response;
184
    }
185
186
    /**
187
     * Triggered before a request is executed
188
     *
189
     * @param string $id
190
     * @param string $resource
191
     * @param string $requestContent
192
     */
193 6
    protected function preCall(string $id, string $resource, string $requestContent = null)
194
    {
195 6
        if (null !== $this->dispatcher) {
196 6
            $this->dispatcher->dispatch(Events::REQUEST, new RequestEvent($id, $resource, $requestContent));
197
        }
198 6
    }
199
200
    /**
201
     * @param string $id
202
     * @param string $resource
203
     * @param string $response
204
     */
205 6
    protected function postCall(string $id, string $resource, string $response = null)
206
    {
207 6
        if (null !== $this->dispatcher) {
208 6
            $responseEvent = new ResponseEvent(
209 6
                $id,
210 4
                $resource,
211 6
                $this->__getLastRequest(),
212 6
                $this->__getLastRequestHeaders(),
213 4
                $response,
214 6
                $this->__getLastResponseHeaders()
215
            );
216 6
            $this->dispatcher->dispatch(Events::RESPONSE, $responseEvent);
217
        }
218 6
    }
219
220
    /**
221
     * @param string $id
222
     * @param string $resource
223
     * @param string $requestContent
224
     * @param \Exception $exception
225
     */
226 3
    protected function faultCall(string $id, string $resource, string $requestContent, \Exception $exception)
227
    {
228 3
        if (null !== $this->dispatcher) {
229 3
            $this->dispatcher->dispatch(
230 3
                Events::FAULT,
231 3
                new FaultEvent($id, $exception, new RequestEvent($id, $resource, $requestContent))
232
            );
233
        }
234 3
    }
235
236
    /**
237
     * @param string $wsdl
238
     * @return string
239
     */
240 18
    protected function resolveLocation($wsdl)
241
    {
242 18
        $wsdlUrl = parse_url($wsdl);
243
244 18
        return ((isset($wsdlUrl['scheme'])) ? $wsdlUrl['scheme'].'://' : '')
245 18
            .((isset($wsdlUrl['user'])) ? $wsdlUrl['user']
246 18
                .((isset($wsdlUrl['pass'])) ? ':'.$wsdlUrl['pass'] : '').'@' : '')
247 18
            .((isset($wsdlUrl['host'])) ? $wsdlUrl['host'] : '')
248 18
            .((isset($wsdlUrl['port'])) ? ':'.$wsdlUrl['port'] : '')
249 18
            .((isset($wsdlUrl['path'])) ? $wsdlUrl['path'] : '');
250
    }
251
252
    /**
253
     * @param array $mockRequests
254
     */
255 12
    public function setMockRequests(array $mockRequests)
256
    {
257 12
        $this->mockRequests = $mockRequests;
258 12
    }
259
260
    /**
261
     * @param array $mockResponses
262
     */
263 12
    public function setMockResponses(array $mockResponses)
264
    {
265 12
        $this->mockResponses = $mockResponses;
266 12
    }
267
268
    /**
269
     * @param EventDispatcherInterface $dispatcher
270
     */
271 18
    public function setDispatcher(EventDispatcherInterface $dispatcher)
272
    {
273 18
        $this->dispatcher = $dispatcher;
274 18
    }
275
276
    /**
277
     * @param $function_name
278
     * @param $arguments
279
     * @param $e
280
     */
281 3
    protected function handleFault($function_name, $arguments, $e): void
282
    {
283 3
        $request = $this->__getLastRequest();
284 3
        if ($request === null) { //only dispatch this when no request was fired
285 3
            $request = implode(' ', $arguments);
286 3
            $id      = Uuid::uuid1();
287 3
            $this->faultCall($id->toString(), $function_name, $request, $e);
288
        }
289
290 3
        throw $e;
291
    }
292
}
293