Completed
Pull Request — master (#66)
by marijn
05:49
created

API::getItem()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 8

Duplication

Lines 15
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 15
loc 15
ccs 0
cts 9
cp 0
rs 9.4285
cc 2
eloc 8
nc 2
nop 2
crap 6
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
    public function __construct(ExchangeWebServices $client = null)
24
    {
25
        if ($client) {
26
            $this->setClient($client);
27
        }
28
    }
29
30
    /**
31
     * @return Type\EmailAddressType
32
     */
33
    public function getPrimarySmtpMailbox()
34
    {
35
        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
    public function getCalendar($name = null)
51
    {
52
        $calendar = new CalendarAPI();
53
        $calendar->setClient($this->getClient());
54
        $calendar->pickCalendar($name);
55
56
        return $calendar;
57
    }
58
59
    /**
60
     * @param string $folderName
61
     * @return MailAPI
62
     */
63
    public function getMailbox($folderName = null)
64
    {
65
        $mailApi = new MailAPI();
66
        $mailApi->setClient($this->getClient());
67
        $mailApi->pickMailFolder($folderName);
68
69
        return $mailApi;
70
    }
71
72
    /**
73
     * Set the API client
74
     *
75
     * @param ExchangeWebServices $client
76
     * @return $this
77
     */
78
    public function setClient($client)
79
    {
80
        $this->client = $client;
81
82
        return $this;
83
    }
84
85
    /**
86
     * Get the API client
87
     *
88
     * @return ExchangeWebServices
89
     */
90
    public function getClient()
91
    {
92
        return $this->client;
93
    }
94
95 32
    public static function withUsernameAndPassword($server, $username, $password, $options = [])
96
    {
97 32
        return new static(ExchangeWebServices::fromUsernameAndPassword(
98 32
            $server,
99 32
            $username,
100 32
            $password,
101 32
            array_replace_recursive(self::$defaultClientOptions, $options)
102 32
        ));
103
    }
104
105
    public static function withCallbackToken($server, $token, $options = [])
106
    {
107
        return new static(ExchangeWebServices::fromCallbackToken(
108
            $server,
109
            $token,
110
            array_replace_recursive(self::$defaultClientOptions, $options)
111
        ));
112
    }
113
114
    public function getPrimarySmptEmailAddress()
115
    {
116
        if ($this->getPrimarySmtpMailbox() == null) {
117
            return null;
118
        }
119
120
        return $this->getPrimarySmtpMailbox()->getEmailAddress();
121
    }
122
123
    public function setPrimarySmtpEmailAddress($emailAddress)
124
    {
125
        $this->getClient()->setPrimarySmtpEmailAddress($emailAddress);
126
127
        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
    public function createItems($items, $options = array())
138
    {
139
        if (!is_array($items)) {
140
            $items = array($items);
141
        }
142
143
        $request = array(
144
            'Items' => $items
145
        );
146
147
        $request = array_replace_recursive($request, $options);
148
        $request = Type::buildFromArray($request);
149
150
        $response = $this->getClient()->CreateItem($request);
151
152
        return $response;
153
    }
154
155
    public function updateItems($items, $options = array())
156
    {
157
        $request = array(
158
            'ItemChanges' => $items,
159
            'MessageDisposition' => 'SaveOnly',
160
            'ConflictResolution' => 'AlwaysOverwrite'
161
        );
162
163
        $request = array_replace_recursive($request, $options);
164
165
        $request = Type::buildFromArray($request);
166
167
        $response = $this->getClient()->UpdateItem($request);
168
        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
            return $response->getItems();
170
        }
171
172
        if (!is_array($response)) {
173
            $response = array($response);
174
        }
175
176
        return $response;
177
    }
178
179
    public function createCalendars($names, Type\FolderIdType $parentFolder = null, $options = array())
180
    {
181
        if ($parentFolder == null) {
182
            $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
        }
184
185
        if (!is_array($names)) {
186
            $names = array($names);
187
        }
188
189
        $names = array_map(function ($name) {
190
            return array(
191
                'DisplayName' => $name,
192
                'FolderClass' => 'IPF.Appointment'
193
            );
194
        }, $names);
195
196
        $request = [
197
            'Folders' => ['Folder' => $names],
198
            'ParentFolderId' => ['FolderId' => $parentFolder->toArray()]
199
        ];
200
201
        $request = array_merge_recursive($request, $options);
202
203
        $this->client->CreateFolder($request);
204
        return true;
205
    }
206
207
    public function createFolders($names, Type\FolderIdType $parentFolder, $options = array())
208
    {
209
        if (!is_array($names)) {
210
            $names = array($names);
211
        }
212
213
        $names = array_map(function ($name) {
214
            return ['DisplayName' => $name];
215
        }, $names);
216
217
        $request = [
218
            'Folders' => ['Folder' => $names]
219
        ];
220
221
        if (!empty($parentFolder)) {
222
            $request['ParentFolderId'] = array('FolderId' => $parentFolder->toArray());
223
        }
224
225
        $request = array_merge_recursive($request, $options);
226
227
        $this->client->CreateFolder($request);
228
229
        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
    public function deleteFolders($folders, $options = array())
245
    {
246
        if (!is_array($folders)) {
247
            $folders = array($folders);
248
        }
249
250
        $folderIds = array_map(function ($folderId) {
251
            return $folderId->toArray();
252
        }, $folders);
253
254
        $request = [
255
            'DeleteType' => 'HardDelete',
256
            'FolderIds' => array(
257
                'FolderId' => $folderIds
258
            )
259
        ];
260
261
        $request = array_merge_recursive($request, $options);
262
        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
    public function deleteItems($items, $options = array())
283
    {
284
        if (!is_array($items) || Type::arrayIsAssoc($items)) {
285
            $items = array($items);
286
        }
287
288
        $items = array_map(function ($item) {
289
            $item = Type\ItemIdType::buildFromArray($item);
290
291
            return $item->toArray();
292
        }, $items);
293
294
        $request = array(
295
            'ItemIds' => array('ItemId' => $items),
296
            'DeleteType' => 'MoveToDeletedItems'
297
        );
298
299
        $request = array_replace_recursive($request, $options);
300
        $request = Type::buildFromArray($request);
301
        $this->getClient()->DeleteItem($request);
302
303
        //If the delete fails, an Exception will be thrown in processResponse before it gets here
304
        return true;
305
    }
306
307
    /**
308
     * @param $identifier
309
     * @return Type\BaseFolderType
310
     */
311
    public function getFolder($identifier)
312
    {
313
        $request = array(
314
            'FolderShape' => array(
315
                'BaseShape' => array('_' => 'Default')
316
            ),
317
            'FolderIds' => $identifier
318
        );
319
        $request = Type::buildFromArray($request);
320
321
        $response = $this->getClient()->GetFolder($request);
322
323
        return $response;
324
    }
325
326
    /**
327
     * Get a folder by it's distinguishedId
328
     *
329
     * @param string $distinguishedId
330
     * @return Type\BaseFolderType
331
     */
332
    public function getFolderByDistinguishedId($distinguishedId)
333
    {
334
        return $this->getFolder(array(
335
            'DistinguishedFolderId' => array(
336
                'Id' => $distinguishedId,
337
                'Mailbox' => $this->getPrimarySmtpMailbox()
338
            )
339
        ));
340
    }
341
342
    /**
343
     * @param $folderId
344
     * @return Type\BaseFolderType
345
     */
346
    public function getFolderByFolderId($folderId)
347
    {
348
        return $this->getFolder(array(
349
            'FolderId' => array('Id' => $folderId, 'Mailbox' => $this->getPrimarySmtpMailbox())
350
        ));
351
    }
352
353
    /**
354
     * @param string|Type\FolderIdType $parentFolderId
355
     * @param array $options
356
     * @return Type\BaseFolderType[]
357
     */
358 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
        if (is_string($parentFolderId)) {
361
            $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
        }
363
364
        $request = array(
365
            'Traversal' => 'Shallow',
366
            'FolderShape' => array(
367
                'BaseShape' => 'AllProperties'
368
            ),
369
            'ParentFolderIds' => array(
370
                'FolderId' => $parentFolderId->toArray()
371
            )
372
        );
373
374
        $request = array_replace_recursive($request, $options);
375
376
        $request = Type::buildFromArray($request);
377
378
        /** @var \garethp\ews\API\Message\FindFolderResponseMessageType $folders */
379
        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
    public function getFolderByDisplayName($folderName, $parentFolderId = 'root', $options = array())
389
    {
390
        $folders = $this->getChildrenFolders($parentFolderId, $options);
391
392
        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
            if ($folder->getDisplayName() == $folderName) {
394
                return $folder;
395
            }
396
        }
397
398
        return false;
399
    }
400
401
    /**
402
     * @param $itemId array|Type\ItemIdType
403
     * @param array $options
404
     * @return Type
405
     */
406 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
        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
            $itemId = $itemId->toArray();
410
        }
411
412
        $request = array(
413
            'ItemShape' => array('BaseShape' => 'AllProperties'),
414
            'ItemIds' => array('ItemId' => $itemId)
415
        );
416
417
        $request = array_replace_recursive($request, $options);
418
419
        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
    public function listItemChanges($folderId, $syncState = null, $options = array())
431
    {
432
        $request = array(
433
            'ItemShape' => array('BaseShape' => 'IdOnly'),
434
            'SyncFolderId' => array('FolderId' => $folderId->toXmlObject()),
435
            'SyncScope' => 'NormalItems',
436
            'MaxChangesReturned' => '100'
437
        );
438
439
        if ($syncState != null) {
440
            $request['SyncState'] = $syncState;
441
            $request['ItemShape']['BaseShape'] = 'AllProperties';
442
        }
443
444
        $request = array_replace_recursive($request, $options);
445
446
        $request = Type::buildFromArray($request);
447
        $response = $this->getClient()->SyncFolderItems($request);
448
449
        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
    public function getNextPage($result)
504
    {
505
        if ($result->isIncludesLastItemInRange()) {
506
            return $result;
507
        }
508
509
        $currentPage = $result->getCurrentPage();
510
        $currentPage->setOffset($result->getIndexedPagingOffset());
511
512
        $lastRequest = $result->getLastRequest();
513
        $lastRequest->setIndexedPage($currentPage);
514
515
        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
            return $this->getClient()->FindFolder($lastRequest);
517
        }
518
519
        return $this->getClient()->FindItem($lastRequest);
520
    }
521
}
522