Completed
Push — master ( b05bb8...7c707d )
by Gareth
03:25
created

API::getFieldUrisFromClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace garethp\ews;
4
5
use garethp\ews\API\Enumeration\DictionaryURIType;
6
use garethp\ews\API\Enumeration\UnindexedFieldURIType;
7
use garethp\ews\API\Exception\ExchangeException;
8
use garethp\ews\API\ExchangeWebServices;
9
use garethp\ews\API\Message\GetServerTimeZonesType;
10
use garethp\ews\API\Message\SyncFolderItemsResponseMessageType;
11
use garethp\ews\API\Message\UpdateItemResponseMessageType;
12
use garethp\ews\API\Type;
13
use garethp\ews\Calendar\CalendarAPI;
14
use garethp\ews\Mail\MailAPI;
15
use garethp\ews\API\FieldURIManager;
16
17
/**
18
 * A base class for APIs
19
 *
20
 * Class BaseAPI
21
 * @package garethp\ews
22
 */
23
class API
24
{
25
    protected static $defaultClientOptions = array(
26
        'version' => ExchangeWebServices::VERSION_2010
27
    );
28
29 30
    public function __construct(ExchangeWebServices $client = null)
30
    {
31 30
        if ($client) {
32 18
            $this->setClient($client);
33 18
        }
34 30
    }
35
36
    /**
37
     * @return Type\EmailAddressType
38
     */
39 21
    public function getPrimarySmtpMailbox()
40
    {
41 21
        return $this->getClient()->getPrimarySmtpMailbox();
42
    }
43
44
    /**
45
     * Storing the API client
46
     * @var ExchangeWebServices
47
     */
48
    private $client;
49
50
    /**
51
     * @deprecated This will be removed in 0.9
52
     *
53
     * @param $className
54
     * @return array
55
     */
56
    public function getFieldUrisFromClass($className)
57
    {
58
        return FieldURIManager::getFieldUrisFromClass($className);
0 ignored issues
show
Deprecated Code introduced by
The method garethp\ews\API\FieldURI...getFieldUrisFromClass() has been deprecated with message: This will be made protected in 0.9

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
59
    }
60
61
    public function setupFieldUris()
62
    {
63
        FieldURIManager::setupFieldUris();
0 ignored issues
show
Deprecated Code introduced by
The method garethp\ews\API\FieldURIManager::setupFieldUris() has been deprecated with message: This will be made protected in 0.9

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
64
    }
65
66
    /**
67
     * @deprecated This will be removed in 0.9. See FieldURIManager
68
     *
69
     * @param $fieldName
70
     * @param string $preference
71
     * @throws ExchangeException
72
     * @return string
73
     */
74 5
    public function getFieldUriByName($fieldName, $preference = 'item')
75
    {
76 5
        return FieldURIManager::getFieldUriByName($fieldName, $preference);
77
    }
78
79
    /**
80
     * @deprecated This will be removed in 0.9. See FieldURIManager
81
     *
82
     * @param $fieldName
83
     * @param string $preference
84
     * @param bool $entryKey
85
     * @throws ExchangeException
86
     * @return string
87
     */
88 1
    public function getIndexedFieldUriByName($fieldName, $preference = 'item', $entryKey = false)
89
    {
90 1
        return FieldURIManager::getIndexedFieldUriByName($fieldName, $preference, $entryKey);
91
    }
92
93
    /**
94
     * Get a calendar item
95
     *
96
     * @param string $name
97
     * @return CalendarAPI
98
     */
99 6
    public function getCalendar($name = null)
100
    {
101 6
        $calendar = new CalendarAPI();
102 6
        $calendar->setClient($this->getClient());
103 6
        $calendar->pickCalendar($name);
104
105 6
        return $calendar;
106
    }
107
108
    /**
109
     * @param string $folderName
110
     * @return MailAPI
111
     */
112 6
    public function getMailbox($folderName = null)
113
    {
114 6
        $mailApi = new MailAPI();
115 6
        $mailApi->setClient($this->getClient());
116 6
        $mailApi->pickMailFolder($folderName);
117
118 6
        return $mailApi;
119
    }
120
121
    /**
122
     * Set the API client
123
     *
124
     * @param ExchangeWebServices $client
125
     * @return $this
126
     */
127 30
    public function setClient($client)
128
    {
129 30
        $this->client = $client;
130 30
        return $this;
131
    }
132
133
    /**
134
     * Get the API client
135
     *
136
     * @return ExchangeWebServices
137
     */
138 28
    public function getClient()
139
    {
140 28
        return $this->client;
141
    }
142
143
    /**
144
     * Instantiate and set a client (ExchangeWebServices) based on the parameters given
145
     *
146
     * @deprecated Since 0.6.3
147
     * @param $server
148
     * @param $username
149
     * @param $password
150
     * @param array $options
151
     * @return $this
152
     */
153 12
    public function buildClient(
154
        $server,
155
        $username,
156
        $password,
157
        $options = []
158
    ) {
159 12
        $this->setClient(ExchangeWebServices::fromUsernameAndPassword(
160 12
            $server,
161 12
            $username,
162 12
            $password,
163 12
            array_replace_recursive(self::$defaultClientOptions, $options)
164 12
        ));
165 12
    }
166
167 17
    public static function withUsernameAndPassword($server, $username, $password, $options = [])
168
    {
169 17
        return new static(ExchangeWebServices::fromUsernameAndPassword(
170 17
            $server,
171 17
            $username,
172 17
            $password,
173 17
            array_replace_recursive(self::$defaultClientOptions, $options)
174 17
        ));
175
    }
176
177 1
    public static function withCallbackToken($server, $token, $options = [])
178
    {
179 1
        return new static(ExchangeWebServices::fromCallbackToken(
180 1
            $server,
181 1
            $token,
182 1
            array_replace_recursive(self::$defaultClientOptions, $options)
183 1
        ));
184
    }
185
186 1
    public function getPrimarySmptEmailAddress()
187
    {
188 1
        if ($this->getPrimarySmtpMailbox() == null) {
189 1
            return null;
190
        }
191
192 1
        return $this->getPrimarySmtpMailbox()->getEmailAddress();
193
    }
194
195 1
    public function setPrimarySmtpEmailAddress($emailAddress)
196
    {
197 1
        $this->getClient()->setPrimarySmtpEmailAddress($emailAddress);
198
199 1
        return $this;
200
    }
201
202
    /**
203
     * Create items through the API client
204
     *
205
     * @param $items
206
     * @param array $options
207
     * @return Type
208
     */
209 13
    public function createItems($items, $options = array())
210
    {
211 13
        if (!is_array($items)) {
212
            $items = array($items);
213
        }
214
215
        $request = array(
216
            'Items' => $items
217 13
        );
218
219 13
        $request = array_replace_recursive($request, $options);
220 13
        $request = Type::buildFromArray($request);
221
222 13
        $response = $this->getClient()->CreateItem($request);
223
224 13
        return $response;
225
    }
226
227 3
    public function updateItems($items, $options = array())
228
    {
229
        $request = array(
230 3
            'ItemChanges' => $items,
231 3
            'MessageDisposition' => 'SaveOnly',
232
            'ConflictResolution' => 'AlwaysOverwrite'
233 3
        );
234
235 3
        $request = array_replace_recursive($request, $options);
236
237 3
        $request = Type::buildFromArray($request);
238
239 3
        $response = $this->getClient()->UpdateItem($request);
240 3
        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...
241 3
            return $response->getItems();
242
        }
243
244
        if (!is_array($response)) {
245
            $response = array($response);
246
        }
247
        return $response;
248
    }
249
250 3
    protected function getFieldURI($uriType, $key = null, $value = null)
251
    {
252 3
        if (strpos($key, ':') !== false) {
253
            try {
254 1
                $fieldUriValue = substr($key, 0, strpos($key, ':'));
255
256 1
                list ($key, $index) = explode(':', $key);
257
258 1
                if (is_array($value)) {
259 1
                    $key = key($value);
260 1
                    $value = $value[$key];
261 1
                }
262
263 1
                if (is_array($value) && !empty($value['Entry']) && is_array($value['Entry'])) {
264 1
                    $entryKey = $value['Entry']['Key'];
265 1
                    unset($value['Entry']['Key']);
266 1
                    reset($value['Entry']);
267
268 1
                    $fieldKey = key($value['Entry']);
269 1
                    $value['Entry']['Key'] = $entryKey;
270 1
                    $fieldUri = $this->getIndexedFieldUriByName($fieldUriValue, $uriType, $fieldKey);
0 ignored issues
show
Deprecated Code introduced by
The method garethp\ews\API::getIndexedFieldUriByName() has been deprecated with message: This will be removed in 0.9. See FieldURIManager

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
271 1
                } else {
272
                    $fieldUri = $this->getIndexedFieldUriByName($fieldUriValue, $uriType);
0 ignored issues
show
Deprecated Code introduced by
The method garethp\ews\API::getIndexedFieldUriByName() has been deprecated with message: This will be removed in 0.9. See FieldURIManager

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
273
                }
274
275 1
                return ['IndexedFieldURI', ['FieldURI' => $fieldUri, 'FieldIndex' => $index], $key, $value];
276
            } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
277
            }
278
        }
279
280 3
        $fullName = $this->getFieldUriByName($key, $uriType);
0 ignored issues
show
Deprecated Code introduced by
The method garethp\ews\API::getFieldUriByName() has been deprecated with message: This will be removed in 0.9. See FieldURIManager

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
281 3
        return ['FieldURI', ['FieldURI' => $fullName], $key, $value];
282
    }
283
284
    /**
285
     * @param string $itemType
286
     * @param string $uriType
287
     */
288 3
    protected function buildUpdateItemChanges($itemType, $uriType, $changes)
289
    {
290 3
        $setItemFields = array();
291 3
        $deleteItemFields = array();
292
293 3
        if (isset($changes['deleteFields'])) {
294
            foreach ($changes['deleteFields'] as $key) {
295
                list($fieldUriType, $fieldKey) = $this->getFieldURI($uriType, $key);
296
                $deleteItemFields[] = [$fieldUriType => $fieldKey];
297
            }
298
299
            unset($changes['deleteFields']);
300
        }
301
302
        //Add each property to a setItemField
303 3
        foreach ($changes as $key => $valueArray) {
304 3
            $valueArray = $this->splitDictionaryUpdateEntries($valueArray);
305 3
            if (!is_array($valueArray) || Type::arrayIsAssoc($valueArray)) {
306 3
                $valueArray = array($valueArray);
307 3
            }
308
309 3
            foreach ($valueArray as $value) {
310 3
                list ($fieldUriType, $fieldKey, $valueKey, $value) = $this->getFieldURI($uriType, $key, $value);
311 3
                $setItemFields[] = array(
312 3
                    $fieldUriType => $fieldKey,
313 3
                    $itemType => [$valueKey => $value]
314 3
                );
315 3
            }
316 3
        }
317
318 3
        return array('SetItemField' => $setItemFields, 'DeleteItemField' => $deleteItemFields);
319
    }
320
321 3
    protected function splitDictionaryUpdateEntries($value)
322
    {
323 3
        if (!is_array($value)) {
324 3
            return $value;
325
        }
326
327 1
        reset($value);
328 1
        $fieldKey = key($value);
329
330 1
        if (!is_array($value[$fieldKey]) || empty($value[$fieldKey]['Entry'])) {
331
            return $value;
332
        }
333
334 1
        $entryKey = $value[$fieldKey]['Entry']['Key'];
335 1
        unset($value[$fieldKey]['Entry']['Key']);
336
337 1
        $newValue = [];
338 1
        foreach ($value[$fieldKey]['Entry'] as $key => $updateValue) {
339 1
            $newValue[] = [$fieldKey => ['Entry' => ['Key' => $entryKey, $key => $updateValue]]];
340 1
        }
341
342 1
        $value = $newValue;
343
344 1
        return $value;
345
    }
346
347 2
    public function createFolders($names, Type\FolderIdType $parentFolder, $options = array())
348
    {
349 2
        $request = array('Folders' => array('Folder' => array()));
350 2
        if (!empty($parentFolder)) {
351 2
            $request['ParentFolderId'] = array('FolderId' => $parentFolder->toArray());
352 2
        }
353
354 2
        if (!is_array($names)) {
355 2
            $names = array($names);
356 2
        }
357
358 2
        foreach ($names as $name) {
359 2
            $request['Folders']['Folder'][] = array(
360
                'DisplayName' => $name
361 2
            );
362 2
        }
363
364 2
        $request = array_merge_recursive($request, $options);
365
366 2
        $this->client->CreateFolder($request);
0 ignored issues
show
Documentation Bug introduced by
The method CreateFolder does not exist on object<garethp\ews\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 2
        return true;
369
    }
370
371 2 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...
372
    {
373
        $request = array(
374 2
            'DeleteType' => 'HardDelete',
375
            'FolderIds' => array(
376 2
                'FolderId' => $folderId->toArray()
377 2
            )
378 2
        );
379
380 2
        $request = array_merge_recursive($request, $options);
381 2
        return $this->client->DeleteFolder($request);
0 ignored issues
show
Documentation Bug introduced by
The method DeleteFolder does not exist on object<garethp\ews\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...
382
    }
383
384 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...
385
    {
386
        $request = array(
387
            'ToFolderId' => array('FolderId' => $folderId->toArray()),
388
            'ItemIds' => array('ItemId' => $itemId->toArray())
389
        );
390
391
        $request = array_merge_recursive($request, $options);
392
393
        return $this->client->MoveItem($request);
0 ignored issues
show
Documentation Bug introduced by
The method MoveItem does not exist on object<garethp\ews\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...
394
    }
395
396
    /**
397
     * @param $items Type\ItemIdType|Type\ItemIdType[]
398
     * @param array $options
399
     * @return bool
400
     */
401 13
    public function deleteItems($items, $options = array())
402
    {
403 13
        if (!is_array($items) || Type::arrayIsAssoc($items)) {
404 13
            $items = array($items);
405 13
        }
406
407 13
        $itemIds = array();
408 13
        foreach ($items as $item) {
409 13
            if ($item 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 12
                $item = $item->toArray();
411 12
            }
412 13
            $item = (array) $item;
413 13
            $itemIds[] = array(
414 13
                'Id' => $item['Id'],
415 13
                'ChangeKey' => $item['ChangeKey']
416 13
            );
417 13
        }
418
419
        $request = array(
420 13
            'ItemIds' => array('ItemId' => $itemIds),
421
            'DeleteType' => 'MoveToDeletedItems'
422 13
        );
423
424 13
        $request = array_replace_recursive($request, $options);
425 13
        $request = Type::buildFromArray($request);
426 13
        $this->getClient()->DeleteItem($request);
427
428
        //If the delete fails, an Exception will be thrown in processResponse before it gets here
429 13
        return true;
430
    }
431
432
    /**
433
     * @param $identifier
434
     * @return Type\BaseFolderType
435
     */
436 20
    public function getFolder($identifier)
437
    {
438
        $request = array(
439
            'FolderShape' => array(
440 20
                'BaseShape' => array('_' => 'Default')
441 20
            ),
442
            'FolderIds' => $identifier
443 20
        );
444 20
        $request = Type::buildFromArray($request);
445
446 20
        $response = $this->getClient()->GetFolder($request);
447 20
        return $response;
448
    }
449
450
    /**
451
     * Get a folder by it's distinguishedId
452
     *
453
     * @param string $distinguishedId
454
     * @return Type\BaseFolderType
455
     */
456 20
    public function getFolderByDistinguishedId($distinguishedId)
457
    {
458 20
        return $this->getFolder(array(
459
            'DistinguishedFolderId' => array(
460 20
                'Id' => $distinguishedId,
461 20
                'Mailbox' => $this->getPrimarySmtpMailbox()
462 20
            )
463 20
        ));
464
    }
465
466
    /**
467
     * @param $folderId
468
     * @return Type\BaseFolderType
469
     */
470 4
    public function getFolderByFolderId($folderId)
471
    {
472 4
        return $this->getFolder(array(
473 4
            'FolderId' => array('Id'=>$folderId, 'Mailbox' => $this->getPrimarySmtpMailbox())
474 4
        ));
475
    }
476
477
    /**
478
     * @param string|Type\FolderIdType $parentFolderId
479
     * @param array $options
480
     * @return bool|Type\BaseFolderType
481
     */
482 19
    public function getChildrenFolders($parentFolderId = 'root', $options = array())
483
    {
484 19
        if (is_string($parentFolderId)) {
485 15
            $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...
486 15
        }
487
488
        $request = array(
489 19
            'Traversal' => 'Shallow',
490
            'FolderShape' => array(
491
                'BaseShape' => 'AllProperties'
492 19
            ),
493
            'ParentFolderIds' => array(
494 19
                'FolderId' => $parentFolderId->toArray()
495 19
            )
496 19
        );
497
498 19
        $request = array_replace_recursive($request, $options);
499
500 19
        $request = Type::buildFromArray($request);
501
502
        /** @var \garethp\ews\API\Message\FindFolderResponseMessageType $folders */
503 19
        return $this->getClient()->FindFolder($request);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getClient()->FindFolder($request); (garethp\ews\API\Type) is incompatible with the return type documented by garethp\ews\API::getChildrenFolders of type boolean|garethp\ews\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...
504
        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...
505
    }
506
507
    /**
508
     * @param string $folderName
509
     * @param string|Type\FolderIdType $parentFolderId
510
     * @param array $options
511
     * @return bool|Type\BaseFolderType
512
     */
513 19
    public function getFolderByDisplayName($folderName, $parentFolderId = 'root', $options = array())
514
    {
515 19
        $folders = $this->getChildrenFolders($parentFolderId, $options);
516
517 19
        foreach ($folders as $folder) {
0 ignored issues
show
Bug introduced by
The expression $folders of type boolean|object<garethp\e...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...
518 19
            if ($folder->getDisplayName() == $folderName) {
519 18
                return $folder;
520
            }
521 13
        }
522
523 3
        return false;
524
    }
525
526
    /**
527
     * @param $itemId array|Type\ItemIdType
528
     * @param array $options
529
     * @return Type
530
     */
531 4 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...
532
    {
533 4
        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...
534 3
            $itemId = $itemId->toArray();
535 3
        }
536
537
        $request = array(
538 4
            'ItemShape' => array('BaseShape' => 'AllProperties'),
539 4
            'ItemIds' => array('ItemId' => $itemId)
540 4
        );
541
542 4
        $request = array_replace_recursive($request, $options);
543
544 4
        return $this->getClient()->GetItem($request);
545
    }
546
547
    /**
548
     * Get a list of sync changes on a folder
549
     *
550
     * @param Type\FolderIdType $folderId
551
     * @param null $syncState
552
     * @param array $options
553
     * @return SyncFolderItemsResponseMessageType
554
     */
555 2
    public function listItemChanges($folderId, $syncState = null, $options = array())
556
    {
557
        $request = array(
558 2
            'ItemShape' => array('BaseShape' => 'IdOnly'),
559 2
            'SyncFolderId' => array('FolderId' => $folderId->toXmlObject()),
560 2
            'SyncScope' => 'NormalItems',
561
            'MaxChangesReturned' => '10'
562 2
        );
563
564 2
        if ($syncState != null) {
565 1
            $request['SyncState'] = $syncState;
566 1
            $request['ItemShape']['BaseShape'] = 'AllProperties';
567 1
        }
568
569 2
        $request = array_replace_recursive($request, $options);
570
571 2
        $request = Type::buildFromArray($request);
572 2
        $response = $this->getClient()->SyncFolderItems($request);
573 2
        return $response;
574
    }
575
576
    public function getServerTimezones($timezoneIDs = array(), $fullTimezoneData = false)
577
    {
578
        $request = GetServerTimeZonesType::buildFromArray(array(
579
            'returnFullTimeZoneData' => $fullTimezoneData
580
        ));
581
582
        if (!empty($timezoneIDs)) {
583
            $request->setIds($timezoneIDs);
584
        }
585
586
        $timezones = $this->getClient()->GetServerTimeZones($request);
0 ignored issues
show
Documentation Bug introduced by
The method GetServerTimeZones does not exist on object<garethp\ews\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...
587
        $timezones = $timezones->TimeZoneDefinition;
588
589
        if (!is_array($timezones)) {
590
            $timezones = array($timezones);
591
        }
592
593
        return $timezones;
594
    }
595
596
    /**
597
     * @param Type\ItemIdType $itemId
598
     * @param $fromType
599
     * @param $destinationType
600
     * @param $mailbox
601
     *
602
     * @return Type\ItemIdType
603
     */
604
    public function convertIdFormat(Type\ItemIdType $itemId, $fromType, $destinationType, $mailbox)
605
    {
606
        $result = $this->getClient()->ConvertId(array(
0 ignored issues
show
Documentation Bug introduced by
The method ConvertId does not exist on object<garethp\ews\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...
607
            'DestinationFormat' => $destinationType,
608
            'SourceIds' => array(
609
                'AlternateId' => array(
610
                    'Format' => $fromType,
611
                    'Id' => $itemId->getId(),
612
                    'Mailbox' => $mailbox
613
                )
614
            )
615
        ));
616
617
        $itemId->setId($result->getId());
618
619
        return $itemId;
620
    }
621
}
622