Completed
Push — master ( db1d86...8cfad3 )
by Gareth
03:04
created

API::withCallbackToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 5
nc 1
nop 3
crap 1
1
<?php
2
3
namespace jamesiarmes\PEWS;
4
5
use jamesiarmes\PEWS\API\Enumeration\DictionaryURIType;
6
use jamesiarmes\PEWS\API\Enumeration\UnindexedFieldURIType;
7
use jamesiarmes\PEWS\API\ExchangeWebServices;
8
use jamesiarmes\PEWS\API\Message\GetServerTimeZonesType;
9
use jamesiarmes\PEWS\API\Message\SyncFolderItemsResponseMessageType;
10
use jamesiarmes\PEWS\API\Type;
11
use jamesiarmes\PEWS\Calendar\CalendarAPI;
12
use jamesiarmes\PEWS\Mail\MailAPI;
13
14
/**
15
 * A base class for APIs
16
 *
17
 * Class BaseAPI
18
 * @package jamesiarmes\PEWS
19
 */
20
class API
21
{
22
    protected static $defaultClientOptions = array(
23 23
        'version' => ExchangeWebServices::VERSION_2010
24
    );
25 23
26 10
    public function __construct(ExchangeWebServices $client = null)
27 10
    {
28 23
        if ($client) {
29
            $this->setClient($client);
30
        }
31
    }
32
33 15
    /**
34
     * @return Type\EmailAddressType
35 15
     */
36
    public function getPrimarySmtpMailbox()
37
    {
38
        return $this->getClient()->getPrimarySmtpMailbox();
39
    }
40
41
    private $unIndexedFieldUris = array();
42
    private $dictionaryFieldUris = array();
43
44
    /**
45
     * Storing the API client
46 4
     * @var ExchangeWebServices
47
     */
48
    private $client;
49 4
50 4
    /**
51 4
     * @param $className
52
     * @return array
53
     */
54 4
    public function getFieldUrisFromClass($className)
55 4
    {
56 4
        //So, since we have to pass in URI's of everything we update, we need to fetch them
57 4
        $reflection = new \ReflectionClass($className);
58 4
        $constants = $reflection->getConstants();
59
        $constantsFound = array();
60 4
61 4
        //Loop through all URI's to list them in an array
62
        foreach ($constants as $constant) {
63 4
            $exploded = explode(":", $constant);
64 4
            if (count($exploded) == 1) {
65 4
                $exploded = ['item', $exploded[0]];
66 4
            }
67 4
68
            $name = strtolower($exploded[1]);
69 4
            $category = strtolower($exploded[0]);
70 4
71
            if (!isset($constantsFound[$name])) {
72 4
                $constantsFound[$name] = array();
73
            }
74 4
            $constantsFound[$name][$category] = $constant;
75 4
        }
76
77 4
        return $constantsFound;
78 4
    }
79 4
80
    public function setupFieldUris()
81 4
    {
82 1
        $this->unIndexedFieldUris = $this
83
            ->getFieldUrisFromClass(UnindexedFieldURIType::class);
84
85 4
        $this->dictionaryFieldUris = $this
86 1
            ->getFieldUrisFromClass(DictionaryURIType::class);
87 1
    }
88
89 4 View Code Duplication
    public function getFieldUriByName($fieldName, $preference = 'item')
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...
90
    {
91
        $fieldName = strtolower($fieldName);
92
        $preference = strtolower($preference);
93 4
94
        if (empty($this->unIndexedFieldUris)) {
95
            $this->setupFieldUris();
96
        }
97
98
        if (!isset($this->unIndexedFieldUris[$fieldName])) {
99
            return false;
100
        }
101
102 6
        if (!isset($this->unIndexedFieldUris[$fieldName][$preference])) {
103
            $preference = 'item';
104 6
        }
105 6
106 6
        if (!isset($this->unIndexedFieldUris[$fieldName][$preference])) {
107
            throw new \Exception("Could not find uri $preference:$fieldName");
108 6
        }
109
110
        return $this->unIndexedFieldUris[$fieldName][$preference];
111
    }
112
113 View Code Duplication
    public function getIndexedFieldUriByName($fieldName, $preference = 'item')
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...
114
    {
115 8
        $fieldName = strtolower($fieldName);
116
        $preference = strtolower($preference);
117 8
118 6
        if (empty($this->dictionaryFieldUris)) {
119 6
            $this->setupFieldUris();
120
        }
121 6
122
        if (!isset($this->dictionaryFieldUris[$fieldName])) {
123
            return false;
124
        }
125
126
        if (!isset($this->dictionaryFieldUris[$fieldName][$preference])) {
127
            $preference = 'item';
128
        }
129
130 23
        if (!isset($this->dictionaryFieldUris[$fieldName][$preference])) {
131
            throw new \Exception("Could not find uri $preference:$fieldName");
132 23
        }
133 23
134
        return $this->dictionaryFieldUris[$fieldName][$preference];
135
    }
136
137
    /**
138
     * Get a calendar item
139
     *
140
     * @param string $name
141 22
     * @return CalendarAPI
142
     */
143 22
    public function getCalendar($name = null)
144
    {
145
        $calendar = new CalendarAPI();
146
        $calendar->setClient($this->getClient());
147
        $calendar->pickCalendar($name);
148
149
        return $calendar;
150
    }
151
152
    /**
153
     * @param string $folderName
154
     * @return MailAPI
155
     */
156
    public function getMailbox($folderName = null)
157
    {
158
        $mailApi = new MailAPI();
159
        $mailApi->setClient($this->getClient());
160
        $mailApi->pickMailFolder($folderName);
161
162
        return $mailApi;
163
    }
164
165
    /**
166
     * Set the API client
167
     *
168
     * @param ExchangeWebServices $client
169
     * @return $this
170 9
     */
171
    public function setClient($client)
172 9
    {
173 9
        $this->client = $client;
174 9
        return $this;
175 9
    }
176 9
177 9
    /**
178
     * Get the API client
179
     *
180 1
     * @return ExchangeWebServices
181
     */
182 1
    public function getClient()
183 1
    {
184 1
        return $this->client;
185 1
    }
186 1
187
    /**
188
     * Instantiate and set a client (ExchangeWebServices) based on the parameters given
189
     *
190
     * @deprecated Since 0.6.3
191
     * @param $server
192
     * @param $username
193
     * @param $password
194
     * @param array $options
195
     * @return $this
196
     */
197
    public function buildClient(
198
        $server,
199
        $username,
200
        $password,
201
        $options = [ ]
202
    ) {
203
        $this->setClient(ExchangeWebServices::fromUsernameAndPassword(
204
            $server,
205
            $username,
206
            $password,
207
            array_replace_recursive(self::$defaultClientOptions, $options)
208
        ));
209
    }
210
211
    public static function withUsernameAndPassword($server, $username, $password, $options = [ ])
212 9
    {
213
        return new static(ExchangeWebServices::fromUsernameAndPassword(
214 9
            $server,
215
            $username,
216
            $password,
217
            array_replace_recursive(self::$defaultClientOptions, $options)
218
        ));
219
    }
220 9
221
    public static function withCallbackToken($server, $token, $options = [ ])
222 9
    {
223 9
        return new static(ExchangeWebServices::fromCallbackToken(
224
            $server,
225 9
            $token,
226
            array_replace_recursive(self::$defaultClientOptions, $options)
227 9
        ));
228
    }
229
230 2
    public function getPrimarySmptEmailAddress()
231
    {
232
        if ($this->getPrimarySmtpMailbox() == null) {
233 2
            return null;
234 2
        }
235
236 2
        return $this->getPrimarySmtpMailbox()->getEmailAddress();
237
    }
238 2
239
    public function setPrimarySmtpEmailAddress($emailAddress)
240 2
    {
241
        $this->getClient()->setPrimarySmtpEmailAddress($emailAddress);
242 2
243
        return $this;
244
    }
245 2
246
    /**
247 2
     * Create items through the API client
248
     *
249
     * @param $items
250 2
     * @param array $options
251 2
     * @return API\CreateItemResponseType
252
     */
253 2 View Code Duplication
    public function createItems($items, $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...
254 2
    {
255 2
        if (!is_array($items)) {
256 2
            $items = array($items);
257 2
        }
258
259 2
        $request = array(
260
            'Items' => $items
261
        );
262
263
        $request = array_replace_recursive($request, $options);
264
        $request = Type::buildFromArray($request);
265
266
        $response = $this->getClient()->CreateItem($request);
267
268
        return $response;
269
    }
270
271
    public function updateItems($items, $options = array())
272
    {
273
        $request = array(
274
            'ItemChanges' => $items,
275
            'MessageDisposition' => 'SaveOnly',
276
            'ConflictResolution' => 'AlwaysOverwrite'
277
        );
278
279
        $request = array_replace_recursive($request, $options);
280
281
        $request = Type::buildFromArray($request);
282
283
        return $this->getClient()->UpdateItem($request)->getItems();
0 ignored issues
show
Documentation Bug introduced by
The method getItems does not exist on object<jamesiarmes\PEWS\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...
284
    }
285
286
    protected function buildUpdateItemChanges($itemType, $uriType, $changes)
287
    {
288
        $setItemFields = array();
289
290
        //Add each property to a setItemField
291
        foreach ($changes as $key => $value) {
292
            if (strpos($key, ':') !== false) {
293
                try {
294
                    $fieldUri = $this->getIndexedFieldUriByName(substr($key, 0, strpos($key, ':')), $uriType);
295
296
                    list ($key, $index) = explode(':', $key);
297
                    $fieldKey = key($value);
298
                    $value = $value[$fieldKey];
299
300
                    $setItemFields[] = array(
301
                        'IndexedFieldURI' => array('FieldURI' => $fieldUri, 'FieldIndex' => $index),
302
                        $itemType => array($fieldKey => $value)
303 9
                    );
304
                    continue;
305 9
                } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
306 9
                }
307 9
            }
308
309 9
            $fullName = $this->getFieldUriByName($key, $uriType);
310 9
311 9
            $setItemFields[] = array(
312 8
                'FieldURI' => array('FieldURI' => $fullName),
313 8
                $itemType => array($key => $value)
314 9
            );
315 9
        }
316 9
317 9
        return $setItemFields;
318 9
    }
319 9
320
    public function createFolders($names, Type\FolderIdType $parentFolder, $options = array())
321
    {
322 9
        $request = array('Folders' => array('Folder' => array()));
323
        if (!empty($parentFolder)) {
324 9
            $request['ParentFolderId'] = array('FolderId' => $parentFolder->toArray());
325
        }
326 9
327 9
        if (!is_array($names)) {
328 9
            $names = array($names);
329
        }
330
331 9
        foreach ($names as $name) {
332
            $request['Folders']['Folder'][] = array(
333
                'DisplayName' => $name
334
            );
335
        }
336
337
        $request = array_merge_recursive($request, $options);
338 15
339
        $this->client->CreateFolder($request);
0 ignored issues
show
Documentation Bug introduced by
The method CreateFolder does not exist on object<jamesiarmes\PEWS\API\ExchangeWebServices>? 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...
340
341
        return true;
342 15
    }
343 15
344 View Code Duplication
    public function deleteFolder(Type\FolderIdType $folderId, $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...
345 15
    {
346 15
        $request = array(
347
            'DeleteType' => 'HardDelete',
348 15
            'FolderIds' => array(
349 15
                'FolderId' => $folderId->toArray()
350
            )
351
        );
352
353
        $request = array_merge_recursive($request, $options);
354
        return $this->client->DeleteFolder($request);
0 ignored issues
show
Documentation Bug introduced by
The method DeleteFolder does not exist on object<jamesiarmes\PEWS\API\ExchangeWebServices>? 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...
355
    }
356
357 View Code Duplication
    public function moveItem(Type\ItemIdType $itemId, Type\FolderIdType $folderId, $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...
358 15
    {
359
        $request = array(
360 15
            'ToFolderId' => array('FolderId' => $folderId->toArray()),
361
            'ItemIds' => array('ItemId' => $itemId->toArray())
362 15
        );
363 15
364 15
        $request = array_merge_recursive($request, $options);
365 15
366
        return $this->client->MoveItem($request);
0 ignored issues
show
Documentation Bug introduced by
The method MoveItem does not exist on object<jamesiarmes\PEWS\API\ExchangeWebServices>? 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...
367
    }
368
369
    /**
370
     * @param $items Type\ItemIdType|Type\ItemIdType[]
371
     * @param array $options
372 4
     * @return bool
373
     */
374 4
    public function deleteItems($items, $options = array())
375 4
    {
376 4
        if (!is_array($items) || Type::arrayIsAssoc($items)) {
377
            $items = array($items);
378
        }
379
380
        $itemIds = array();
381
        foreach ($items as $item) {
382
            if ($item instanceof Type\ItemIdType) {
0 ignored issues
show
Bug introduced by
The class jamesiarmes\PEWS\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...
383
                $item = $item->toArray();
384 14
            }
385
            $item = (array) $item;
386 14
            $itemIds[] = array(
387 14
                'Id' => $item['Id'],
388 14
                'ChangeKey' => $item['ChangeKey']
389
            );
390
        }
391 14
392
        $request = array(
393
            'ItemIds' => array('ItemId' => $itemIds),
394 14
            'DeleteType' => 'MoveToDeletedItems'
395
        );
396 14
397 14
        $request = array_replace_recursive($request, $options);
398 14
        $request = Type::buildFromArray($request);
399
        $this->getClient()->DeleteItem($request);
400 14
401
        //If the delete fails, an Exception will be thrown in processResponse before it gets here
402 14
        return true;
403
    }
404
405 14
    /**
406
     * @param $identifier
407
     * @return Type\BaseFolderType
408
     */
409
    public function getFolder($identifier)
410
    {
411
        $request = array(
412
            'FolderShape' => array(
413
                'BaseShape' => array('_' => 'Default')
414
            ),
415 14
            'FolderIds' => $identifier
416
        );
417 14
        $request = Type::buildFromArray($request);
418
419 14
        $response = $this->getClient()->GetFolder($request);
420 14
        return $response;
421 14
    }
422
423 6
    /**
424
     * Get a folder by it's distinguishedId
425
     *
426
     * @param string $distinguishedId
427
     * @return Type\BaseFolderType
428
     */
429
    public function getFolderByDistinguishedId($distinguishedId)
430
    {
431
        return $this->getFolder(array(
432
            'DistinguishedFolderId' => array(
433 1
                'Id' => $distinguishedId,
434
                'Mailbox' => $this->getPrimarySmtpMailbox()
435 1
            )
436
        ));
437
    }
438
439
    /**
440 1
     * @param $folderId
441 1
     * @return Type\BaseFolderType
442 1
     */
443
    public function getFolderByFolderId($folderId)
444 1
    {
445
        return $this->getFolder(array(
446 1
            'FolderId' => array('Id'=>$folderId, 'Mailbox' => $this->getPrimarySmtpMailbox())
447
        ));
448
    }
449
450
    /**
451
     * @param string|Type\FolderIdType $parentFolderId
452
     * @param array $options
453
     * @return bool|Type\BaseFolderType
454
     */
455
    public function getChildrenFolders($parentFolderId = 'root', $options = array())
456
    {
457 2
        if (is_string($parentFolderId)) {
458
            $parentFolderId = $this->getFolderByDistinguishedId($parentFolderId)->getFolderId();
0 ignored issues
show
Documentation Bug introduced by
The method getFolderId does not exist on object<jamesiarmes\PEWS\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...
459
        }
460 2
461 2
        $request = array(
462 2
            'Traversal' => 'Shallow',
463
            'FolderShape' => array(
464 2
                'BaseShape' => 'AllProperties'
465
            ),
466 2
            'ParentFolderIds' => array(
467
                'FolderId' => $parentFolderId->toArray()
468
            )
469
        );
470
471 2
        $request = array_replace_recursive($request, $options);
472
473 2
        $request = Type::buildFromArray($request);
474 2
475 2
        /** @var \jamesiarmes\PEWS\API\Message\FindFolderResponseMessageType $folders */
476
        return $this->getClient()->FindFolder($request);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getClient()->FindFolder($request); (jamesiarmes\PEWS\API\Type) is incompatible with the return type documented by jamesiarmes\PEWS\API::getChildrenFolders of type boolean|jamesiarmes\PEWS\API\Type\BaseFolderType.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
477
        return $folders->getFolders();
0 ignored issues
show
Unused Code introduced by
return $folders->getFolders(); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
478
    }
479
480
    /**
481
     * @param $folderName
482
     * @param string|Type\FolderIdType $parentFolderId
483
     * @param array $options
484
     * @return bool|Type\BaseFolderType
485
     */
486
    public function getFolderByDisplayName($folderName, $parentFolderId = 'root', $options = array())
487
    {
488
        $folders = $this->getChildrenFolders($parentFolderId, $options);
489
490
        foreach ($folders as $folder) {
0 ignored issues
show
Bug introduced by
The expression $folders of type boolean|object<jamesiarm...PI\Type\BaseFolderType> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
491
            if ($folder->getDisplayName() == $folderName) {
492
                return $folder;
493
            }
494
        }
495
496
        return false;
497
    }
498
499
    /**
500
     * @param $itemId array|Type\ItemIdType
501
     * @param array $options
502
     * @return Type
503
     */
504
    public function getItem($itemId, $options = array())
505
    {
506
        if ($itemId instanceof Type\ItemIdType) {
0 ignored issues
show
Bug introduced by
The class jamesiarmes\PEWS\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...
507
            $itemId = $itemId->toArray();
508
        }
509
510
        $request = array(
511
            'ItemShape' => array('BaseShape' => 'AllProperties'),
512
            'ItemIds' => array('ItemId' => $itemId)
513
        );
514
515
        $request = array_replace_recursive($request, $options);
516
517
        return $this->getClient()->GetItem($request);
518
    }
519
520
    /**
521
     * Get a list of sync changes on a folder
522
     *
523
     * @param Type\FolderIdType $folderId
524
     * @param null $syncState
525
     * @param array $options
526
     * @return SyncFolderItemsResponseMessageType
527
     */
528
    public function listItemChanges($folderId, $syncState = null, $options = array())
529
    {
530
        $request = array(
531
            'ItemShape' => array('BaseShape' => 'IdOnly'),
532
            'SyncFolderId' => array('FolderId' => $folderId->toXmlObject()),
533
            'SyncScope' => 'NormalItems',
534
            'MaxChangesReturned' => '10'
535
        );
536
537
        if ($syncState != null) {
538
            $request['SyncState'] = $syncState;
539
            $request['ItemShape']['BaseShape'] = 'AllProperties';
540
        }
541
542
        $request = array_replace_recursive($request, $options);
543
544
        $request = Type::buildFromArray($request);
545
        $response = $this->getClient()->SyncFolderItems($request);
546
        return $response;
547
    }
548
549 View Code Duplication
    public function getServerTimezones($timezoneIDs = array(), $fullTimezoneData = false)
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...
550
    {
551
        $request = GetServerTimeZonesType::buildFromArray(array(
552
            'returnFullTimeZoneData' => $fullTimezoneData
553
        ));
554
555
        if (!empty($timezoneIDs)) {
556
            $request->setIds($timezoneIDs);
557
        }
558
559
        $timezones = $this->getClient()->GetServerTimeZones($request);
0 ignored issues
show
Documentation Bug introduced by
The method GetServerTimeZones does not exist on object<jamesiarmes\PEWS\API\ExchangeWebServices>? 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...
560
        $timezones = $timezones->TimeZoneDefinition;
561
562
        if (!is_array($timezones)) {
563
            $timezones = array($timezones);
564
        }
565
566
        return $timezones;
567
    }
568
}
569