Completed
Push — master ( d328d0...51fcf8 )
by Gareth
03:07
created

API   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 512
Duplicated Lines 10.16 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 80.38%

Importance

Changes 0
Metric Value
dl 52
loc 512
ccs 168
cts 209
cp 0.8038
rs 8.72
c 0
b 0
f 0
wmc 46
lcom 1
cbo 4

31 Methods

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

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 34
    public function __construct(ExchangeWebServices $client = null)
26
    {
27 34
        if ($client) {
28 34
            $this->setClient($client);
29 34
        }
30 34
    }
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 34
    public function setClient($client)
81
    {
82 34
        $this->client = $client;
83
84 34
        return $this;
85
    }
86
87
    /**
88
     * Get the API client
89
     *
90
     * @return ExchangeWebServices
91
     */
92 34
    public function getClient()
93
    {
94 34
        return $this->client;
95
    }
96
97 33
    public static function withUsernameAndPassword($server, $username, $password, $options = [])
98
    {
99 33
        return new static(ExchangeWebServices::fromUsernameAndPassword(
100 33
            $server,
101 33
            $username,
102 33
            $password,
103 33
            array_replace_recursive(self::$defaultClientOptions, $options)
104 33
        ));
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 function getPrimarySmptEmailAddress()
117
    {
118 1
        if ($this->getPrimarySmtpMailbox() == null) {
119 1
            return null;
120
        }
121
122 1
        return $this->getPrimarySmtpMailbox()->getEmailAddress();
123
    }
124
125 1
    public function setPrimarySmtpEmailAddress($emailAddress)
126
    {
127 1
        $this->getClient()->setPrimarySmtpEmailAddress($emailAddress);
128
129 1
        return $this;
130
    }
131
132
    /**
133
     * Create items through the API client
134
     *
135
     * @param $items
136
     * @param array $options
137
     * @return Type
138
     */
139 16
    public function createItems($items, $options = array())
140
    {
141 16
        $items = Utilities\ensureIsArray($items);
142
        $request = array(
143
            'Items' => $items
144 16
        );
145
146 16
        $request = array_replace_recursive($request, $options);
147 16
        $request = Type::buildFromArray($request);
148
149 16
        $response = $this->getClient()->CreateItem($request);
150
151 16
        return $response;
152
    }
153
154 4
    public function updateItems($items, $options = array())
155
    {
156
        $request = array(
157 4
            'ItemChanges' => $items,
158 4
            'MessageDisposition' => 'SaveOnly',
159
            'ConflictResolution' => 'AlwaysOverwrite'
160 4
        );
161
162 4
        $request = array_replace_recursive($request, $options);
163
164 4
        $request = Type::buildFromArray($request);
165
166 4
        $response = $this->getClient()->UpdateItem($request);
167 4
        if ($response instanceof UpdateItemResponseMessageType) {
168 4
            return $response->getItems();
169
        }
170
171
        return Utilities\ensureIsArray($response);
172
    }
173
174 1 View Code Duplication
    public function createCalendars($names, BaseFolderIdType $parentFolder = null, $options = array())
175
    {
176 1
        if ($parentFolder === null) {
177 1
            $parentFolder = $this->getDistinguishedFolderId('calendar');
178 1
        }
179
180 1
        return $this->createFolders($names, $parentFolder, $options, 'IPF.Appointment');
181
    }
182
    
183 View Code Duplication
    public function createContactsFolder($names, BaseFolderIdType $parentFolder = null, $options = array())
184
    {
185
        if ($parentFolder === null) {
186
            $parentFolder = $this->getDistinguishedFolderId('contacts');
187
        }
188
189
        return $this->createFolders($names, $parentFolder, $options, 'IPF.Contact');
190
    }
191
192 4
    public function createFolders($names, BaseFolderIdType $parentFolder, $options = array(), $folderClass = null)
193
    {
194 4
        $names = Utilities\ensureIsArray($names);
195
        $names = array_map(function ($name) use ($folderClass) {
196 4
            return ['DisplayName' => $name, 'FolderClass' => $folderClass];
197 4
        }, $names);
198
199
        $request = [
200 4
            'Folders' => ['Folder' => $names]
201 4
        ];
202
203 4
        if ($parentFolder !== null) {
204 4
            $request['ParentFolderId'] = $parentFolder->toArray(true);
205 4
        }
206
207 4
        $request = array_merge_recursive($request, $options);
208
209 4
        $this->client->CreateFolder($request);
210 4
        return true;
211
    }
212
213
    /**
214
     * @deprecated Please use API::deleteFolders() instead
215
     *
216
     * @param BaseFolderIdType $folderId
217
     * @param array $options
218
     * @return Type
219
     */
220 3
    public function deleteFolder(BaseFolderIdType $folderId, $options = array())
221
    {
222 3
        return $this->deleteFolders($folderId, $options);
223
    }
224
225 4
    public function deleteFolders($folders, $options = array())
226
    {
227 4
        $folderIds = Utilities\getFolderIds($folders);
228
229
        $request = [
230 4
            'DeleteType' => 'HardDelete',
231
            'FolderIds' => $folderIds
232 4
        ];
233
234 4
        $request = array_merge_recursive($request, $options);
235 4
        return $this->client->DeleteFolder($request);
236
    }
237
238
    public function moveItem(Type\ItemIdType $itemId, BaseFolderIdType $folderId, $options = array())
239
    {
240
        $request = array(
241
            'ToFolderId' => $folderId->toArray(true),
242
            'ItemIds' => array('ItemId' => $itemId->toArray())
243
        );
244
245
        $request = array_merge_recursive($request, $options);
246
247
        return $this->client->MoveItem($request);
248
    }
249
250
    /**
251
     * @param $items Type\ItemIdType|Type\ItemIdType[]
252
     * @param array $options
253
     * @return bool
254
     */
255 16
    public function deleteItems($items, $options = array())
256
    {
257 16
        $items = Utilities\ensureIsArray($items, true);
258
259 16
        $items = array_map(function ($item) {
260 16
            $item = Type\ItemIdType::buildFromArray($item);
261
262 16
            return $item->toArray();
263 16
        }, $items);
264
265
        $request = array(
266 16
            'ItemIds' => array('ItemId' => $items),
267
            'DeleteType' => 'MoveToDeletedItems'
268 16
        );
269
270 16
        $request = array_replace_recursive($request, $options);
271 16
        $request = Type::buildFromArray($request);
272 16
        $this->getClient()->DeleteItem($request);
273
274
        //If the delete fails, an Exception will be thrown in processResponse before it gets here
275 16
        return true;
276
    }
277
278
    /**
279
     * @param $identifier
280
     * @param array $options
281
     * @return Type\BaseFolderType
282
     */
283 8
    public function getFolder($identifier, $options = [])
284
    {
285
        $request = array(
286
            'FolderShape' => array(
287 8
                'BaseShape' => array('_' => 'Default')
288 8
            ),
289
            'FolderIds' => $identifier
290 8
        );
291
292 8
        $request = array_replace_recursive($request, $options);
293
294 8
        $request = Type::buildFromArray($request);
295
296 8
        $response = $this->getClient()->GetFolder($request);
297
298 8
        return $response;
299
    }
300
301
    /**
302
     * Get a folder by it's distinguishedId
303
     *
304
     * @param string $distinguishedId
305
     * @param array $options
306
     * @return Type\BaseFolderType
307
     */
308 4
    public function getFolderByDistinguishedId($distinguishedId, $options = [])
309
    {
310 4
        return $this->getFolder(array(
311
            'DistinguishedFolderId' => array(
312 4
                'Id' => $distinguishedId,
313 4
                'Mailbox' => $this->getPrimarySmtpMailbox()
314 4
            )
315 4
        ), $options);
316
    }
317
318
    /**
319
     * @param string|BaseFolderIdType $folderId
320
     * @param array $options
321
     * @return Type\BaseFolderType
322
     * @throws API\Exception
323
     */
324 4
    public function getFolderByFolderId($folderId, $options = [])
325
    {
326 4
        if (is_string($folderId)) {
327
            $folderId = ['FolderId' => ['Id' => $folderId, 'Mailbox' => $this->getPrimarySmtpMailbox()]];
328
        } else {
329 4
            $folderId = $folderId->toArray(true);
330
        }
331
332 4
        return $this->getFolder($folderId, $options);
333
    }
334
335
    /**
336
     * @param string|BaseFolderIdType $parentFolderId
337
     * @param array $options
338
     * @return Type\BaseFolderType[]
339
     */
340 25 View Code Duplication
    public function getChildrenFolders($parentFolderId = 'root', array $options = array())
341
    {
342 25
        if (is_string($parentFolderId)) {
343 17
            $parentFolderId = $this->getDistinguishedFolderId($parentFolderId);
344 17
        }
345
346
        $request = array(
347 25
            'Traversal' => 'Shallow',
348
            'FolderShape' => array(
349
                'BaseShape' => 'AllProperties'
350 25
            ),
351 25
            'ParentFolderIds' => $parentFolderId->toArray(true)
352 25
        );
353
354 25
        $request = array_replace_recursive($request, $options);
355
356 25
        $request = Type::buildFromArray($request);
357
358
        /** @var \garethp\ews\API\Message\FindFolderResponseMessageType $folders */
359 25
        return $this->getClient()->FindFolder($request);
360
    }
361
362
    /**
363
     * @param string $folderName
364
     * @param string|BaseFolderIdType $parentFolderId
365
     * @param array $options
366
     * @return bool|Type\BaseFolderType
367
     */
368 25
    public function getFolderByDisplayName($folderName, $parentFolderId = 'root', $options = array())
369
    {
370 25
        $folders = $this->getChildrenFolders($parentFolderId, $options);
371
372 25
        foreach ($folders as $folder) {
0 ignored issues
show
Bug introduced by
The expression $folders of type object<garethp\ews\API\Type> is not traversable.
Loading history...
373 25
            if ($folder->getDisplayName() === $folderName) {
374 24
                return $folder;
375
            }
376 17
        }
377
378 4
        return false;
379
    }
380
381
    /**
382
     * @param $itemId array|Type\ItemIdType
383
     * @param array $options
384
     * @return Type
385
     */
386 5 View Code Duplication
    public function getItem($itemId, $options = array())
387
    {
388 5
        if ($itemId instanceof Type\ItemIdType) {
389 4
            $itemId = $itemId->toArray();
390 4
        }
391
392
        $request = array(
393 5
            'ItemShape' => array('BaseShape' => 'AllProperties'),
394 5
            'ItemIds' => array('ItemId' => $itemId)
395 5
        );
396
397 5
        $request = array_replace_recursive($request, $options);
398
399 5
        return $this->getClient()->GetItem($request);
400
    }
401
402
    /**
403
     * Get a list of sync changes on a folder
404
     *
405
     * @param BaseFolderIdType $folderId
406
     * @param null $syncState
407
     * @param array $options
408
     * @return SyncFolderItemsResponseMessageType
409
     */
410 2
    public function listItemChanges($folderId, $syncState = null, array $options = array())
411
    {
412
        $request = array(
413 2
            'ItemShape' => array('BaseShape' => 'AllProperties'),
414 2
            'SyncFolderId' => $folderId->toArray(true),
415 2
            'SyncScope' => 'NormalItems',
416
            'MaxChangesReturned' => '100'
417 2
        );
418
419 2
        if ($syncState != null) {
420 1
            $request['SyncState'] = $syncState;
421 1
            $request['ItemShape']['BaseShape'] = 'AllProperties';
422 1
        }
423
424 2
        $request = array_replace_recursive($request, $options);
425
426 2
        $request = Type::buildFromArray($request);
427 2
        $response = $this->getClient()->SyncFolderItems($request);
428
429 2
        return $response;
430
    }
431
432
    public function getServerTimezones($timezoneIDs = array(), $fullTimezoneData = false)
433
    {
434
        $request = GetServerTimeZonesType::buildFromArray(array(
435
            'returnFullTimeZoneData' => $fullTimezoneData
436
        ));
437
438
        if (!empty($timezoneIDs)) {
439
            $request->setIds($timezoneIDs);
440
        }
441
442
        $timezones = $this->getClient()->GetServerTimeZones($request);
443
        $timezones = $timezones->TimeZoneDefinition;
0 ignored issues
show
Documentation introduced by
The property TimeZoneDefinition does not exist on object<garethp\ews\API\Type>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
444
445
        return Utilities\ensureIsArray($timezones);
446
    }
447
448
    /**
449
     * @param Type\ItemIdType $itemId
450
     * @param $fromType
451
     * @param $destinationType
452
     * @param $mailbox
453
     *
454
     * @return Type\ItemIdType
455
     */
456
    public function convertIdFormat(Type\ItemIdType $itemId, $fromType, $destinationType, $mailbox)
457
    {
458
        $result = $this->getClient()->ConvertId(array(
459
            'DestinationFormat' => $destinationType,
460
            'SourceIds' => array(
461
                'AlternateId' => array(
462
                    'Format' => $fromType,
463
                    'Id' => $itemId->getId(),
464
                    'Mailbox' => $mailbox
465
                )
466
            )
467
        ));
468
469
        $itemId->setId($result->getId());
470
471
        return $itemId;
472
    }
473
474
    /**
475
     * @param Type\FindItemParentType|Type\FindFolderParentType $result
476
     *
477
     * @return Type\FindItemParentType|Type\FindFolderParentType
478
     */
479 2
    public function getNextPage($result)
480
    {
481 2
        if ($result->isIncludesLastItemInRange()) {
482
            return $result;
483
        }
484
485 2
        $currentPage = $result->getCurrentPage();
486 2
        $currentPage->setOffset($result->getIndexedPagingOffset());
487
488 2
        $lastRequest = $result->getLastRequest();
489 2
        $lastRequest->setIndexedPage($currentPage);
490
491 2
        if ($result instanceof Type\FindFolderParentType) {
492 1
            return $this->getClient()->FindFolder($lastRequest);
493
        }
494
495 1
        return $this->getClient()->FindItem($lastRequest);
496
    }
497
498
    /**
499
     * @param BaseFolderIdType $folderId
500
     * @param string $deleteType
501
     * @param bool $deleteSubFolders
502
     * @param array $options
503
     * @return EmptyFolderResponseType
504
     */
505
    public function emptyFolder(
506
        BaseFolderIdType $folderId,
507
        $deleteType = 'SoftDelete',
508
        $deleteSubFolders = false,
509
        array $options = []
510
    ) {
511
        $request = [
512
            'DeleteType' => $deleteType,
513
            'DeleteSubFolders' => $deleteSubFolders,
514
            'FolderIds' => $folderId->toArray(true)
515
        ];
516
517
        $request = array_merge_recursive($request, $options);
518
519
        return $this->getClient()->EmptyFolder($request);
520
    }
521
522 23
    protected function getDistinguishedFolderId($id = null, $changeKey = null)
523
    {
524 23
        return new Type\DistinguishedFolderIdType(
525 23
            $id,
526 23
            $changeKey,
527 23
            $this->getPrimarySmtpMailbox()
528 23
        );
529
    }
530
}
531