API   B
last analyzed

Complexity

Total Complexity 47

Size/Duplication

Total Lines 518
Duplicated Lines 0 %

Test Coverage

Coverage 80.78%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 181
c 5
b 0
f 0
dl 0
loc 518
ccs 185
cts 229
cp 0.8078
rs 8.64
wmc 47

32 Methods

Rating   Name   Duplication   Size   Complexity  
A getMailbox() 0 7 1
A withCustomAuthentication() 0 6 1
A getServerTimezones() 0 14 2
A deleteFolder() 0 3 1
A getPrimarySmptEmailAddress() 0 7 2
A __construct() 0 4 2
A getNextPage() 0 17 3
A getPrimarySmtpMailbox() 0 3 1
A getDistinguishedFolderId() 0 6 1
A withCallbackToken() 0 6 1
A setPrimarySmtpEmailAddress() 0 5 1
A setClient() 0 5 1
A getItem() 0 14 2
A withUsernameAndPassword() 0 7 1
A getCalendar() 0 7 1
A getClient() 0 3 1
A getFolderByFolderId() 0 9 2
A getFolderByDisplayName() 0 11 3
A createContactsFolder() 0 7 2
A createCalendars() 0 7 2
A moveItem() 0 10 1
A getFolder() 0 16 1
A createItems() 0 13 1
A updateItems() 0 18 2
A deleteItems() 0 21 1
A createFolders() 0 19 2
A emptyFolder() 0 15 1
A deleteFolders() 0 11 1
A convertIdFormat() 0 16 1
A getFolderByDistinguishedId() 0 8 1
A listItemChanges() 0 20 2
A getChildrenFolders() 0 20 2

How to fix   Complexity   

Complex Class

Complex classes like API often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use API, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace garethp\ews;
4
5
use garethp\ews\API\ExchangeWebServices;
6
use garethp\ews\API\Message\EmptyFolderResponseType;
7
use garethp\ews\API\Message\GetServerTimeZonesType;
8
use garethp\ews\API\Message\SyncFolderItemsResponseMessageType;
9
use garethp\ews\API\Message\UpdateItemResponseMessageType;
10
use garethp\ews\API\Type;
11
use garethp\ews\API\Type\BaseFolderIdType;
12
13
/**
14
 * A base class for APIs
15
 *
16
 * Class BaseAPI
17
 * @package garethp\ews
18
 */
19
class API
20
{
21
    protected static $defaultClientOptions = array(
22
        'version' => ExchangeWebServices::VERSION_2010
23
    );
24
25 36
    public function __construct(ExchangeWebServices $client = null)
26
    {
27 36
        if ($client) {
28 36
            $this->setClient($client);
29
        }
30
    }
31
32
    /**
33
     * @return Type\EmailAddressType
34
     */
35 27
    public function getPrimarySmtpMailbox()
36
    {
37 27
        return $this->getClient()->getPrimarySmtpMailbox();
38
    }
39
40
    /**
41
     * Storing the API client
42
     * @var ExchangeWebServices
43
     */
44
    private $client;
45
46
    /**
47
     * Get a calendar item
48
     *
49
     * @param string $name
50
     * @return CalendarAPI
51
     */
52 6
    public function getCalendar($name = null)
53
    {
54 6
        $calendar = new CalendarAPI();
55 6
        $calendar->setClient($this->getClient());
56 6
        $calendar->pickCalendar($name);
57
58 6
        return $calendar;
59
    }
60
61
    /**
62
     * @param string $folderName
63
     * @return MailAPI
64
     */
65 7
    public function getMailbox($folderName = null)
66
    {
67 7
        $mailApi = new MailAPI();
68 7
        $mailApi->setClient($this->getClient());
69 7
        $mailApi->pickMailFolder($folderName);
70
71 7
        return $mailApi;
72
    }
73
74
    /**
75
     * Set the API client
76
     *
77
     * @param ExchangeWebServices $client
78
     * @return $this
79
     */
80 36
    public function setClient($client)
81
    {
82 36
        $this->client = $client;
83
84 36
        return $this;
85
    }
86
87
    /**
88
     * Get the API client
89
     *
90
     * @return ExchangeWebServices
91
     */
92 35
    public function getClient()
93
    {
94 35
        return $this->client;
95
    }
96
97 34
    public static function withUsernameAndPassword($server, $username, $password, $options = [])
98
    {
99 34
        return new static(ExchangeWebServices::fromUsernameAndPassword(
100 34
            $server,
101 34
            $username,
102 34
            $password,
103 34
            array_replace_recursive(self::$defaultClientOptions, $options)
104 34
        ));
105
    }
106
107 1
    public static function withCallbackToken($server, $token, $options = [])
108
    {
109 1
        return new static(ExchangeWebServices::fromCallbackToken(
110 1
            $server,
111 1
            $token,
112 1
            array_replace_recursive(self::$defaultClientOptions, $options)
113 1
        ));
114
    }
115
116 1
    public static function withCustomAuthentication($server, $authentication, $options = [])
117
    {
118 1
        return new static(ExchangeWebServices::fromCustomAuthentication(
119 1
            $server,
120 1
            $authentication,
121 1
            array_replace_recursive(self::$defaultClientOptions, $options)
122 1
        ));
123
    }
124
125 1
    public function getPrimarySmptEmailAddress()
126
    {
127 1
        if ($this->getPrimarySmtpMailbox() == null) {
128 1
            return null;
129
        }
130
131 1
        return $this->getPrimarySmtpMailbox()->getEmailAddress();
132
    }
133
134 1
    public function setPrimarySmtpEmailAddress($emailAddress)
135
    {
136 1
        $this->getClient()->setPrimarySmtpEmailAddress($emailAddress);
137
138 1
        return $this;
139
    }
140
141
    /**
142
     * Create items through the API client
143
     *
144
     * @param $items
145
     * @param array $options
146
     * @return Type
147
     */
148 16
    public function createItems($items, $options = array())
149
    {
150 16
        $items = Utilities\ensureIsArray($items);
151 16
        $request = array(
152 16
            'Items' => $items
153 16
        );
154
155 16
        $request = array_replace_recursive($request, $options);
156 16
        $request = Type::buildFromArray($request);
157
158 16
        $response = $this->getClient()->CreateItem($request);
159
160 16
        return $response;
161
    }
162
163 4
    public function updateItems($items, $options = array())
164
    {
165 4
        $request = array(
166 4
            'ItemChanges' => $items,
167 4
            'MessageDisposition' => 'SaveOnly',
168 4
            'ConflictResolution' => 'AlwaysOverwrite'
169 4
        );
170
171 4
        $request = array_replace_recursive($request, $options);
172
173 4
        $request = Type::buildFromArray($request);
174
175 4
        $response = $this->getClient()->UpdateItem($request);
176 4
        if ($response instanceof UpdateItemResponseMessageType) {
177 4
            return $response->getItems();
178
        }
179
180
        return Utilities\ensureIsArray($response);
181
    }
182
183 1
    public function createCalendars($names, BaseFolderIdType $parentFolder = null, $options = array())
184
    {
185 1
        if ($parentFolder === null) {
186 1
            $parentFolder = $this->getDistinguishedFolderId('calendar');
187
        }
188
189 1
        return $this->createFolders($names, $parentFolder, $options, 'IPF.Appointment');
190
    }
191
192
    public function createContactsFolder($names, BaseFolderIdType $parentFolder = null, $options = array())
193
    {
194
        if ($parentFolder === null) {
195
            $parentFolder = $this->getDistinguishedFolderId('contacts');
196
        }
197
198
        return $this->createFolders($names, $parentFolder, $options, 'IPF.Contact');
199
    }
200
201 4
    public function createFolders($names, BaseFolderIdType $parentFolder, $options = array(), $folderClass = null)
202
    {
203 4
        $names = Utilities\ensureIsArray($names);
204 4
        $names = array_map(function ($name) use ($folderClass) {
205 4
            return ['DisplayName' => $name, 'FolderClass' => $folderClass];
206 4
        }, $names);
207
208 4
        $request = [
209 4
            'Folders' => ['Folder' => $names]
210 4
        ];
211
212 4
        if ($parentFolder !== null) {
213 4
            $request['ParentFolderId'] = $parentFolder->toArray(true);
214
        }
215
216 4
        $request = array_merge_recursive($request, $options);
217
218 4
        $this->client->CreateFolder($request);
219 4
        return true;
220
    }
221
222
    /**
223
     * @deprecated Please use API::deleteFolders() instead
224
     *
225
     * @param BaseFolderIdType $folderId
226
     * @param array $options
227
     * @return Type
228
     */
229 3
    public function deleteFolder(BaseFolderIdType $folderId, $options = array())
230
    {
231 3
        return $this->deleteFolders($folderId, $options);
232
    }
233
234 4
    public function deleteFolders($folders, $options = array())
235
    {
236 4
        $folderIds = Utilities\getFolderIds($folders);
237
238 4
        $request = [
239 4
            'DeleteType' => 'HardDelete',
240 4
            'FolderIds' => $folderIds
241 4
        ];
242
243 4
        $request = array_merge_recursive($request, $options);
244 4
        return $this->client->DeleteFolder($request);
245
    }
246
247
    public function moveItem(Type\ItemIdType $itemId, BaseFolderIdType $folderId, $options = array())
248
    {
249
        $request = array(
250
            'ToFolderId' => $folderId->toArray(true),
251
            'ItemIds' => array('ItemId' => $itemId->toArray())
252
        );
253
254
        $request = array_merge_recursive($request, $options);
255
256
        return $this->client->MoveItem($request);
257
    }
258
259
    /**
260
     * @param $items Type\ItemIdType|Type\ItemIdType[]
261
     * @param array $options
262
     * @return bool
263
     */
264 16
    public function deleteItems($items, $options = array())
265
    {
266 16
        $items = Utilities\ensureIsArray($items, true);
267
268 16
        $items = array_map(function ($item) {
269 16
            $item = Type\ItemIdType::buildFromArray($item);
270
271 16
            return $item->toArray();
272 16
        }, $items);
273
274 16
        $request = array(
275 16
            'ItemIds' => array('ItemId' => $items),
276 16
            'DeleteType' => 'MoveToDeletedItems'
277 16
        );
278
279 16
        $request = array_replace_recursive($request, $options);
280 16
        $request = Type::buildFromArray($request);
281 16
        $this->getClient()->DeleteItem($request);
282
283
        //If the delete fails, an Exception will be thrown in processResponse before it gets here
284 16
        return true;
285
    }
286
287
    /**
288
     * @param $identifier
289
     * @param array $options
290
     * @return Type\BaseFolderType
291
     */
292 13
    public function getFolder($identifier, $options = [])
293
    {
294 13
        $request = array(
295 13
            'FolderShape' => array(
296 13
                'BaseShape' => array('_' => 'Default')
297 13
            ),
298 13
            'FolderIds' => $identifier
299 13
        );
300
301 13
        $request = array_replace_recursive($request, $options);
302
303 13
        $request = Type::buildFromArray($request);
304
305 13
        $response = $this->getClient()->GetFolder($request);
306
307 13
        return $response;
308
    }
309
310
    /**
311
     * Get a folder by it's distinguishedId
312
     *
313
     * @param string $distinguishedId
314
     * @param array $options
315
     * @return Type\BaseFolderType
316
     */
317 9
    public function getFolderByDistinguishedId($distinguishedId, $options = [])
318
    {
319 9
        return $this->getFolder(array(
320 9
            'DistinguishedFolderId' => array(
321 9
                'Id' => $distinguishedId,
322 9
                'Mailbox' => $this->getPrimarySmtpMailbox()
323 9
            )
324 9
        ), $options);
325
    }
326
327
    /**
328
     * @param string|BaseFolderIdType $folderId
329
     * @param array $options
330
     * @return Type\BaseFolderType
331
     * @throws API\Exception
332
     */
333 4
    public function getFolderByFolderId($folderId, $options = [])
334
    {
335 4
        if (is_string($folderId)) {
336
            $folderId = ['FolderId' => ['Id' => $folderId, 'Mailbox' => $this->getPrimarySmtpMailbox()]];
337
        } else {
338 4
            $folderId = $folderId->toArray(true);
339
        }
340
341 4
        return $this->getFolder($folderId, $options);
342
    }
343
344
    /**
345
     * @param string|BaseFolderIdType $parentFolderId
346
     * @param array $options
347
     * @return Type\BaseFolderType[]
348
     */
349 25
    public function getChildrenFolders($parentFolderId = 'root', array $options = array())
350
    {
351 25
        if (is_string($parentFolderId)) {
352 17
            $parentFolderId = $this->getDistinguishedFolderId($parentFolderId);
353
        }
354
355 25
        $request = array(
356 25
            'Traversal' => 'Shallow',
357 25
            'FolderShape' => array(
358 25
                'BaseShape' => 'AllProperties'
359 25
            ),
360 25
            'ParentFolderIds' => $parentFolderId->toArray(true)
361 25
        );
362
363 25
        $request = array_replace_recursive($request, $options);
364
365 25
        $request = Type::buildFromArray($request);
366
367
        /** @var \garethp\ews\API\Message\FindFolderResponseMessageType $folders */
368 25
        return $this->getClient()->FindFolder($request);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getClient()->FindFolder($request) returns the type garethp\ews\API\Type which is incompatible with the documented return type garethp\ews\API\Type\BaseFolderType[].
Loading history...
369
    }
370
371
    /**
372
     * @param string $folderName
373
     * @param string|BaseFolderIdType $parentFolderId
374
     * @param array $options
375
     * @return bool|Type\BaseFolderType
376
     */
377 25
    public function getFolderByDisplayName($folderName, $parentFolderId = 'root', $options = array())
378
    {
379 25
        $folders = $this->getChildrenFolders($parentFolderId, $options);
380
381 25
        foreach ($folders as $folder) {
382 25
            if ($folder->getDisplayName() === $folderName) {
383 24
                return $folder;
384
            }
385
        }
386
387 4
        return false;
388
    }
389
390
    /**
391
     * @param $itemId array|Type\ItemIdType
392
     * @param array $options
393
     * @return Type
394
     */
395 5
    public function getItem($itemId, $options = array())
396
    {
397 5
        if ($itemId instanceof Type\ItemIdType) {
398 4
            $itemId = $itemId->toArray();
399
        }
400
401 5
        $request = array(
402 5
            'ItemShape' => array('BaseShape' => 'AllProperties'),
403 5
            'ItemIds' => array('ItemId' => $itemId)
404 5
        );
405
406 5
        $request = array_replace_recursive($request, $options);
407
408 5
        return $this->getClient()->GetItem($request);
409
    }
410
411
    /**
412
     * Get a list of sync changes on a folder
413
     *
414
     * @param BaseFolderIdType $folderId
415
     * @param null $syncState
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $syncState is correct as it would always require null to be passed?
Loading history...
416
     * @param array $options
417
     * @return SyncFolderItemsResponseMessageType
418
     */
419 2
    public function listItemChanges($folderId, $syncState = null, array $options = array())
420
    {
421 2
        $request = array(
422 2
            'ItemShape' => array('BaseShape' => 'AllProperties'),
423 2
            'SyncFolderId' => $folderId->toArray(true),
424 2
            'SyncScope' => 'NormalItems',
425 2
            'MaxChangesReturned' => '100'
426 2
        );
427
428 2
        if ($syncState != null) {
429 1
            $request['SyncState'] = $syncState;
430 1
            $request['ItemShape']['BaseShape'] = 'AllProperties';
431
        }
432
433 2
        $request = array_replace_recursive($request, $options);
434
435 2
        $request = Type::buildFromArray($request);
436 2
        $response = $this->getClient()->SyncFolderItems($request);
437
438 2
        return $response;
439
    }
440
441
    public function getServerTimezones($timezoneIDs = array(), $fullTimezoneData = false)
442
    {
443
        $request = GetServerTimeZonesType::buildFromArray(array(
444
            'returnFullTimeZoneData' => $fullTimezoneData
445
        ));
446
447
        if (!empty($timezoneIDs)) {
448
            $request->setIds($timezoneIDs);
449
        }
450
451
        $timezones = $this->getClient()->GetServerTimeZones($request);
452
        $timezones = $timezones->TimeZoneDefinition;
0 ignored issues
show
Bug introduced by
The property TimeZoneDefinition does not seem to exist on garethp\ews\API\Type.
Loading history...
453
454
        return Utilities\ensureIsArray($timezones);
455
    }
456
457
    /**
458
     * @param Type\ItemIdType $itemId
459
     * @param $fromType
460
     * @param $destinationType
461
     * @param $mailbox
462
     *
463
     * @return Type\ItemIdType
464
     */
465
    public function convertIdFormat(Type\ItemIdType $itemId, $fromType, $destinationType, $mailbox)
466
    {
467
        $result = $this->getClient()->ConvertId(array(
468
            'DestinationFormat' => $destinationType,
469
            'SourceIds' => array(
470
                'AlternateId' => array(
471
                    'Format' => $fromType,
472
                    'Id' => $itemId->getId(),
473
                    'Mailbox' => $mailbox
474
                )
475
            )
476
        ));
477
478
        $itemId->setId($result->getId());
0 ignored issues
show
Bug introduced by
The method getId() does not exist on garethp\ews\API\Type. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

478
        $itemId->setId($result->/** @scrutinizer ignore-call */ getId());
Loading history...
479
480
        return $itemId;
481
    }
482
483
    /**
484
     * @param Type\FindItemParentType|Type\FindFolderParentType $result
485
     *
486
     * @return Type\FindItemParentType|Type\FindFolderParentType
487
     */
488 2
    public function getNextPage($result)
489
    {
490 2
        if ($result->isIncludesLastItemInRange()) {
491
            return $result;
492
        }
493
494 2
        $currentPage = $result->getCurrentPage();
495 2
        $currentPage->setOffset($result->getIndexedPagingOffset());
496
497 2
        $lastRequest = $result->getLastRequest();
498 2
        $lastRequest->setIndexedPage($currentPage);
499
500 2
        if ($result instanceof Type\FindFolderParentType) {
501 1
            return $this->getClient()->FindFolder($lastRequest);
502
        }
503
504 1
        return $this->getClient()->FindItem($lastRequest);
505
    }
506
507
    /**
508
     * @param BaseFolderIdType $folderId
509
     * @param string $deleteType
510
     * @param bool $deleteSubFolders
511
     * @param array $options
512
     * @return EmptyFolderResponseType
513
     */
514
    public function emptyFolder(
515
        BaseFolderIdType $folderId,
516
        $deleteType = 'SoftDelete',
517
        $deleteSubFolders = false,
518
        array $options = []
519
    ) {
520
        $request = [
521
            'DeleteType' => $deleteType,
522
            'DeleteSubFolders' => $deleteSubFolders,
523
            'FolderIds' => $folderId->toArray(true)
524
        ];
525
526
        $request = array_merge_recursive($request, $options);
527
528
        return $this->getClient()->EmptyFolder($request);
529
    }
530
531 18
    protected function getDistinguishedFolderId($id = null, $changeKey = null)
532
    {
533 18
        return new Type\DistinguishedFolderIdType(
534 18
            $id,
535 18
            $changeKey,
536 18
            $this->getPrimarySmtpMailbox()
537 18
        );
538
    }
539
}
540