Completed
Push — master ( 53001c...a108e7 )
by Gareth
03:19
created

ExchangeWebServices   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 331
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 93.1%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 38
c 2
b 0
f 0
lcom 1
cbo 8
dl 0
loc 331
ccs 108
cts 116
cp 0.931
rs 8.3999

14 Methods

Rating   Name   Duplication   Size   Complexity  
A getPrimarySmtpMailbox() 0 4 1
A getPrimarySmtpEmailAddress() 0 8 2
A setPrimarySmtpEmailAddress() 0 8 1
A fromUsernameAndPassword() 0 7 1
A fromCallbackToken() 0 7 1
A __call() 0 6 1
A getClient() 0 4 1
A setClient() 0 6 1
A setTimezone() 0 4 1
B createClient() 0 29 3
B cleanServerUrl() 0 21 5
C processResponse() 0 35 8
D drillDownResponseLevels() 0 34 10
A __construct() 0 14 2
1
<?php
2
/**
3
 * Contains ExchangeWebServices.
4
 */
5
6
namespace garethp\ews\API;
7
8
use garethp\ews\API\Exception\ExchangeException;
9
use garethp\ews\API\Exception\NoResponseReturnedException;
10
use garethp\ews\API\Exception\ServiceUnavailableException;
11
use garethp\ews\API\Exception\UnauthorizedException;
12
use garethp\ews\API\Message;
13
use garethp\ews\API\Type\EmailAddressType;
14
15
/**
16
 * Base class of the Exchange Web Services application.
17
 *
18
 * @package php-ews\Client
19
 *
20
 * @method Type CreateItem($request)
21
 * @method Type FindItem($request)
22
 * @method Type GetFolder($request)
23
 * @method Type SyncFolderItems($request)
24
 * @method Type FindFolder($request)
25
 * @method Type UpdateItem($request)
26
 * @method Type DeleteItem($request)
27
 * @method Type GetItem($request)
28
 */
29
class ExchangeWebServices
30
{
31
    const VERSION_2007 = 'Exchange2007';
32
    const VERSION_2007_SP1 = 'Exchange2007_SP1';
33
    const VERSION_2007_SP2 = 'Exchange2007_SP2';
34
    const VERSION_2007_SP3 = 'Exchange2007_SP3';
35
36
    const VERSION_2010 = 'Exchange2010';
37
    const VERSION_2010_SP1 = 'Exchange2010_SP1';
38
    const VERSION_2010_SP2 = 'Exchange2010_SP2';
39
    const VERSION_2010_SP3 = 'Exchange2010_SP3';
40
41
    const VERSION_2013 = 'Exchange2013';
42
    const VERSION_2013_SP1 = 'Exchange2013_SP1';
43
44
    /**
45
     * Password to use when connecting to the Exchange server.
46
     *
47
     * @var string
48
     */
49
    protected $password;
50
51
    /**
52
     * Location of the Exchange server.
53
     *
54
     * @var string
55
     */
56
    protected $server;
57
58
    /**
59
     * SOAP client used to make the request
60
     *
61
     * @var NTLMSoapClient
62
     */
63
    protected $soap;
64
65
    /**
66
     * Username to use when connecting to the Exchange server.
67
     *
68
     * @var string
69
     */
70
    protected $username;
71
72
    /**
73
     * @var EmailAddressType
74
     */
75
    protected $primarySmtpMailbox;
76
77
    /**
78
     * A setting to check whether or not responses should be drilled down before being returned. Setting this to false
79
     * will return the raw responses without any filtering
80
     *
81
     * @var bool
82
     */
83
    protected $drillDownResponses = true;
84
85
    /**
86
     * @return EmailAddressType
87
     */
88 20
    public function getPrimarySmtpMailbox()
89
    {
90 20
        return $this->primarySmtpMailbox;
91
    }
92
93 1
    public function getPrimarySmtpEmailAddress()
94
    {
95 1
        if ($this->primarySmtpMailbox == null) {
96 1
            return null;
97
        }
98
99 1
        return $this->primarySmtpMailbox->getEmailAddress();
100
    }
101
102 2
    public function setPrimarySmtpEmailAddress($emailAddress)
103
    {
104 2
        $mailbox = new EmailAddressType();
105 2
        $mailbox->setEmailAddress($emailAddress);
106 2
        $this->primarySmtpMailbox = $mailbox;
107
108 2
        return $this;
109
    }
110
111
    /**
112
     * Miscrosoft Exchange version that we are going to connect to
113
     *
114
     * @var string
115
     *
116
     * @see ExchangeWebServices::VERSION_2007
117
     * @see ExchangeWebServices::VERSION_2007_SP1
118
     * @see ExchangeWebServices::VERSION_2010
119
     * @see ExchangeWebServices::VERSION_2010_SP1
120
     */
121
    protected $version;
122
123
    protected $options;
124
125
    /**
126
     * The timezone for the client
127
     *
128
     * @var bool
129
     */
130
    protected $timezone = false;
131
132
    /**
133
     * @param boolean $timezone
134
     */
135
    public function setTimezone($timezone)
136
    {
137
        $this->timezone = $timezone;
138
    }
139
140
    /**
141
     * Constructor for the ExchangeWebServices class
142
     *
143
     * @deprecated Since 0.6.3
144
     * @param string $server
145
     * @param string $username
146
     * @param string $password
147
     * @param array $options
148
     */
149 28
    public function __construct(
150
        $server = null,
151
        $username = null,
152
        $password = null,
153
        $options = []
154
    ) {
155 28
        if ($server !== null) {
156 1
            $this->createClient(
157 1
                $server,
158 1
                ExchangeWebServicesAuth::fromUsernameAndPassword($username, $password),
159
                $options
160 1
            );
161 1
        }
162 28
    }
163
164 26
    public static function fromUsernameAndPassword($server, $username, $password, $options)
165
    {
166 26
        $self = new static();
167 26
        $self->createClient($server, ExchangeWebServicesAuth::fromUsernameAndPassword($username, $password), $options);
168
169 26
        return $self;
170
    }
171
172 1
    public static function fromCallbackToken($server, $token, $options)
173
    {
174 1
        $self = new static();
175 1
        $self->createClient($server, ExchangeWebServicesAuth::fromCallbackToken($token), $options);
176
177 1
        return $self;
178
    }
179
180 28
    protected function createClient($server, $auth, $options)
181
    {
182 28
        $location = 'https://' . $this->cleanServerUrl($server) . '/EWS/Exchange.asmx';
183
184 28
        $options = array_replace_recursive([
185 28
            'version' => self::VERSION_2007,
186 28
            'trace' => 1,
187 28
            'exceptions' => true,
188 28
            'classmap' => ClassMap::getClassMap(),
189
            'drillDownResponses' => true
190 28
        ], $options);
191
192 28
        $this->soap = new NTLMSoapClient(
193 28
            $location,
194 28
            $auth,
195 28
            dirname(__FILE__) . '/../../Resources/wsdl/services.wsdl',
196
            $options
197 28
        );
198
199 28
        if (isset($options['primarySmtpEmailAddress'])) {
200 1
            $this->setPrimarySmtpEmailAddress($options['primarySmtpEmailAddress']);
201 1
        }
202
203 28
        if (isset($options['impersonation'])) {
204 1
            $this->setPrimarySmtpEmailAddress($options['impersonation']);
205 1
        }
206
207 28
        $this->drillDownResponses = $options['drillDownResponses'];
208 28
    }
209
210
    /**
211
     * @codeCoverageIgnore
212
     *
213
     * @param $name
214
     * @param $arguments
215
     * @return Type
216
     * @throws \garethp\ews\API\Exception
217
     */
218
    public function __call($name, $arguments)
219
    {
220
        $response = $this->getClient()->__call($name, $arguments);
221
222
        return $this->processResponse($response);
223
    }
224
225
    /**
226
     * Returns the SOAP Client that may be used to make calls against the server
227
     *
228
     * @return NTLMSoapClient
229
     */
230 26
    public function getClient()
231
    {
232 26
        return $this->soap;
233
    }
234
235
    /**
236
     * Sets the client
237
     *
238
     * @param NTLMSoapClient $client
239
     * @return $this
240
     */
241 2
    public function setClient($client)
242
    {
243 2
        $this->soap = $client;
244
245 2
        return $this;
246
    }
247
248
    /**
249
     * Cleans the server URL for usage
250
     *
251
     * @param $server
252
     * @return string
253
     */
254 35
    public function cleanServerUrl($server)
255
    {
256 35
        $url = parse_url($server);
257 35
        if (!isset($url['host']) && isset($url['path'])) {
258 30
            $url['host'] = $url['path'];
259 30
            unset($url['path']);
260 30
        }
261
262 35
        $server = $url['host'];
263 35
        if (isset($url['port'])) {
264 2
            $server .= ':' . $url['port'];
265 2
        }
266
267 35
        if (isset($url['path'])) {
268 4
            $server .= $url['path'];
269 4
        }
270
271 35
        $server = rtrim($server, "/");
272
273 35
        return $server;
274
    }
275
276
    /**
277
     * Process a response to verify that it succeeded and take the appropriate
278
     * action
279
     *
280
     * @param \garethp\ews\API\Message\BaseResponseMessageType $response
281
     * @return \garethp\ews\API\Message\ArrayOfResponseMessageType|\garethp\ews\API\Message\ResponseMessageType
282
     * @throws \garethp\ews\API\Exception
283
     */
284 24
    protected function processResponse($response)
285
    {
286
        // If the soap call failed then we need to thow an exception.
287 24
        $code = $this->getClient()->getResponseCode();
288 24
        if ($code == 401) {
289
            throw new UnauthorizedException();
290
        }
291
292 24
        if ($code == 503) {
293
            throw new ServiceUnavailableException();
294
        }
295
296 24
        if ($code != 200) {
297 2
            throw new ExchangeException('SOAP client returned status of ' . $code, $code);
298
        }
299
300 22
        if (empty($response) ||
301 22
            empty($response->getNonNullResponseMessages())
302 22
        ) {
303
            throw new NoResponseReturnedException();
304
        }
305
306 22
        if (!$this->drillDownResponses) {
307
            return $response;
308
        }
309
310 22
        if (!$response->exists('responseMessages')) {
311
            return $response;
312
        }
313
314 22
        $response = $response->getResponseMessages();
315 22
        $response = $this->drillDownResponseLevels($response);
316
317 22
        return $response;
318
    }
319
320
    /**
321
     * @param $response
322
     * @return array
323
     * @throws \garethp\ews\API\Exception
324
     */
325 22
    public function drillDownResponseLevels($response)
326
    {
327 22
        $items = array();
328 22
        if ($response instanceof Type) {
329 22
            $items = $response->getNonNullItems();
330 22
        } elseif (is_array($response)) {
331 1
            $items = $response;
332 1
        }
333
334 22
        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...
335 22
            if ($response->getResponseClass() !== "Success") {
336 1
                throw new ExchangeException($response->getMessageText());
337
            }
338
339 22
            unset($items['responseClass']);
340 22
            unset($items['responseCode']);
341 22
        }
342
343 22
        if (count($items) == 1) {
344 22
            reset($items);
345 22
            $key = key($items);
346 22
            $methodName = "get$key";
347 22
            $response = $response->$methodName();
348
349 22
            $response = $this->drillDownResponseLevels($response);
350 22
        } elseif (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...
351 1
            $response = array();
352 1
            foreach ($items as $responseItem) {
353 1
                $response[] = $this->drillDownResponseLevels($responseItem);
354 1
            }
355 1
        }
356
357 22
        return $response;
358
    }
359
}
360