Completed
Push — master ( 14422e...17eb68 )
by Gareth
02:59
created

API::getFolderByDistinguishedId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
crap 1
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
12
/**
13
 * A base class for APIs
14
 *
15
 * Class BaseAPI
16
 * @package garethp\ews
17
 */
18
class API
19
{
20
    protected static $defaultClientOptions = array(
21
        'version' => ExchangeWebServices::VERSION_2010
22
    );
23
24 34
    public function __construct(ExchangeWebServices $client = null)
25
    {
26 34
        if ($client) {
27 34
            $this->setClient($client);
28 34
        }
29 34
    }
30
31
    /**
32
     * @return Type\EmailAddressType
33
     */
34 26
    public function getPrimarySmtpMailbox()
35
    {
36 26
        return $this->getClient()->getPrimarySmtpMailbox();
37
    }
38
39
    /**
40
     * Storing the API client
41
     * @var ExchangeWebServices
42
     */
43
    private $client;
44
45
    /**
46
     * Get a calendar item
47
     *
48
     * @param string $name
49
     * @return CalendarAPI
50
     */
51 6
    public function getCalendar($name = null)
52
    {
53 6
        $calendar = new CalendarAPI();
54 6
        $calendar->setClient($this->getClient());
55 6
        $calendar->pickCalendar($name);
56
57 6
        return $calendar;
58
    }
59
60
    /**
61
     * @param string $folderName
62
     * @return MailAPI
63
     */
64 6
    public function getMailbox($folderName = null)
65
    {
66 6
        $mailApi = new MailAPI();
67 6
        $mailApi->setClient($this->getClient());
68 6
        $mailApi->pickMailFolder($folderName);
69
70 6
        return $mailApi;
71
    }
72
73
    /**
74
     * Set the API client
75
     *
76
     * @param ExchangeWebServices $client
77
     * @return $this
78
     */
79 34
    public function setClient($client)
80
    {
81 34
        $this->client = $client;
82
83 34
        return $this;
84
    }
85
86
    /**
87
     * Get the API client
88
     *
89
     * @return ExchangeWebServices
90
     */
91 33
    public function getClient()
92
    {
93 33
        return $this->client;
94
    }
95
96 33
    public static function withUsernameAndPassword($server, $username, $password, $options = [])
97
    {
98 33
        return new static(ExchangeWebServices::fromUsernameAndPassword(
99 33
            $server,
100 33
            $username,
101 33
            $password,
102 33
            array_replace_recursive(self::$defaultClientOptions, $options)
103 33
        ));
104
    }
105
106 1
    public static function withCallbackToken($server, $token, $options = [])
107
    {
108 1
        return new static(ExchangeWebServices::fromCallbackToken(
109 1
            $server,
110 1
            $token,
111 1
            array_replace_recursive(self::$defaultClientOptions, $options)
112 1
        ));
113
    }
114
115 1
    public function getPrimarySmptEmailAddress()
116
    {
117 1
        if ($this->getPrimarySmtpMailbox() == null) {
118 1
            return null;
119
        }
120
121 1
        return $this->getPrimarySmtpMailbox()->getEmailAddress();
122
    }
123
124 1
    public function setPrimarySmtpEmailAddress($emailAddress)
125
    {
126 1
        $this->getClient()->setPrimarySmtpEmailAddress($emailAddress);
127
128 1
        return $this;
129
    }
130
131
    /**
132
     * Create items through the API client
133
     *
134
     * @param $items
135
     * @param array $options
136
     * @return Type
137
     */
138 16
    public function createItems($items, $options = array())
139
    {
140 16
        if (!is_array($items)) {
141
            $items = array($items);
142
        }
143
144
        $request = array(
145
            'Items' => $items
146 16
        );
147
148 16
        $request = array_replace_recursive($request, $options);
149 16
        $request = Type::buildFromArray($request);
150
151 16
        $response = $this->getClient()->CreateItem($request);
152
153 16
        return $response;
154
    }
155
156 4
    public function updateItems($items, $options = array())
157
    {
158
        $request = array(
159 4
            'ItemChanges' => $items,
160 4
            'MessageDisposition' => 'SaveOnly',
161
            'ConflictResolution' => 'AlwaysOverwrite'
162 4
        );
163
164 4
        $request = array_replace_recursive($request, $options);
165
166 4
        $request = Type::buildFromArray($request);
167
168 4
        $response = $this->getClient()->UpdateItem($request);
169 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...
170 4
            return $response->getItems();
171
        }
172
173
        if (!is_array($response)) {
174
            $response = array($response);
175
        }
176
177
        return $response;
178
    }
179
180 1
    public function createCalendars($names, Type\FolderIdType $parentFolder = null, $options = array())
181
    {
182 1
        if ($parentFolder == null) {
183 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...
184 1
        }
185
186 1
        if (!is_array($names)) {
187 1
            $names = array($names);
188 1
        }
189
190
        $names = array_map(function ($name) {
191
            return array(
192 1
                'DisplayName' => $name,
193
                'FolderClass' => 'IPF.Appointment'
194 1
            );
195 1
        }, $names);
196
197
        $request = [
198 1
            'Folders' => ['Folder' => $names],
199 1
            'ParentFolderId' => ['FolderId' => $parentFolder->toArray()]
200 1
        ];
201
202 1
        $request = array_merge_recursive($request, $options);
203
204 1
        $this->client->CreateFolder($request);
205 1
        return true;
206
    }
207
208 3
    public function createFolders($names, Type\FolderIdType $parentFolder, $options = array())
209
    {
210 3
        if (!is_array($names)) {
211 2
            $names = array($names);
212 2
        }
213
214
        $names = array_map(function ($name) {
215 3
            return ['DisplayName' => $name];
216 3
        }, $names);
217
218
        $request = [
219 3
            'Folders' => ['Folder' => $names]
220 3
        ];
221
222 3
        if (!empty($parentFolder)) {
223 3
            $request['ParentFolderId'] = array('FolderId' => $parentFolder->toArray());
224 3
        }
225
226 3
        $request = array_merge_recursive($request, $options);
227
228 3
        $this->client->CreateFolder($request);
229
230 3
        return true;
231
    }
232
233
    /**
234
     * @deprecated Please use API::deleteFolders() instead
235
     *
236
     * @param Type\FolderIdType $folderId
237
     * @param array $options
238
     * @return Type
239
     */
240 3
    public function deleteFolder(Type\FolderIdType $folderId, $options = array())
241
    {
242 3
        return $this->deleteFolders($folderId, $options);
243
    }
244
245 4
    public function deleteFolders($folders, $options = array())
246
    {
247 4
        if (!is_array($folders)) {
248 3
            $folders = array($folders);
249 3
        }
250
251
        $folderIds = array_map(function ($folderId) {
252 4
            return $folderId->toArray();
253 4
        }, $folders);
254
255
        $request = [
256 4
            'DeleteType' => 'HardDelete',
257
            'FolderIds' => array(
258
                'FolderId' => $folderIds
259 4
            )
260 4
        ];
261
262 4
        $request = array_merge_recursive($request, $options);
263 4
        return $this->client->DeleteFolder($request);
264
    }
265
266
    public function moveItem(Type\ItemIdType $itemId, Type\FolderIdType $folderId, $options = array())
267
    {
268
        $request = array(
269
            'ToFolderId' => array('FolderId' => $folderId->toArray()),
270
            'ItemIds' => array('ItemId' => $itemId->toArray())
271
        );
272
273
        $request = array_merge_recursive($request, $options);
274
275
        return $this->client->MoveItem($request);
276
    }
277
278
    /**
279
     * @param $items Type\ItemIdType|Type\ItemIdType[]
280
     * @param array $options
281
     * @return bool
282
     */
283 16
    public function deleteItems($items, $options = array())
284
    {
285 16
        if (!is_array($items) || Type::arrayIsAssoc($items)) {
286 15
            $items = array($items);
287 15
        }
288
289 16
        $items = array_map(function ($item) {
290 16
            $item = Type\ItemIdType::buildFromArray($item);
291
292 16
            return $item->toArray();
293 16
        }, $items);
294
295
        $request = array(
296 16
            'ItemIds' => array('ItemId' => $items),
297
            'DeleteType' => 'MoveToDeletedItems'
298 16
        );
299
300 16
        $request = array_replace_recursive($request, $options);
301 16
        $request = Type::buildFromArray($request);
302 16
        $this->getClient()->DeleteItem($request);
303
304
        //If the delete fails, an Exception will be thrown in processResponse before it gets here
305 16
        return true;
306
    }
307
308
    /**
309
     * @param $identifier
310
     * @return Type\BaseFolderType
311
     */
312 25
    public function getFolder($identifier)
313
    {
314
        $request = array(
315
            'FolderShape' => array(
316 25
                'BaseShape' => array('_' => 'Default')
317 25
            ),
318
            'FolderIds' => $identifier
319 25
        );
320 25
        $request = Type::buildFromArray($request);
321
322 25
        $response = $this->getClient()->GetFolder($request);
323
324 25
        return $response;
325
    }
326
327
    /**
328
     * Get a folder by it's distinguishedId
329
     *
330
     * @param string $distinguishedId
331
     * @return Type\BaseFolderType
332
     */
333 25
    public function getFolderByDistinguishedId($distinguishedId)
334
    {
335 25
        return $this->getFolder(array(
336
            'DistinguishedFolderId' => array(
337 25
                'Id' => $distinguishedId,
338 25
                'Mailbox' => $this->getPrimarySmtpMailbox()
339 25
            )
340 25
        ));
341
    }
342
343
    /**
344
     * @param $folderId
345
     * @return Type\BaseFolderType
346
     */
347 4
    public function getFolderByFolderId($folderId)
348
    {
349 4
        return $this->getFolder(array(
350 4
            'FolderId' => array('Id' => $folderId, 'Mailbox' => $this->getPrimarySmtpMailbox())
351 4
        ));
352
    }
353
354
    /**
355
     * @param string|Type\FolderIdType $parentFolderId
356
     * @param array $options
357
     * @return Type\BaseFolderType[]
358
     */
359 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...
360
    {
361 24
        if (is_string($parentFolderId)) {
362 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...
363 16
        }
364
365
        $request = array(
366 24
            'Traversal' => 'Shallow',
367
            'FolderShape' => array(
368
                'BaseShape' => 'AllProperties'
369 24
            ),
370
            'ParentFolderIds' => array(
371 24
                'FolderId' => $parentFolderId->toArray()
372 24
            )
373 24
        );
374
375 24
        $request = array_replace_recursive($request, $options);
376
377 24
        $request = Type::buildFromArray($request);
378
379
        /** @var \garethp\ews\API\Message\FindFolderResponseMessageType $folders */
380 24
        return $this->getClient()->FindFolder($request);
381
    }
382
383
    /**
384
     * @param string $folderName
385
     * @param string|Type\FolderIdType $parentFolderId
386
     * @param array $options
387
     * @return bool|Type\BaseFolderType
388
     */
389 24
    public function getFolderByDisplayName($folderName, $parentFolderId = 'root', $options = array())
390
    {
391 24
        $folders = $this->getChildrenFolders($parentFolderId, $options);
392
393 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...
394 24
            if ($folder->getDisplayName() == $folderName) {
395 23
                return $folder;
396
            }
397 17
        }
398
399 4
        return false;
400
    }
401
402
    /**
403
     * @param $itemId array|Type\ItemIdType
404
     * @param array $options
405
     * @return Type
406
     */
407 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...
408
    {
409 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...
410 4
            $itemId = $itemId->toArray();
411 4
        }
412
413
        $request = array(
414 5
            'ItemShape' => array('BaseShape' => 'AllProperties'),
415 5
            'ItemIds' => array('ItemId' => $itemId)
416 5
        );
417
418 5
        $request = array_replace_recursive($request, $options);
419
420 5
        return $this->getClient()->GetItem($request);
421
    }
422
423
    /**
424
     * Get a list of sync changes on a folder
425
     *
426
     * @param Type\FolderIdType $folderId
427
     * @param null $syncState
428
     * @param array $options
429
     * @return SyncFolderItemsResponseMessageType
430
     */
431 2
    public function listItemChanges($folderId, $syncState = null, $options = array())
432
    {
433
        $request = array(
434 2
            'ItemShape' => array('BaseShape' => 'AllProperties'),
435 2
            'SyncFolderId' => array('FolderId' => $folderId->toXmlObject()),
436 2
            'SyncScope' => 'NormalItems',
437
            'MaxChangesReturned' => '100'
438 2
        );
439
440 2
        if ($syncState != null) {
441 1
            $request['SyncState'] = $syncState;
442 1
            $request['ItemShape']['BaseShape'] = 'AllProperties';
443 1
        }
444
445 2
        $request = array_replace_recursive($request, $options);
446
447 2
        $request = Type::buildFromArray($request);
448 2
        $response = $this->getClient()->SyncFolderItems($request);
449
450 2
        return $response;
451
    }
452
453
    public function getServerTimezones($timezoneIDs = array(), $fullTimezoneData = false)
454
    {
455
        $request = GetServerTimeZonesType::buildFromArray(array(
456
            'returnFullTimeZoneData' => $fullTimezoneData
457
        ));
458
459
        if (!empty($timezoneIDs)) {
460
            $request->setIds($timezoneIDs);
461
        }
462
463
        $timezones = $this->getClient()->GetServerTimeZones($request);
464
        $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...
465
466
        if (!is_array($timezones)) {
467
            $timezones = array($timezones);
468
        }
469
470
        return $timezones;
471
    }
472
473
    /**
474
     * @param Type\ItemIdType $itemId
475
     * @param $fromType
476
     * @param $destinationType
477
     * @param $mailbox
478
     *
479
     * @return Type\ItemIdType
480
     */
481
    public function convertIdFormat(Type\ItemIdType $itemId, $fromType, $destinationType, $mailbox)
482
    {
483
        $result = $this->getClient()->ConvertId(array(
484
            'DestinationFormat' => $destinationType,
485
            'SourceIds' => array(
486
                'AlternateId' => array(
487
                    'Format' => $fromType,
488
                    'Id' => $itemId->getId(),
489
                    'Mailbox' => $mailbox
490
                )
491
            )
492
        ));
493
494
        $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...
495
496
        return $itemId;
497
    }
498
499
    /**
500
     * @param Type\FindItemParentType|Type\FindFolderParentType $result
501
     *
502
     * @return Type\FindItemParentType|Type\FindFolderParentType
503
     */
504 2
    public function getNextPage($result)
505
    {
506 2
        if ($result->isIncludesLastItemInRange()) {
507
            return $result;
508
        }
509
510 2
        $currentPage = $result->getCurrentPage();
511 2
        $currentPage->setOffset($result->getIndexedPagingOffset());
512
513 2
        $lastRequest = $result->getLastRequest();
514 2
        $lastRequest->setIndexedPage($currentPage);
515
516 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...
517 1
            return $this->getClient()->FindFolder($lastRequest);
518
        }
519
520 1
        return $this->getClient()->FindItem($lastRequest);
521
    }
522
523
    /**
524
     * @param Type\FolderIdType $folderId
525
     * @param string $deleteType
526
     * @param bool $deleteSubFolders
527
     * @param array $options
528
     * @return EmptyFolderResponseType
529
     */
530
    public function emptyFolder(
531
        Type\FolderIdType $folderId,
532
        $deleteType = 'SoftDelete',
533
        $deleteSubFolders = false,
534
        array $options = []
535
    ) {
536
        $request = [
537
            'DeleteType' => $deleteType,
538
            'DeleteSubFolders' => $deleteSubFolders,
539
            'FolderIds' => ['FolderId' => $folderId->toArray()]
540
        ];
541
542
        $request = array_merge_recursive($request, $options);
543
544
        return $this->getClient()->EmptyFolder($request);
545
    }
546
}
547