Completed
Push — search_feature_flags ( 457ab1...63fd57 )
by André
23:24
created

Repository   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 544
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

Changes 0
Metric Value
dl 0
loc 544
c 0
b 0
f 0
rs 8.295
wmc 42
lcom 1
cbo 14

26 Methods

Rating   Name   Duplication   Size   Complexity  
A getCurrentUser() 0 4 1
A __construct() 0 5 1
A getCurrentUserReference() 0 4 1
A setCurrentUser() 0 4 1
A sudo() 0 4 1
A hasAccess() 0 4 1
A canUser() 0 4 1
A getContentService() 0 10 2
A getContentLanguageService() 0 10 2
A getContentTypeService() 0 10 2
A getLocationService() 0 10 2
A getTrashService() 0 10 2
A getSectionService() 0 10 2
A getUserService() 0 10 2
A getURLAliasService() 0 10 2
A getURLWildcardService() 0 10 2
A getObjectStateService() 0 10 2
A getRoleService() 0 10 2
A getSearchService() 0 10 2
A getFieldTypeService() 0 10 2
A getPermissionResolver() 0 4 1
A beginTransaction() 0 10 2
A commit() 0 10 2
A rollback() 0 8 2
A commitEvent() 0 4 1
A createDateTime() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Repository often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Repository, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Repository class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\SignalSlot;
10
11
use eZ\Publish\API\Repository\Repository as RepositoryInterface;
12
use eZ\Publish\API\Repository\Values\ValueObject;
13
use eZ\Publish\API\Repository\Values\User\UserReference;
14
use eZ\Publish\SPI\Persistence\TransactionHandler;
15
16
/**
17
 * Repository class.
18
 */
19
class Repository implements RepositoryInterface
20
{
21
    /**
22
     * Repository Handler object.
23
     *
24
     * @var \eZ\Publish\API\Repository\Repository
25
     */
26
    protected $repository;
27
28
    /**
29
     * SignalDispatcher.
30
     *
31
     * @var \eZ\Publish\Core\SignalSlot\SignalDispatcher
32
     */
33
    protected $signalDispatcher;
34
35
    /**
36
     * Instance of content service.
37
     *
38
     * @var \eZ\Publish\API\Repository\ContentService
39
     */
40
    protected $contentService;
41
42
    /**
43
     * Instance of section service.
44
     *
45
     * @var \eZ\Publish\API\Repository\SectionService
46
     */
47
    protected $sectionService;
48
49
    /**
50
     * Instance of role service.
51
     *
52
     * @var \eZ\Publish\API\Repository\RoleService
53
     */
54
    protected $roleService;
55
56
    /**
57
     * Instance of search service.
58
     *
59
     * @var \eZ\Publish\API\Repository\SearchService
60
     */
61
    protected $searchService;
62
63
    /**
64
     * Instance of user service.
65
     *
66
     * @var \eZ\Publish\API\Repository\UserService
67
     */
68
    protected $userService;
69
70
    /**
71
     * Instance of language service.
72
     *
73
     * @var \eZ\Publish\API\Repository\LanguageService
74
     */
75
    protected $languageService;
76
77
    /**
78
     * Instance of location service.
79
     *
80
     * @var \eZ\Publish\API\Repository\LocationService
81
     */
82
    protected $locationService;
83
84
    /**
85
     * Instance of Trash service.
86
     *
87
     * @var \eZ\Publish\API\Repository\TrashService
88
     */
89
    protected $trashService;
90
91
    /**
92
     * Instance of content type service.
93
     *
94
     * @var \eZ\Publish\API\Repository\ContentTypeService
95
     */
96
    protected $contentTypeService;
97
98
    /**
99
     * Instance of IO service.
100
     *
101
     * @var \eZ\Publish\API\Repository\IOService
102
     */
103
    protected $ioService;
104
105
    /**
106
     * Instance of object state service.
107
     *
108
     * @var \eZ\Publish\API\Repository\ObjectStateService
109
     */
110
    protected $objectStateService;
111
112
    /**
113
     * Instance of field type service.
114
     *
115
     * @var \eZ\Publish\API\Repository\FieldTypeService
116
     */
117
    protected $fieldTypeService;
118
119
    /**
120
     * Instance of URL alias service.
121
     *
122
     * @var \eZ\Publish\Core\Repository\URLAliasService
123
     */
124
    protected $urlAliasService;
125
126
    /**
127
     * Instance of URL wildcard service.
128
     *
129
     * @var \eZ\Publish\Core\Repository\URLWildcardService
130
     */
131
    protected $urlWildcardService;
132
133
    /**
134
     * Constructor.
135
     *
136
     * Construct repository object from aggregated repository and signal
137
     * dispatcher
138
     *
139
     * @param \eZ\Publish\API\Repository\Repository $repository
140
     * @param \eZ\Publish\Core\SignalSlot\SignalDispatcher $signalDispatcher
141
     */
142
    public function __construct(RepositoryInterface $repository, SignalDispatcher $signalDispatcher)
143
    {
144
        $this->repository = $repository;
145
        $this->signalDispatcher = $signalDispatcher;
146
    }
147
148
    /**
149
     * @deprecated since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead.
150
     *
151
     * Get current user.
152
     *
153
     * @return \eZ\Publish\API\Repository\Values\User\User
154
     */
155
    public function getCurrentUser()
156
    {
157
        return $this->repository->getCurrentUser();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

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...
158
    }
159
160
    /**
161
     * @deprecated since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead.
162
     *
163
     * Get current user ref.
164
     *
165
     * @return \eZ\Publish\API\Repository\Values\User\UserReference
166
     */
167
    public function getCurrentUserReference()
168
    {
169
        return $this->repository->getCurrentUserReference();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...tCurrentUserReference() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user reference.

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...
170
    }
171
172
    /**
173
     * @deprecated since 6.6, to be removed. Use PermissionResolver::setCurrentUserReference() instead.
174
     *
175
     * Sets the current user to the given $user.
176
     *
177
     * @param \eZ\Publish\API\Repository\Values\User\UserReference $user
178
     */
179
    public function setCurrentUser(UserReference $user)
180
    {
181
        return $this->repository->setCurrentUser($user);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::setCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::setCurrentUserReference() instead. Sets the current user to the given $user.

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...
182
    }
183
184
    /**
185
     * Allows API execution to be performed with full access sand-boxed.
186
     *
187
     * The closure sandbox will do a catch all on exceptions and rethrow after
188
     * re-setting the sudo flag.
189
     *
190
     * Example use:
191
     *     $location = $repository->sudo(
192
     *         function ( Repository $repo ) use ( $locationId )
193
     *         {
194
     *             return $repo->getLocationService()->loadLocation( $locationId )
195
     *         }
196
     *     );
197
     *
198
     *
199
     * @param \Closure $callback
200
     *
201
     * @throws \RuntimeException Thrown on recursive sudo() use.
202
     * @throws \Exception Re throws exceptions thrown inside $callback
203
     *
204
     * @return mixed
205
     */
206
    public function sudo(\Closure $callback)
207
    {
208
        return $this->repository->sudo($callback, $this);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface eZ\Publish\API\Repository\Repository as the method sudo() does only exist in the following implementations of said interface: eZ\Publish\Core\Repository\Repository, eZ\Publish\Core\SignalSlot\Repository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
209
    }
210
211
    /**
212
     * @deprecated since 6.6, to be removed. Use PermissionResolver::hasAccess() instead.
213
     *
214
     * Check if user has access to a given module / function.
215
     *
216
     * Low level function, use canUser instead if you have objects to check against.
217
     *
218
     * @param string $module
219
     * @param string $function
220
     * @param \eZ\Publish\API\Repository\Values\User\UserReference $user
221
     *
222
     * @return bool|array Bool if user has full or no access, array if limitations if not
223
     */
224
    public function hasAccess($module, $function, UserReference $user = null)
225
    {
226
        return $this->repository->hasAccess($module, $function, $user);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::hasAccess() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::hasAccess() instead.

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...
227
    }
228
229
    /**
230
     * @deprecated since 6.6, to be removed. Use PermissionResolver::canUser() instead.
231
     *
232
     * Check if user has access to a given action on a given value object.
233
     *
234
     * Indicates if the current user is allowed to perform an action given by the function on the given
235
     * objects.
236
     *
237
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If any of the arguments are invalid
238
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException If value of the LimitationValue is unsupported
239
     *
240
     * @param string $module The module, aka controller identifier to check permissions on
241
     * @param string $function The function, aka the controller action to check permissions on
242
     * @param \eZ\Publish\API\Repository\Values\ValueObject $object The object to check if the user has access to
243
     * @param mixed $targets The location, parent or "assignment" value object, or an array of the same
244
     *
245
     * @return bool
246
     */
247
    public function canUser($module, $function, ValueObject $object, $targets = null)
248
    {
249
        return $this->repository->canUser($module, $function, $object, $targets);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::canUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::canUser() instead. Indicates if the current user is allowed to perform an action given by the function on the given
objects. Example: canUser( 'content', 'edit', $content, $location ); This will check edit permission on content given the specific location, if skipped if will check on all locations. Example2: canUser( 'section', 'assign', $content, $section ); Check if user has access to assign $content to $section.

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...
250
    }
251
252
    /**
253
     * Get Content Service.
254
     *
255
     * Get service object to perform operations on Content objects and it's aggregate members.
256
     *
257
     * @return \eZ\Publish\API\Repository\ContentService
258
     */
259
    public function getContentService()
260
    {
261
        if ($this->contentService !== null) {
262
            return $this->contentService;
263
        }
264
265
        $this->contentService = new ContentService($this->repository->getContentService(), $this->signalDispatcher);
266
267
        return $this->contentService;
268
    }
269
270
    /**
271
     * Get Content Language Service.
272
     *
273
     * Get service object to perform operations on Content language objects
274
     *
275
     * @return \eZ\Publish\API\Repository\LanguageService
276
     */
277
    public function getContentLanguageService()
278
    {
279
        if ($this->languageService !== null) {
280
            return $this->languageService;
281
        }
282
283
        $this->languageService = new LanguageService($this->repository->getContentLanguageService(), $this->signalDispatcher);
284
285
        return $this->languageService;
286
    }
287
288
    /**
289
     * Get Content Type Service.
290
     *
291
     * Get service object to perform operations on Content Type objects and it's aggregate members.
292
     * ( Group, Field & FieldCategory )
293
     *
294
     * @return \eZ\Publish\API\Repository\ContentTypeService
295
     */
296
    public function getContentTypeService()
297
    {
298
        if ($this->contentTypeService !== null) {
299
            return $this->contentTypeService;
300
        }
301
302
        $this->contentTypeService = new ContentTypeService($this->repository->getContentTypeService(), $this->signalDispatcher);
303
304
        return $this->contentTypeService;
305
    }
306
307
    /**
308
     * Get Content Location Service.
309
     *
310
     * Get service object to perform operations on Location objects and subtrees
311
     *
312
     * @return \eZ\Publish\API\Repository\LocationService
313
     */
314
    public function getLocationService()
315
    {
316
        if ($this->locationService !== null) {
317
            return $this->locationService;
318
        }
319
320
        $this->locationService = new LocationService($this->repository->getLocationService(), $this->signalDispatcher);
321
322
        return $this->locationService;
323
    }
324
325
    /**
326
     * Get Content Trash service.
327
     *
328
     * Trash service allows to perform operations related to location trash
329
     * (trash/untrash, load/list from trash...)
330
     *
331
     * @return \eZ\Publish\API\Repository\TrashService
332
     */
333
    public function getTrashService()
334
    {
335
        if ($this->trashService !== null) {
336
            return $this->trashService;
337
        }
338
339
        $this->trashService = new TrashService($this->repository->getTrashService(), $this->signalDispatcher);
340
341
        return $this->trashService;
342
    }
343
344
    /**
345
     * Get Content Section Service.
346
     *
347
     * Get Section service that lets you manipulate section objects
348
     *
349
     * @return \eZ\Publish\API\Repository\SectionService
350
     */
351
    public function getSectionService()
352
    {
353
        if ($this->sectionService !== null) {
354
            return $this->sectionService;
355
        }
356
357
        $this->sectionService = new SectionService($this->repository->getSectionService(), $this->signalDispatcher);
358
359
        return $this->sectionService;
360
    }
361
362
    /**
363
     * Get User Service.
364
     *
365
     * Get service object to perform operations on Users and UserGroup
366
     *
367
     * @return \eZ\Publish\API\Repository\UserService
368
     */
369
    public function getUserService()
370
    {
371
        if ($this->userService !== null) {
372
            return $this->userService;
373
        }
374
375
        $this->userService = new UserService($this->repository->getUserService(), $this->signalDispatcher);
376
377
        return $this->userService;
378
    }
379
380
    /**
381
     * Get URLAliasService.
382
     *
383
     * @return \eZ\Publish\API\Repository\URLAliasService
384
     */
385
    public function getURLAliasService()
386
    {
387
        if ($this->urlAliasService !== null) {
388
            return $this->urlAliasService;
389
        }
390
391
        $this->urlAliasService = new URLAliasService($this->repository->getURLAliasService(), $this->signalDispatcher);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \eZ\Publish\Core\Sig...this->signalDispatcher) of type object<eZ\Publish\Core\S...alSlot\URLAliasService> is incompatible with the declared type object<eZ\Publish\Core\R...sitory\URLAliasService> of property $urlAliasService.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
392
393
        return $this->urlAliasService;
394
    }
395
396
    /**
397
     * Get URLWildcardService.
398
     *
399
     * @return \eZ\Publish\API\Repository\URLWildcardService
400
     */
401
    public function getURLWildcardService()
402
    {
403
        if ($this->urlWildcardService !== null) {
404
            return $this->urlWildcardService;
405
        }
406
407
        $this->urlWildcardService = new URLWildcardService($this->repository->getURLWildcardService(), $this->signalDispatcher);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \eZ\Publish\Core\Sig...this->signalDispatcher) of type object<eZ\Publish\Core\S...lot\URLWildcardService> is incompatible with the declared type object<eZ\Publish\Core\R...ory\URLWildcardService> of property $urlWildcardService.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
408
409
        return $this->urlWildcardService;
410
    }
411
412
    /**
413
     * Get ObjectStateService.
414
     *
415
     * @return \eZ\Publish\API\Repository\ObjectStateService
416
     */
417
    public function getObjectStateService()
418
    {
419
        if ($this->objectStateService !== null) {
420
            return $this->objectStateService;
421
        }
422
423
        $this->objectStateService = new ObjectStateService($this->repository->getObjectStateService(), $this->signalDispatcher);
424
425
        return $this->objectStateService;
426
    }
427
428
    /**
429
     * Get RoleService.
430
     *
431
     * @return \eZ\Publish\API\Repository\RoleService
432
     */
433
    public function getRoleService()
434
    {
435
        if ($this->roleService !== null) {
436
            return $this->roleService;
437
        }
438
439
        $this->roleService = new RoleService($this->repository->getRoleService(), $this->signalDispatcher);
440
441
        return $this->roleService;
442
    }
443
444
    /**
445
     * Get SearchService.
446
     *
447
     * @return \eZ\Publish\API\Repository\SearchService
448
     */
449
    public function getSearchService()
450
    {
451
        if ($this->searchService !== null) {
452
            return $this->searchService;
453
        }
454
455
        $this->searchService = new SearchService($this->repository->getSearchService(), $this->signalDispatcher);
456
457
        return $this->searchService;
458
    }
459
460
    /**
461
     * Get FieldTypeService.
462
     *
463
     * @return \eZ\Publish\API\Repository\FieldTypeService
464
     */
465
    public function getFieldTypeService()
466
    {
467
        if ($this->fieldTypeService !== null) {
468
            return $this->fieldTypeService;
469
        }
470
471
        $this->fieldTypeService = new FieldTypeService($this->repository->getFieldTypeService(), $this->signalDispatcher);
472
473
        return $this->fieldTypeService;
474
    }
475
476
    /**
477
     * Get PermissionResolver.
478
     *
479
     * @return \eZ\Publish\API\Repository\PermissionResolver
480
     */
481
    public function getPermissionResolver()
482
    {
483
        return $this->repository->getPermissionResolver();
484
    }
485
486
    /**
487
     * Begin transaction.
488
     *
489
     * Begins an transaction, make sure you'll call commit or rollback when done,
490
     * otherwise work will be lost.
491
     */
492
    public function beginTransaction()
493
    {
494
        $return = $this->repository->beginTransaction();
495
496
        if ($this->signalDispatcher instanceof TransactionHandler) {
497
            $this->signalDispatcher->beginTransaction();
498
        }
499
500
        return $return;
501
    }
502
503
    /**
504
     * Commit transaction.
505
     *
506
     * Commit transaction, or throw exceptions if no transactions has been started.
507
     *
508
     * @throws \RuntimeException If no transaction has been started
509
     */
510
    public function commit()
511
    {
512
        $return = $this->repository->commit();
513
514
        if ($this->signalDispatcher instanceof TransactionHandler) {
515
            $this->signalDispatcher->commit();
516
        }
517
518
        return $return;
519
    }
520
521
    /**
522
     * Rollback transaction.
523
     *
524
     * Rollback transaction, or throw exceptions if no transactions has been started.
525
     *
526
     * @throws \RuntimeException If no transaction has been started
527
     */
528
    public function rollback()
529
    {
530
        if ($this->signalDispatcher instanceof TransactionHandler) {
531
            $this->signalDispatcher->rollback();
532
        }
533
534
        return $this->repository->rollback();
535
    }
536
537
    /**
538
     * Enqueue an event to be triggered at commit or directly if no transaction has started.
539
     *
540
     * @deprecated In 5.3.3, to be removed. Signals are emitted after transaction instead of being required to use this.
541
     *
542
     * @param callable $event
543
     */
544
    public function commitEvent($event)
545
    {
546
        return $this->repository->commitEvent($event);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...pository::commitEvent() has been deprecated with message: In 5.3.3, to be removed. Signals are emitted after transaction instead of being required to use this.

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...
547
    }
548
549
    /**
550
     * Only for internal use.
551
     *
552
     * Creates a \DateTime object for $timestamp in the current time zone
553
     *
554
     * @param int $timestamp
555
     *
556
     * @return \DateTime
557
     */
558
    public function createDateTime($timestamp = null)
559
    {
560
        return $this->repository->createDateTime($timestamp);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface eZ\Publish\API\Repository\Repository as the method createDateTime() does only exist in the following implementations of said interface: eZ\Publish\Core\Repository\Repository, eZ\Publish\Core\SignalSlot\Repository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
561
    }
562
}
563