Completed
Pull Request — master (#50)
by
unknown
03:51
created

ExchangeWebServices::processResponse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3.072

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 19
ccs 8
cts 10
cp 0.8
rs 9.4285
cc 3
eloc 10
nc 3
nop 1
crap 3.072
1
<?php
2
/**
3
 * Contains ExchangeWebServices.
4
 */
5
6
7
namespace garethp\ews\API;
8
9
use garethp\ews\API\Exception\ExchangeException;
10
use garethp\ews\API\Exception\NoResponseReturnedException;
11
use garethp\ews\API\Exception\ServiceUnavailableException;
12
use garethp\ews\API\Exception\UnauthorizedException;
13
use garethp\ews\API\Message;
14
use garethp\ews\API\Type\EmailAddressType;
15
16
/**
17
 * Base class of the Exchange Web Services application.
18
 *
19
 *
20
 *
21
 * @package php-ews\Client
22
 *
23
 * @method Type AddDelegate($request)
24
 * @method Type ApplyConversationAction($request)
25
 * @method Type ConvertId($request)
26
 * @method Type CopyFolder($request)
27
 * @method Type CopyItem($request)
28
 * @method Type CreateAttachment($request)
29
 * @method Type CreateFolder($request)
30
 * @method Type CreateItem($request)
31
 * @method Type CreateManagedFolder($request)
32
 * @method Type CreateUserConfiguration($request)
33
 * @method Type DeleteAttachment($request)
34
 * @method Type DeleteFolder($request)
35
 * @method Type DeleteItem($request)
36
 * @method Type DeleteUserConfiguration($request)
37
 * @method Type DisconnectPhoneCall($request)
38
 * @method Type EmptyFolder($request)
39
 * @method Type ExpandDL($request)
40
 * @method Type ExportItems($request)
41
 * @method Type FindConversation($request)
42
 * @method Type FindFolder($request)
43
 * @method Type FindItem($request)
44
 * @method Type FindMessageTrackingReport($request)
45
 * @method Type GetAttachment($request)
46
 * @method Type GetDelegate($request)
47
 * @method Type GetEvents($request)
48
 * @method Type GetFolder($request)
49
 * @method Type GetInboxRules($request)
50
 * @method Type GetItem($request)
51
 * @method Type GetMailTips($request)
52
 * @method Type GetMessageTrackingReport($request)
53
 * @method Type GetPasswordExpirationDate($request)
54
 * @method Type GetPhoneCallInformation($request)
55
 * @method Type GetRoomLists($request)
56
 * @method Type GetRooms($request)
57
 * @method Type GetServerTimeZones($request)
58
 * @method Type GetServiceConfiguration($request)
59
 * @method Type GetSharingFolder($request)
60
 * @method Type GetSharingMetadata($request)
61
 * @method Type GetStreamingEvents($request)
62
 * @method Type GetUserAvailability($request)
63
 * @method Type GetUserConfiguration($request)
64
 * @method Type GetUserOofSettings($request)
65
 * @method Type MoveFolder($request)
66
 * @method Type MoveItem($request)
67
 * @method Type PlayOnPhone($request)
68
 * @method Type RefreshSharingFolder($request)
69
 * @method Type RemoveDelegate($request)
70
 * @method Type ResolveNames($request)
71
 * @method Type SendItem($request)
72
 * @method Type SetUserOofSettings($request)
73
 * @method Type Subscribe($request)
74
 * @method Type SyncFolderHierarchy($request)
75
 * @method Type SyncFolderItems($request)
76
 * @method Type Unsubscribe($request)
77
 * @method Type UpdateDelegate($request)
78
 * @method Type UpdateFolder($request)
79
 * @method Type UpdateInboxRules($request)
80
 * @method Type UpdateItem($request)
81
 * @method Type UpdateUserConfiguration($request)
82
 * @method Type UploadItems($request)
83
 */
84
class ExchangeWebServices
85
{
86
87
    const VERSION_2007 = 'Exchange2007';
88
89
    const VERSION_2007_SP1 = 'Exchange2007_SP1';
90
91
    const VERSION_2010 = 'Exchange2010';
92
93
    const VERSION_2010_SP1 = 'Exchange2010_SP1';
94
95
    const VERSION_2010_SP2 = 'Exchange2010_SP2';
96
97
    const VERSION_2013 = 'Exchange2013';
98
99
    const VERSION_2013_SP1 = 'Exchange2013_SP1';
100
101
    /**
102
     * Password to use when connecting to the Exchange server.
103
     *
104
     * @var string
105
     */
106
    protected $password = null;
107
108
    /**
109
     * Location of the Exchange server.
110
     *
111
     * @var string
112
     */
113
    protected $server = null;
114
115
    /**
116
     * SOAP client used to make the request
117
     *
118
     * @var NTLMSoapClient
119
     */
120
    protected $soap = null;
121
122
    /**
123
     * Username to use when connecting to the Exchange server.
124
     *
125
     * @var string
126
     */
127
    protected $username = null;
128
129
    /**
130
     * @var EmailAddressType
131
     */
132
    protected $primarySmtpMailbox = null;
133
134
    /**
135
     * A setting to check whether or not responses should be drilled down before being
136
     * returned. Setting this to false
137
     * will return the raw responses without any filtering
138
     *
139
     * @var bool
140
     */
141
    protected $drillDownResponses = true;
142
143
    /**
144
     * Miscrosoft Exchange version that we are going to connect to
145
     *
146
     * @var string
147
     */
148
    protected $version = null;
149
150
    protected $options = null;
151
152
    /**
153
     * The timezone for the client
154
     *
155
     * @var bool
156
     */
157
    protected $timezone = false;
158
159
    /**
160
     * @return EmailAddressType
161
     */
162 25
    public function getPrimarySmtpMailbox()
163
    {
164 25
        return $this->primarySmtpMailbox;
165
    }
166
167 1
    public function getPrimarySmtpEmailAddress()
168
    {
169 1
        if ($this->primarySmtpMailbox == null) {
170 1
            return null;
171
        }
172
173 1
        return $this->primarySmtpMailbox->getEmailAddress();
174
    }
175
176 2
    public function setPrimarySmtpEmailAddress($emailAddress)
177
    {
178 2
        $mailbox = new EmailAddressType();
179 2
        $mailbox->setEmailAddress($emailAddress);
180 2
        $this->primarySmtpMailbox = $mailbox;
181
182 2
        return $this;
183
    }
184
185
    /**
186
     * @param boolean $timezone
187
     */
188
    public function setTimezone($timezone)
189
    {
190
        $this->timezone = $timezone;
191
    }
192
193
    /**
194
     * @return string
195
     */
196 2
    public function getVersion()
197
    {
198 2
        return $this->version;
199
    }
200
201
    /**
202
     * @return string
203
     */
204
    public function getServer()
205
    {
206
        return $this->server;
207
    }
208
209
    /**
210
     * Constructor for the ExchangeWebServices class
211
     *
212
     * @deprecated Since 0.6.3
213
     * @param string $server
214
     * @param string $username
215
     * @param string $password
216
     * @param array $options
217
     */
218 33
    public function __construct($server = null, $username = null, $password = null, $options = array())
219
    {
220 33
        if ($server !== null) {
221 1
            $this->createClient(
222 1
                $server,
223 1
                ExchangeWebServicesAuth::fromUsernameAndPassword($username, $password),
224
                $options
225 1
            );
226 1
        }
227 33
    }
228
229 31
    public static function fromUsernameAndPassword($server, $username, $password, $options)
230
    {
231 31
        $self = new self();
232 31
        $self->createClient($server, ExchangeWebServicesAuth::fromUsernameAndPassword($username, $password), $options);
233
234 31
        return $self;
235
    }
236
237 1
    public static function fromCallbackToken($server, $token, $options)
238
    {
239 1
        $self = new self();
240 1
        $self->createClient($server, ExchangeWebServicesAuth::fromCallbackToken($token), $options);
241
242 1
        return $self;
243
    }
244
245 33
    protected function createClient($server, $auth, $options)
246
    {
247 33
        $location = 'https://'.$this->cleanServerUrl($server).'/EWS/Exchange.asmx';
248
249 33
        $options = array_replace_recursive([
250 33
            'version' => self::VERSION_2007,
251 33
            'trace' => 1,
252 33
            'exceptions' => true,
253 33
            'classmap' => ClassMap::getClassMap(),
254
            'drillDownResponses' => true
255 33
        ], $options);
256
257 33
        $this->server = $server;
258 33
        $this->version = $options['version'];
259
260 33
        $this->soap = new NTLMSoapClient(
261 33
            $location,
262 33
            $auth,
263 33
            dirname(__FILE__).'/../../Resources/wsdl/services.wsdl',
264
            $options
265 33
        );
266
267 33
        if (isset($options['primarySmtpEmailAddress'])) {
268 1
            $this->setPrimarySmtpEmailAddress($options['primarySmtpEmailAddress']);
269 1
        }
270
271 33
        if (isset($options['impersonation'])) {
272 1
            $this->setPrimarySmtpEmailAddress($options['impersonation']);
273 1
        }
274
275 33
        $this->drillDownResponses = $options['drillDownResponses'];
276 33
    }
277
278
    /**
279
     * @codeCoverageIgnore
280
     *
281
     * @param $name
282
     * @param $arguments
283
     * @return Type
284
     * @throws \garethp\ews\API\Exception
285
     */
286
    public function __call($name, $arguments)
287
    {
288
        $response = $this->getClient()->__call($name, $arguments);
289
290
        return $this->processResponse($response);
291
    }
292
293
    /**
294
     * Returns the SOAP Client that may be used to make calls against the server
295
     *
296
     * @return NTLMSoapClient
297
     */
298 31
    public function getClient()
299
    {
300 31
        return $this->soap;
301
    }
302
303
    /**
304
     * Sets the client
305
     *
306
     * @param NTLMSoapClient $client
307
     * @return $this
308
     */
309 2
    public function setClient($client)
310
    {
311 2
        $this->soap = $client;
312
313 2
        return $this;
314
    }
315
316
    /**
317
     * Cleans the server URL for usage
318
     *
319
     * @param $server
320
     * @return string
321
     */
322 40
    public function cleanServerUrl($server)
323
    {
324 40
        $url = parse_url($server);
325 40
        if (!isset($url['host']) && isset($url['path'])) {
326 35
            $url['host'] = $url['path'];
327 35
            unset($url['path']);
328 35
        }
329
330 40
        $server = $url['host'];
331 40
        if (isset($url['port'])) {
332 2
            $server .= ':'.$url['port'];
333 2
        }
334
335 40
        if (isset($url['path'])) {
336 4
            $server .= $url['path'];
337 4
        }
338
339 40
        $server = rtrim($server, "/");
340
341 40
        return $server;
342
    }
343
344
    /**
345
     * Process a response to verify that it succeeded and take the appropriate
346
     * action
347
     *
348
     * @param \garethp\ews\API\Message\BaseResponseMessageType $response
349
     * @return Type[]
350
     * @throws \garethp\ews\API\Exception
351
     */
352 29
    protected function processResponse($response)
353
    {
354
        // If the soap call failed then we need to thow an exception.
355 29
        $code = $this->getClient()->getResponseCode();
356 29
        $this->handleNonSuccessfulResponses($response, $code);
357
358 27
        if (!$this->drillDownResponses) {
359
            return $response;
360
        }
361
362 27
        if (!$response->exists('responseMessages')) {
363
            return $response;
364
        }
365
366 27
        $response = $response->getResponseMessages();
367 27
        $response = $this->drillDownResponseLevels($response);
368
369 27
        return $response;
370
    }
371
372
    /**
373
     * @param $response
374
     * @return array
375
     * @throws \garethp\ews\API\Exception
376
     */
377 27
    public function drillDownResponseLevels($response)
378
    {
379 27
        $items = $this->getItemsFromResponse($response);
380
381 27
        if (count($items) == 1) {
382 27
            reset($items);
383 27
            $key = key($items);
384 27
            $methodName = "get$key";
385 27
            $response = $response->$methodName();
386
387 27
            return $this->drillDownResponseLevels($response);
388
        }
389
390 27
        if (is_array($items) && isset($items[1]) && $items[1] instanceof Message\ResponseMessageType) {
0 ignored issues
show
Bug introduced by
The class garethp\ews\API\Message\ResponseMessageType does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
391 1
            $response = array();
392 1
            foreach ($items as $responseItem) {
393 1
                $response[] = $this->drillDownResponseLevels($responseItem);
394 1
            }
395
396 1
            return $response;
397
        }
398
399 27
        return $response;
400
    }
401
402
    /**
403
     * @param $response
404
     * @return array
405
     * @throws ExchangeException
406
     */
407 27
    protected function getItemsFromResponse($response)
408
    {
409 27
        $items = array();
410 27
        if ($response instanceof Type) {
411 27
            $items = $response->getNonNullItems();
412 27
        }
413
414 27
        if (is_array($response)) {
415 1
            $items = $response;
416 1
        }
417
418 27
        if ($response instanceof Message\ResponseMessageType) {
0 ignored issues
show
Bug introduced by
The class garethp\ews\API\Message\ResponseMessageType does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
419 27
            if ($response->getResponseClass() !== "Success") {
420 1
                throw new ExchangeException($response->getMessageText());
421
            }
422
423 27
            unset($items['responseClass']);
424 27
            unset($items['responseCode']);
425 27
        }
426
427 27
        return $items;
428
    }
429
430
    /**
431
     * @param Message\BaseResponseMessageType $response
432
     * @param $code
433
     * @throws ExchangeException
434
     * @throws NoResponseReturnedException
435
     * @throws ServiceUnavailableException
436
     * @throws UnauthorizedException
437
     */
438 29
    protected function handleNonSuccessfulResponses($response, $code)
439
    {
440 29
        if ($code == 401) {
441
            throw new UnauthorizedException();
442
        }
443
444 29
        if ($code == 503) {
445
            throw new ServiceUnavailableException();
446
        }
447
448 29
        if ($code >= 300) {
449 2
            throw new ExchangeException('SOAP client returned status of ' . $code, $code);
450
        }
451
452 27
        if (empty($response) || empty($response->getNonNullResponseMessages())) {
453
            throw new NoResponseReturnedException();
454
        }
455 27
    }
456
}
457