Completed
Push — master ( 62e8ac...4b82f4 )
by Gareth
03:48
created

API::getChildrenFolders()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 12

Duplication

Lines 23
Ratio 100 %

Code Coverage

Tests 12
CRAP Score 2

Importance

Changes 3
Bugs 2 Features 2
Metric Value
c 3
b 2
f 2
dl 23
loc 23
ccs 12
cts 12
cp 1
rs 9.0856
cc 2
eloc 12
nc 2
nop 2
crap 2
1
<?php
2
3
namespace garethp\ews;
4
5
use garethp\ews\API\ExchangeWebServices;
6
use garethp\ews\API\Message\GetServerTimeZonesType;
7
use garethp\ews\API\Message\SyncFolderItemsResponseMessageType;
8
use garethp\ews\API\Message\UpdateItemResponseMessageType;
9
use garethp\ews\API\Type;
10
11
/**
12
 * A base class for APIs
13
 *
14
 * Class BaseAPI
15
 * @package garethp\ews
16
 */
17
class API
18
{
19
    protected static $defaultClientOptions = array(
20
        'version' => ExchangeWebServices::VERSION_2010
21
    );
22
23 34
    public function __construct(ExchangeWebServices $client = null)
24
    {
25 34
        if ($client) {
26 34
            $this->setClient($client);
27 34
        }
28 34
    }
29
30
    /**
31
     * @return Type\EmailAddressType
32
     */
33 26
    public function getPrimarySmtpMailbox()
34
    {
35 26
        return $this->getClient()->getPrimarySmtpMailbox();
36
    }
37
38
    /**
39
     * Storing the API client
40
     * @var ExchangeWebServices
41
     */
42
    private $client;
43
44
    /**
45
     * Get a calendar item
46
     *
47
     * @param string $name
48
     * @return CalendarAPI
49
     */
50 6
    public function getCalendar($name = null)
51
    {
52 6
        $calendar = new CalendarAPI();
53 6
        $calendar->setClient($this->getClient());
54 6
        $calendar->pickCalendar($name);
55
56 6
        return $calendar;
57
    }
58
59
    /**
60
     * @param string $folderName
61
     * @return MailAPI
62
     */
63 6
    public function getMailbox($folderName = null)
64
    {
65 6
        $mailApi = new MailAPI();
66 6
        $mailApi->setClient($this->getClient());
67 6
        $mailApi->pickMailFolder($folderName);
68
69 6
        return $mailApi;
70
    }
71
72
    /**
73
     * Set the API client
74
     *
75
     * @param ExchangeWebServices $client
76
     * @return $this
77
     */
78 34
    public function setClient($client)
79
    {
80 34
        $this->client = $client;
81
82 34
        return $this;
83
    }
84
85
    /**
86
     * Get the API client
87
     *
88
     * @return ExchangeWebServices
89
     */
90 33
    public function getClient()
91 2
    {
92 33
        return $this->client;
93
    }
94
95 33
    public static function withUsernameAndPassword($server, $username, $password, $options = [])
96
    {
97 33
        return new static(ExchangeWebServices::fromUsernameAndPassword(
98 33
            $server,
99 33
            $username,
100 33
            $password,
101 33
            array_replace_recursive(self::$defaultClientOptions, $options)
102 33
        ));
103
    }
104
105 1
    public static function withCallbackToken($server, $token, $options = [])
106
    {
107 1
        return new static(ExchangeWebServices::fromCallbackToken(
108 1
            $server,
109 1
            $token,
110 1
            array_replace_recursive(self::$defaultClientOptions, $options)
111 1
        ));
112
    }
113
114 1
    public function getPrimarySmptEmailAddress()
115
    {
116 1
        if ($this->getPrimarySmtpMailbox() == null) {
117 1
            return null;
118
        }
119
120 1
        return $this->getPrimarySmtpMailbox()->getEmailAddress();
121
    }
122
123 1
    public function setPrimarySmtpEmailAddress($emailAddress)
124
    {
125 1
        $this->getClient()->setPrimarySmtpEmailAddress($emailAddress);
126
127 1
        return $this;
128
    }
129
130
    /**
131
     * Create items through the API client
132
     *
133
     * @param $items
134
     * @param array $options
135
     * @return Type
136
     */
137 16
    public function createItems($items, $options = array())
138
    {
139 16
        if (!is_array($items)) {
140
            $items = array($items);
141
        }
142
143
        $request = array(
144
            'Items' => $items
145 16
        );
146
147 16
        $request = array_replace_recursive($request, $options);
148 16
        $request = Type::buildFromArray($request);
149
150 16
        $response = $this->getClient()->CreateItem($request);
151
152 16
        return $response;
153
    }
154
155 4
    public function updateItems($items, $options = array())
156
    {
157
        $request = array(
158 4
            'ItemChanges' => $items,
159 4
            'MessageDisposition' => 'SaveOnly',
160
            'ConflictResolution' => 'AlwaysOverwrite'
161 4
        );
162
163 4
        $request = array_replace_recursive($request, $options);
164
165 4
        $request = Type::buildFromArray($request);
166
167 4
        $response = $this->getClient()->UpdateItem($request);
168 4
        if ($response instanceof UpdateItemResponseMessageType) {
0 ignored issues
show
Bug introduced by
The class garethp\ews\API\Message\...ItemResponseMessageType 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...
169 4
            return $response->getItems();
170
        }
171
172
        if (!is_array($response)) {
173
            $response = array($response);
174
        }
175
176
        return $response;
177
    }
178
179 1
    public function createCalendars($names, Type\FolderIdType $parentFolder = null, $options = array())
180
    {
181 1
        if ($parentFolder == null) {
182 1
            $parentFolder = $this->getFolderByDistinguishedId('calendar')->getFolderId();
0 ignored issues
show
Documentation Bug introduced by
The method getFolderId does not exist on object<garethp\ews\API\Type>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
183 1
        }
184
185 1
        if (!is_array($names)) {
186 1
            $names = array($names);
187 1
        }
188
189
        $names = array_map(function ($name) {
190
            return array(
191 1
                'DisplayName' => $name,
192
                'FolderClass' => 'IPF.Appointment'
193 1
            );
194 1
        }, $names);
195
196
        $request = [
197 1
            'Folders' => ['Folder' => $names],
198 1
            'ParentFolderId' => ['FolderId' => $parentFolder->toArray()]
199 1
        ];
200
201 1
        $request = array_merge_recursive($request, $options);
202
203 1
        $this->client->CreateFolder($request);
204 1
        return true;
205
    }
206
207 3
    public function createFolders($names, Type\FolderIdType $parentFolder, $options = array())
208
    {
209 3
        if (!is_array($names)) {
210 2
            $names = array($names);
211 2
        }
212
213
        $names = array_map(function ($name) {
214 3
            return ['DisplayName' => $name];
215 3
        }, $names);
216
217
        $request = [
218 3
            'Folders' => ['Folder' => $names]
219 3
        ];
220
221 3
        if (!empty($parentFolder)) {
222 3
            $request['ParentFolderId'] = array('FolderId' => $parentFolder->toArray());
223 3
        }
224
225 3
        $request = array_merge_recursive($request, $options);
226
227 3
        $this->client->CreateFolder($request);
228
229 3
        return true;
230
    }
231
232
    /**
233
     * @deprecated Please use API::deleteFolders() instead
234
     *
235
     * @param Type\FolderIdType $folderId
236
     * @param array $options
237
     * @return Type
238
     */
239
    public function deleteFolder(Type\FolderIdType $folderId, $options = array())
240
    {
241
        return $this->deleteFolders($folderId, $options);
242
    }
243
244 4
    public function deleteFolders($folders, $options = array())
245
    {
246 4
        if (!is_array($folders)) {
247 3
            $folders = array($folders);
248 3
        }
249
250
        $folderIds = array_map(function ($folderId) {
251 4
            return $folderId->toArray();
252 4
        }, $folders);
253
254
        $request = [
255 4
            'DeleteType' => 'HardDelete',
256
            'FolderIds' => array(
257
                'FolderId' => $folderIds
258 4
            )
259 4
        ];
260
261 4
        $request = array_merge_recursive($request, $options);
262 4
        return $this->client->DeleteFolder($request);
263
    }
264
265
    public function moveItem(Type\ItemIdType $itemId, Type\FolderIdType $folderId, $options = array())
266
    {
267
        $request = array(
268
            'ToFolderId' => array('FolderId' => $folderId->toArray()),
269
            'ItemIds' => array('ItemId' => $itemId->toArray())
270
        );
271
272
        $request = array_merge_recursive($request, $options);
273
274
        return $this->client->MoveItem($request);
275
    }
276
277
    /**
278
     * @param        $items Type\ItemIdType|Type\ItemIdType[]
279
     * @param array  $options
280
     * @return bool
281
     */
282 16
    public function deleteItems($items, $options = array())
283
    {
284 16
        if (!is_array($items) || Type::arrayIsAssoc($items)) {
285 15
            $items = array($items);
286 15
        }
287
288 16
        $items = array_map(function ($item) {
289 16
            $item = Type\ItemIdType::buildFromArray($item);
290
291 16
            return $item->toArray();
292 16
        }, $items);
293
294
        $request = array(
295 16
            'ItemIds' => array('ItemId' => $items),
296
            'DeleteType' => 'MoveToDeletedItems'
297 16
        );
298
299 16
        $request = array_replace_recursive($request, $options);
300 16
        $request = Type::buildFromArray($request);
301 16
        $this->getClient()->DeleteItem($request);
302
303
        //If the delete fails, an Exception will be thrown in processResponse before it gets here
304 16
        return true;
305
    }
306
307
    /**
308
     * @param $identifier
309
     * @return Type\BaseFolderType
310
     */
311 25
    public function getFolder($identifier)
312
    {
313
        $request = array(
314
            'FolderShape' => array(
315 25
                'BaseShape' => array('_' => 'Default')
316 25
            ),
317
            'FolderIds' => $identifier
318 25
        );
319 25
        $request = Type::buildFromArray($request);
320
321 25
        $response = $this->getClient()->GetFolder($request);
322
323 25
        return $response;
324
    }
325
326
    /**
327
     * Get a folder by it's distinguishedId
328
     *
329
     * @param string $distinguishedId
330
     * @return Type\BaseFolderType
331
     */
332 25
    public function getFolderByDistinguishedId($distinguishedId)
333
    {
334 25
        return $this->getFolder(array(
335
            'DistinguishedFolderId' => array(
336 25
                'Id' => $distinguishedId,
337 25
                'Mailbox' => $this->getPrimarySmtpMailbox()
338 25
            )
339 25
        ));
340
    }
341
342
    /**
343
     * @param $folderId
344
     * @return Type\BaseFolderType
345
     */
346 4
    public function getFolderByFolderId($folderId)
347
    {
348 4
        return $this->getFolder(array(
349 4
            'FolderId' => array('Id' => $folderId, 'Mailbox' => $this->getPrimarySmtpMailbox())
350 4
        ));
351
    }
352
353
    /**
354
     * @param string|Type\FolderIdType $parentFolderId
355
     * @param array $options
356
     * @return Type\BaseFolderType[]
357
     */
358 24 View Code Duplication
    public function getChildrenFolders($parentFolderId = 'root', $options = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
359
    {
360 24
        if (is_string($parentFolderId)) {
361 16
            $parentFolderId = $this->getFolderByDistinguishedId($parentFolderId)->getFolderId();
0 ignored issues
show
Documentation Bug introduced by
The method getFolderId does not exist on object<garethp\ews\API\Type>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
362 16
        }
363
364
        $request = array(
365 24
            'Traversal' => 'Shallow',
366
            'FolderShape' => array(
367
                'BaseShape' => 'AllProperties'
368 24
            ),
369
            'ParentFolderIds' => array(
370 24
                'FolderId' => $parentFolderId->toArray()
371 24
            )
372 24
        );
373
374 24
        $request = array_replace_recursive($request, $options);
375
376 24
        $request = Type::buildFromArray($request);
377
378
        /** @var \garethp\ews\API\Message\FindFolderResponseMessageType $folders */
379 24
        return $this->getClient()->FindFolder($request);
380
    }
381
382
    /**
383
     * @param string $folderName
384
     * @param string|Type\FolderIdType $parentFolderId
385
     * @param array $options
386
     * @return bool|Type\BaseFolderType
387
     */
388 24
    public function getFolderByDisplayName($folderName, $parentFolderId = 'root', $options = array())
389
    {
390 24
        $folders = $this->getChildrenFolders($parentFolderId, $options);
391
392 24
        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...
393 24
            if ($folder->getDisplayName() == $folderName) {
394 23
                return $folder;
395
            }
396 17
        }
397
398 4
        return false;
399
    }
400
401
    /**
402
     * @param $itemId array|Type\ItemIdType
403
     * @param array $options
404
     * @return Type
405
     */
406 5 View Code Duplication
    public function getItem($itemId, $options = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
407
    {
408 5
        if ($itemId instanceof Type\ItemIdType) {
0 ignored issues
show
Bug introduced by
The class garethp\ews\API\Type\ItemIdType 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...
409 4
            $itemId = $itemId->toArray();
410 4
        }
411
412
        $request = array(
413 5
            'ItemShape' => array('BaseShape' => 'AllProperties'),
414 5
            'ItemIds' => array('ItemId' => $itemId)
415 5
        );
416
417 5
        $request = array_replace_recursive($request, $options);
418
419 5
        return $this->getClient()->GetItem($request);
420
    }
421
422
    /**
423
     * Get a list of sync changes on a folder
424
     *
425
     * @param Type\FolderIdType $folderId
426
     * @param null $syncState
427
     * @param array $options
428
     * @return SyncFolderItemsResponseMessageType
429
     */
430 2
    public function listItemChanges($folderId, $syncState = null, $options = array())
431
    {
432
        $request = array(
433 2
            'ItemShape' => array('BaseShape' => 'IdOnly'),
434 2
            'SyncFolderId' => array('FolderId' => $folderId->toXmlObject()),
435 2
            'SyncScope' => 'NormalItems',
436
            'MaxChangesReturned' => '100'
437 2
        );
438
439 2
        if ($syncState != null) {
440 1
            $request['SyncState'] = $syncState;
441 1
            $request['ItemShape']['BaseShape'] = 'AllProperties';
442 1
        }
443
444 2
        $request = array_replace_recursive($request, $options);
445
446 2
        $request = Type::buildFromArray($request);
447 2
        $response = $this->getClient()->SyncFolderItems($request);
448
449 2
        return $response;
450
    }
451
452
    public function getServerTimezones($timezoneIDs = array(), $fullTimezoneData = false)
453
    {
454
        $request = GetServerTimeZonesType::buildFromArray(array(
455
            'returnFullTimeZoneData' => $fullTimezoneData
456
        ));
457
458
        if (!empty($timezoneIDs)) {
459
            $request->setIds($timezoneIDs);
460
        }
461
462
        $timezones = $this->getClient()->GetServerTimeZones($request);
463
        $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...
464
465
        if (!is_array($timezones)) {
466
            $timezones = array($timezones);
467
        }
468
469
        return $timezones;
470
    }
471
472
    /**
473
     * @param Type\ItemIdType $itemId
474
     * @param $fromType
475
     * @param $destinationType
476
     * @param $mailbox
477
     *
478
     * @return Type\ItemIdType
479
     */
480
    public function convertIdFormat(Type\ItemIdType $itemId, $fromType, $destinationType, $mailbox)
481
    {
482
        $result = $this->getClient()->ConvertId(array(
483
            'DestinationFormat' => $destinationType,
484
            'SourceIds' => array(
485
                'AlternateId' => array(
486
                    'Format' => $fromType,
487
                    'Id' => $itemId->getId(),
488
                    'Mailbox' => $mailbox
489
                )
490
            )
491
        ));
492
493
        $itemId->setId($result->getId());
0 ignored issues
show
Documentation Bug introduced by
The method getId does not exist on object<garethp\ews\API\Type>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
494
495
        return $itemId;
496
    }
497
498
    /**
499
     * @param Type\FindItemParentType|Type\FindFolderParentType $result
500
     *
501
     * @return Type\FindItemParentType|Type\FindFolderParentType
502
     */
503 2
    public function getNextPage($result)
504
    {
505 2
        if ($result->isIncludesLastItemInRange()) {
506
            return $result;
507
        }
508
509 2
        $currentPage = $result->getCurrentPage();
510 2
        $currentPage->setOffset($result->getIndexedPagingOffset());
511
512 2
        $lastRequest = $result->getLastRequest();
513 2
        $lastRequest->setIndexedPage($currentPage);
514
515 2
        if ($result instanceof Type\FindFolderParentType) {
0 ignored issues
show
Bug introduced by
The class garethp\ews\API\Type\FindFolderParentType 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...
516 1
            return $this->getClient()->FindFolder($lastRequest);
517
        }
518
519 1
        return $this->getClient()->FindItem($lastRequest);
520
    }
521
}
522