Completed
Pull Request — master (#50)
by
unknown
03:53
created

API::getServerTimezones()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
173 4
            return $response->getItems();
174
        }
175
176
        if (!is_array($response)) {
177
            $response = array($response);
178
        }
179
180
        return $response;
181
    }
182
183
    /**
184
     * @param string $itemType
185
     * @param string $uriType
186
     * @param array $changes
187
     * @return array
188
     */
189 4
    protected function buildUpdateItemChanges($itemType, $uriType, $changes)
190
    {
191 4
        return ItemUpdateBuilder::buildUpdateItemChanges($itemType, $uriType, $changes);
192
    }
193
194 1
    public function createCalendars($names, Type\FolderIdType $parentFolder = null, $options = array())
195
    {
196 1
        if ($parentFolder == null) {
197 1
            $parentFolder = $this->getFolderByDistinguishedId('calendar')->getFolderId();
0 ignored issues
show
Documentation Bug introduced by
The method getFolderId does not exist on object<garethp\ews\API\Type>? Since you implemented __call, maybe consider adding a @method annotation.

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

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

class ParentClass {
    private $data = array();

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

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

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
198 1
        }
199
200 1
        $request = array('Folders' => array('Folder' => array()));
201 1
        if (!empty($parentFolder)) {
202 1
            $request['ParentFolderId'] = array('FolderId' => $parentFolder->toArray());
203 1
        }
204
205 1
        if (!is_array($names)) {
206 1
            $names = array($names);
207 1
        }
208
209 1
        foreach ($names as $name) {
210 1
            $request['Folders']['Folder'][] = array(
211 1
                'DisplayName' => $name,
212
                'FolderClass' => 'IPF.Appointment'
213 1
            );
214 1
        }
215
216 1
        $request = array_merge_recursive($request, $options);
217
218 1
        $this->client->CreateFolder($request);
219
220 1
        return true;
221
    }
222
    
223 2
    public function createFolders($names, Type\FolderIdType $parentFolder, $options = array())
224
    {
225 2
        $request = array('Folders' => array('Folder' => array()));
226 2
        if (!empty($parentFolder)) {
227 2
            $request['ParentFolderId'] = array('FolderId' => $parentFolder->toArray());
228 2
        }
229
230 2
        if (!is_array($names)) {
231 2
            $names = array($names);
232 2
        }
233
234 2
        foreach ($names as $name) {
235 2
            $request['Folders']['Folder'][] = array(
236
                'DisplayName' => $name
237 2
            );
238 2
        }
239
240 2
        $request = array_merge_recursive($request, $options);
241
242 2
        $this->client->CreateFolder($request);
243
244 2
        return true;
245
    }
246
247 3 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...
248
    {
249
        $request = array(
250 3
            'DeleteType' => 'HardDelete',
251
            'FolderIds' => array(
252 3
                'FolderId' => $folderId->toArray()
253 3
            )
254 3
        );
255
256 3
        $request = array_merge_recursive($request, $options);
257
258 3
        return $this->client->DeleteFolder($request);
259
    }
260
261 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...
262
    {
263
        $request = array(
264
            'ToFolderId' => array('FolderId' => $folderId->toArray()),
265
            'ItemIds' => array('ItemId' => $itemId->toArray())
266
        );
267
268
        $request = array_merge_recursive($request, $options);
269
270
        return $this->client->MoveItem($request);
271
    }
272
273
    /**
274
     * @param        $items Type\ItemIdType|Type\ItemIdType[]
275
     * @param array  $options
276
     * @param string $deleteType DisposalType::HARD_DELETE
277
     *                           DisposalType::MOVE_TO_DELETED_ITEMS
278
     *                           DisposalType::SOFT_DELETE
279
     *
280
     * @return bool
281
     */
282 15
    public function deleteItems($items, $options = array(), $deleteType = DisposalType::MOVE_TO_DELETED_ITEMS)
283
    {
284 15
        if (!is_array($items) || Type::arrayIsAssoc($items)) {
285 15
            $items = array($items);
286 15
        }
287
288 15
        $itemIds = array();
289 15
        foreach ($items as $item) {
290 15
            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...
291 14
                $item = $item->toArray();
292 14
            }
293 15
            $item = (array)$item;
294 15
            $itemIds[] = array(
295 15
                'Id' => $item['Id'],
296 15
                'ChangeKey' => $item['ChangeKey']
297 15
            );
298 15
        }
299
300
        $request = array(
301 15
            'ItemIds' => array('ItemId' => $itemIds),
302
            'DeleteType' => $deleteType
303 15
        );
304
305 15
        $request = array_replace_recursive($request, $options);
306 15
        $request = Type::buildFromArray($request);
307 15
        $this->getClient()->DeleteItem($request);
308
309
        //If the delete fails, an Exception will be thrown in processResponse before it gets here
310 15
        return true;
311
    }
312
313
    /**
314
     * @param $identifier
315
     * @return Type\BaseFolderType
316
     */
317 23
    public function getFolder($identifier)
318
    {
319
        $request = array(
320
            'FolderShape' => array(
321 23
                'BaseShape' => array('_' => 'Default')
322 23
            ),
323
            'FolderIds' => $identifier
324 23
        );
325 23
        $request = Type::buildFromArray($request);
326
327 23
        $response = $this->getClient()->GetFolder($request);
328
329 23
        return $response;
330
    }
331
332
    /**
333
     * Get a folder by it's distinguishedId
334
     *
335
     * @param string $distinguishedId
336
     * @return Type\BaseFolderType
337
     */
338 23
    public function getFolderByDistinguishedId($distinguishedId)
339
    {
340 23
        return $this->getFolder(array(
341
            'DistinguishedFolderId' => array(
342 23
                'Id' => $distinguishedId,
343 23
                'Mailbox' => $this->getPrimarySmtpMailbox()
344 23
            )
345 23
        ));
346
    }
347
348
    /**
349
     * @param $folderId
350
     * @return Type\BaseFolderType
351
     */
352 4
    public function getFolderByFolderId($folderId)
353
    {
354 4
        return $this->getFolder(array(
355 4
            'FolderId' => array('Id' => $folderId, 'Mailbox' => $this->getPrimarySmtpMailbox())
356 4
        ));
357
    }
358
359
    /**
360
     * @param string|Type\FolderIdType $parentFolderId
361
     * @param array $options
362
     * @return bool|Type\BaseFolderType
363
     */
364 22
    public function getChildrenFolders($parentFolderId = 'root', $options = array())
365
    {
366 22
        if (is_string($parentFolderId)) {
367 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...
368 15
        }
369
370
        $request = array(
371 22
            'Traversal' => 'Shallow',
372
            'FolderShape' => array(
373
                'BaseShape' => 'AllProperties'
374 22
            ),
375
            'ParentFolderIds' => array(
376 22
                'FolderId' => $parentFolderId->toArray()
377 22
            )
378 22
        );
379
380 22
        $request = array_replace_recursive($request, $options);
381
382 22
        $request = Type::buildFromArray($request);
383
384
        /** @var \garethp\ews\API\Message\FindFolderResponseMessageType $folders */
385 22
        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...
386
387
        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...
388
    }
389
390
    /**
391
     * @param string $folderName
392
     * @param string|Type\FolderIdType $parentFolderId
393
     * @param array $options
394
     * @return bool|Type\BaseFolderType
395
     */
396 22
    public function getFolderByDisplayName($folderName, $parentFolderId = 'root', $options = array())
397
    {
398 22
        $folders = $this->getChildrenFolders($parentFolderId, $options);
399
400 22
        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...
401 22
            if ($folder->getDisplayName() == $folderName) {
402 21
                return $folder;
403
            }
404 16
        }
405
406 4
        return false;
407
    }
408
409
    /**
410
     * @param $itemId array|Type\ItemIdType
411
     * @param array $options
412
     * @return Type
413
     */
414 5 View Code Duplication
    public function getItem($itemId, $options = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
415
    {
416 5
        if ($itemId instanceof Type\ItemIdType) {
0 ignored issues
show
Bug introduced by
The class garethp\ews\API\Type\ItemIdType does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
417 4
            $itemId = $itemId->toArray();
418 4
        }
419
420
        $request = array(
421 5
            'ItemShape' => array('BaseShape' => 'AllProperties'),
422 5
            'ItemIds' => array('ItemId' => $itemId)
423 5
        );
424
425 5
        $request = array_replace_recursive($request, $options);
426
427 5
        return $this->getClient()->GetItem($request);
428
    }
429
430
    /**
431
     * Get a list of sync changes on a folder
432
     *
433
     * @param Type\FolderIdType $folderId
434
     * @param null $syncState
435
     * @param array $options
436
     * @return SyncFolderItemsResponseMessageType
437
     */
438 2
    public function listItemChanges($folderId, $syncState = null, $options = array())
439
    {
440
        $request = array(
441 2
            'ItemShape' => array('BaseShape' => 'IdOnly'),
442 2
            'SyncFolderId' => array('FolderId' => $folderId->toXmlObject()),
443 2
            'SyncScope' => 'NormalItems',
444
            'MaxChangesReturned' => '10'
445 2
        );
446
447 2
        if ($syncState != null) {
448 1
            $request['SyncState'] = $syncState;
449 1
            $request['ItemShape']['BaseShape'] = 'AllProperties';
450 1
        }
451
452 2
        $request = array_replace_recursive($request, $options);
453
454 2
        switch ($this->getClient()->getVersion()) {
455 2
            case ExchangeWebServices::VERSION_2007:
456 2
            case ExchangeWebServices::VERSION_2007_SP1:
457
                unset($request['SyncScope']);
458 2
        }
459
460 2
        $request = Type::buildFromArray($request);
461 2
        $response = $this->getClient()->SyncFolderItems($request);
462
463 2
        return $response;
464
    }
465
466
    public function getServerTimezones($timezoneIDs = array(), $fullTimezoneData = false)
467
    {
468
        $request = GetServerTimeZonesType::buildFromArray(array(
469
            'returnFullTimeZoneData' => $fullTimezoneData
470
        ));
471
472
        if (!empty($timezoneIDs)) {
473
            $request->setIds($timezoneIDs);
474
        }
475
476
        $timezones = $this->getClient()->GetServerTimeZones($request);
477
        $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...
478
479
        if (!is_array($timezones)) {
480
            $timezones = array($timezones);
481
        }
482
483
        return $timezones;
484
    }
485
486
    /**
487
     * @param Type\ItemIdType $itemId
488
     * @param $fromType
489
     * @param $destinationType
490
     * @param $mailbox
491
     *
492
     * @return Type\ItemIdType
493
     */
494
    public function convertIdFormat(Type\ItemIdType $itemId, $fromType, $destinationType, $mailbox)
495
    {
496
        $result = $this->getClient()->ConvertId(array(
497
            'DestinationFormat' => $destinationType,
498
            'SourceIds' => array(
499
                'AlternateId' => array(
500
                    'Format' => $fromType,
501
                    'Id' => $itemId->getId(),
502
                    'Mailbox' => $mailbox
503
                )
504
            )
505
        ));
506
507
        $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...
508
509
        return $itemId;
510
    }
511
}
512