Completed
Pull Request — master (#32261)
by Matthew
24:00 queued 07:53
created

User::__construct()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 16
nop 8
dl 0
loc 25
rs 9.2088
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * @author Arthur Schiwon <[email protected]>
4
 * @author Bart Visscher <[email protected]>
5
 * @author Björn Schießle <[email protected]>
6
 * @author Jörn Friedrich Dreyer <[email protected]>
7
 * @author Lukas Reschke <[email protected]>
8
 * @author Morris Jobke <[email protected]>
9
 * @author Robin Appelman <[email protected]>
10
 * @author Thomas Müller <[email protected]>
11
 * @author Tom Needham <[email protected]>
12
 * @author Victor Dubiniuk <[email protected]>
13
 * @author Vincent Petry <[email protected]>
14
 *
15
 * @copyright Copyright (c) 2018, ownCloud GmbH
16
 * @license AGPL-3.0
17
 *
18
 * This code is free software: you can redistribute it and/or modify
19
 * it under the terms of the GNU Affero General Public License, version 3,
20
 * as published by the Free Software Foundation.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
 * GNU Affero General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU Affero General Public License, version 3,
28
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
29
 *
30
 */
31
32
namespace OC\User;
33
34
use OC\Files\Cache\Storage;
35
use OC\Hooks\Emitter;
36
use OC_Helper;
37
use OCP\Events\EventEmitterTrait;
38
use OCP\IAvatarManager;
39
use OCP\IImage;
40
use OCP\IURLGenerator;
41
use OCP\IUser;
42
use OCP\IConfig;
43
use OCP\IUserBackend;
44
use OCP\IUserSession;
45
use OCP\User\IChangePasswordBackend;
46
use Symfony\Component\EventDispatcher\EventDispatcher;
47
use Symfony\Component\EventDispatcher\GenericEvent;
48
49
class User implements IUser {
50
	use EventEmitterTrait;
51
	/** @var Account */
52
	private $account;
53
54
	/** @var Emitter|Manager $emitter */
55
	private $emitter;
56
57
	/** @var \OCP\IConfig $config */
58
	private $config;
59
60
	/** @var IAvatarManager */
61
	private $avatarManager;
62
63
	/** @var IURLGenerator */
64
	private $urlGenerator;
65
66
	/** @var EventDispatcher */
67
	private $eventDispatcher;
68
69
	/** @var AccountMapper */
70
	private $mapper;
71
72
	/** @var \OC\Group\Manager  */
73
	private $groupManager;
74
75
	/** @var Session  */
76
	private $userSession;
77
78
	/**
79
	 * User constructor.
80
	 *
81
	 * @param Account $account
82
	 * @param AccountMapper $mapper
83
	 * @param null $emitter
84
	 * @param IConfig|null $config
85
	 * @param null $urlGenerator
86
	 * @param EventDispatcher|null $eventDispatcher
87
	 * @param \OC\Group\Manager|null $groupManager
88
	 * @param Session|null $userSession
89
	 */
90
	public function __construct(Account $account, AccountMapper $mapper, $emitter = null, IConfig $config = null,
91
								$urlGenerator = null, EventDispatcher $eventDispatcher = null,
92
								\OC\Group\Manager $groupManager = null, Session $userSession = null
93
	) {
94
		$this->account = $account;
95
		$this->mapper = $mapper;
96
		$this->emitter = $emitter;
97
		$this->eventDispatcher = $eventDispatcher;
98
		if ($config === null) {
99
			$config = \OC::$server->getConfig();
100
		}
101
		$this->config = $config;
102
		$this->urlGenerator = $urlGenerator;
103
		if ($this->urlGenerator === null) {
104
			$this->urlGenerator = \OC::$server->getURLGenerator();
105
		}
106
		$this->groupManager = $groupManager;
107
		if ($this->groupManager === null) {
108
			$this->groupManager = \OC::$server->getGroupManager();
109
		}
110
		$this->userSession = $userSession;
111
		if ($this->userSession === null) {
112
			$this->userSession = \OC::$server->getUserSession();
113
		}
114
	}
115
116
	/**
117
	 * get the user id
118
	 *
119
	 * @return string
120
	 */
121
	public function getUID() {
122
		return $this->account->getUserId();
123
	}
124
125
	/**
126
	 * get the display name for the user, if no specific display name is set it will fallback to the user id
127
	 *
128
	 * @return string
129
	 */
130
	public function getDisplayName() {
131
		$displayName = $this->account->getDisplayName();
132
		if (empty($displayName)) {
133
			$displayName = $this->getUID();
134
		}
135
		return $displayName;
136
	}
137
138
	/**
139
	 * set the displayname for the user
140
	 *
141
	 * @param string $displayName
142
	 * @return bool
143
	 */
144
	public function setDisplayName($displayName) {
145
		if (!$this->canChangeDisplayName()) {
146
			return false;
147
		}
148
		$displayName = \trim($displayName);
149
		if ($displayName === $this->account->getDisplayName()) {
150
			return false;
151
		}
152
		$this->account->setDisplayName($displayName);
153
		$this->mapper->update($this->account);
154
155
		$backend = $this->account->getBackendInstance();
156
		if ($backend->implementsActions(Backend::SET_DISPLAYNAME)) {
157
			$backend->setDisplayName($this->account->getUserId(), $displayName);
158
		}
159
160
		$this->triggerChange('displayName', $displayName);
161
162
		return true;
163
	}
164
165
	/**
166
	 * set the email address of the user
167
	 *
168
	 * @param string|null $mailAddress
169
	 * @return void
170
	 * @since 9.0.0
171
	 */
172
	public function setEMailAddress($mailAddress) {
173
		$mailAddress = \trim($mailAddress);
174
		if ($mailAddress === $this->account->getEmail()) {
175
			return;
176
		}
177
		$this->account->setEmail($mailAddress);
178
		$this->mapper->update($this->account);
179
		$this->triggerChange('eMailAddress', $mailAddress);
180
	}
181
182
	/**
183
	 * returns the timestamp of the user's last login or 0 if the user did never
184
	 * login
185
	 *
186
	 * @return int
187
	 */
188
	public function getLastLogin() {
189
		return (int)$this->account->getLastLogin();
190
	}
191
192
	/**
193
	 * updates the timestamp of the most recent login of this user
194
	 */
195
	public function updateLastLoginTimestamp() {
196
		$firstTimeLogin = ($this->getLastLogin() === 0);
197
		$this->account->setLastLogin(\time());
198
		$this->mapper->update($this->account);
199
		return $firstTimeLogin;
200
	}
201
202
	/**
203
	 * Delete the user
204
	 *
205
	 * @return bool
206
	 */
207
	public function delete() {
208
		if ($this->emitter) {
209
			$this->emitter->emit('\OC\User', 'preDelete', [$this]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Hooks\Emitter as the method emit() does only exist in the following implementations of said interface: OCA\Files_Sharing\Scanner, OC\App\CodeChecker\CodeChecker, OC\App\CodeChecker\InfoChecker, OC\Files\Cache\Scanner, OC\Files\Config\MountProviderCollection, OC\Files\Node\LazyRoot, OC\Files\Node\Root, OC\Files\ObjectStore\NoopScanner, OC\Files\Utils\Scanner, OC\Group\Manager, OC\Hooks\BasicEmitter, OC\Hooks\ForwardingEmitter, OC\Hooks\LegacyEmitter, OC\Hooks\PublicEmitter, OC\SubAdmin, OC\Updater, OC\User\Manager.

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...
210
		}
211
		// get the home now because it won't return it after user deletion
212
		$homePath = $this->getHome();
213
		$this->mapper->delete($this->account);
214
		$bi = $this->account->getBackendInstance();
215
		if ($bi !== null) {
216
			$bi->deleteUser($this->account->getUserId());
217
		}
218
219
		// FIXME: Feels like an hack - suggestions?
220
221
		// We have to delete the user from all groups
222
		foreach (\OC::$server->getGroupManager()->getUserGroups($this) as $group) {
223
			$group->removeUser($this);
224
		}
225
		// Delete the user's keys in preferences
226
		\OC::$server->getConfig()->deleteAllUserValues($this->getUID());
227
228
		// Delete all mount points for user
229
		\OC::$server->getUserStoragesService()->deleteAllMountsForUser($this);
230
		//Delete external storage or remove user from applicableUsers list
231
		\OC::$server->getGlobalStoragesService()->deleteAllForUser($this);
232
233
		// Delete user files in /data/
234
		if ($homePath !== false) {
235
			// FIXME: this operates directly on FS, should use View instead...
236
			// also this is not testable/mockable...
237
			\OC_Helper::rmdirr($homePath);
238
		}
239
240
		// Delete the users entry in the storage table
241
		Storage::remove('home::' . $this->getUID());
242
		Storage::remove('object::user:' . $this->getUID());
243
244
		\OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->getUID());
245
		\OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
246
247
		if ($this->emitter) {
248
			$this->emitter->emit('\OC\User', 'postDelete', [$this]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Hooks\Emitter as the method emit() does only exist in the following implementations of said interface: OCA\Files_Sharing\Scanner, OC\App\CodeChecker\CodeChecker, OC\App\CodeChecker\InfoChecker, OC\Files\Cache\Scanner, OC\Files\Config\MountProviderCollection, OC\Files\Node\LazyRoot, OC\Files\Node\Root, OC\Files\ObjectStore\NoopScanner, OC\Files\Utils\Scanner, OC\Group\Manager, OC\Hooks\BasicEmitter, OC\Hooks\ForwardingEmitter, OC\Hooks\LegacyEmitter, OC\Hooks\PublicEmitter, OC\SubAdmin, OC\Updater, OC\User\Manager.

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...
249
		}
250
		return true;
251
	}
252
253
	/**
254
	 * Set the user's password
255
	 *
256
	 * @param string $password
257
	 * @param string $recoveryPassword for the encryption app to reset encryption keys
258
	 * @return bool
259
	 * @throws ArgumentNotSetException
260
	 */
261
	public function setPassword($password, $recoveryPassword = null) {
262
		if (empty($password)) {
263
			throw new ArgumentNotSetException('Password cannot be empty');
264
		}
265
266
		return $this->emittingCall(function () use (&$password, &$recoveryPassword) {
267
			if ($this->emitter) {
268
				$this->emitter->emit('\OC\User', 'preSetPassword', [$this, $password, $recoveryPassword]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Hooks\Emitter as the method emit() does only exist in the following implementations of said interface: OCA\Files_Sharing\Scanner, OC\App\CodeChecker\CodeChecker, OC\App\CodeChecker\InfoChecker, OC\Files\Cache\Scanner, OC\Files\Config\MountProviderCollection, OC\Files\Node\LazyRoot, OC\Files\Node\Root, OC\Files\ObjectStore\NoopScanner, OC\Files\Utils\Scanner, OC\Group\Manager, OC\Hooks\BasicEmitter, OC\Hooks\ForwardingEmitter, OC\Hooks\LegacyEmitter, OC\Hooks\PublicEmitter, OC\SubAdmin, OC\Updater, OC\User\Manager.

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...
269
				\OC::$server->getEventDispatcher()->dispatch(
270
					'OCP\User::validatePassword',
271
					new GenericEvent(null, ['uid'=> $this->getUID(), 'password' => $password])
272
				);
273
			}
274
			if ($this->canChangePassword()) {
275
				/** @var IChangePasswordBackend $backend */
276
				$backend = $this->account->getBackendInstance();
277
				$result = $backend->setPassword($this->getUID(), $password);
278
				if ($result) {
279
					if ($this->emitter) {
280
						$this->emitter->emit('\OC\User', 'postSetPassword', [$this, $password, $recoveryPassword]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Hooks\Emitter as the method emit() does only exist in the following implementations of said interface: OCA\Files_Sharing\Scanner, OC\App\CodeChecker\CodeChecker, OC\App\CodeChecker\InfoChecker, OC\Files\Cache\Scanner, OC\Files\Config\MountProviderCollection, OC\Files\Node\LazyRoot, OC\Files\Node\Root, OC\Files\ObjectStore\NoopScanner, OC\Files\Utils\Scanner, OC\Group\Manager, OC\Hooks\BasicEmitter, OC\Hooks\ForwardingEmitter, OC\Hooks\LegacyEmitter, OC\Hooks\PublicEmitter, OC\SubAdmin, OC\Updater, OC\User\Manager.

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...
281
					}
282
					$this->config->deleteUserValue($this->getUID(), 'owncloud', 'lostpassword');
283
				}
284
				return !($result === false);
285
			} else {
286
				return false;
287
			}
288
		}, [
289
			'before' => ['user' => $this, 'password' => $password, 'recoveryPassword' => $recoveryPassword],
290
			'after' => ['user' => $this, 'password' => $password, 'recoveryPassword' => $recoveryPassword]
291
		], 'user', 'setpassword');
292
	}
293
294
	/**
295
	 * get the users home folder to mount
296
	 *
297
	 * @return string
298
	 */
299
	public function getHome() {
300
		return $this->account->getHome();
301
	}
302
303
	/**
304
	 * Get the name of the backend class the user is connected with
305
	 *
306
	 * @return string
307
	 */
308
	public function getBackendClassName() {
309
		$b = $this->account->getBackendInstance();
310
		if ($b instanceof IUserBackend) {
311
			return $b->getBackendName();
312
		}
313
		return $this->account->getBackend();
314
	}
315
316
	/**
317
	 * check if the backend allows the user to change his avatar on Personal page
318
	 *
319
	 * @return bool
320
	 */
321
	public function canChangeAvatar() {
322
		$backend = $this->account->getBackendInstance();
323
		if ($backend === null) {
324
			return false;
325
		}
326
		if ($backend->implementsActions(Backend::PROVIDE_AVATAR)) {
327
			return $backend->canChangeAvatar($this->getUID());
328
		}
329
		return true;
330
	}
331
332
	/**
333
	 * check if the backend supports changing passwords
334
	 *
335
	 * @return bool
336
	 */
337
	public function canChangePassword() {
338
		$backend = $this->account->getBackendInstance();
339
		if ($backend === null) {
340
			return false;
341
		}
342
		return $backend instanceof IChangePasswordBackend || $backend->implementsActions(Backend::SET_PASSWORD);
343
	}
344
345
	/**
346
	 * check if the backend supports changing display names
347
	 *
348
	 * @return bool
349
	 */
350
	public function canChangeDisplayName() {
351
		// Only Admin and SubAdmins are allowed to change display name
352
		if ($this->userSession instanceof IUserSession) {
353
			$user = $this->userSession->getUser();
354
			if (
355
				($this->config->getSystemValue('allow_user_to_change_display_name') === false) &&
356
				(($user !== null) && (!$this->groupManager->isAdmin($user->getUID()))) &&
357
				(($user !== null) && (!$this->groupManager->getSubAdmin()->isSubAdmin($user)))
358
			) {
359
				return false;
360
			}
361
		}
362
		$backend = $this->account->getBackendInstance();
363
		if ($backend === null) {
364
			return false;
365
		}
366
		return $backend->implementsActions(Backend::SET_DISPLAYNAME);
367
	}
368
369
	/**
370
	 * check if the user is enabled
371
	 *
372
	 * @return bool
373
	 */
374
	public function isEnabled() {
375
		return $this->account->getState() === Account::STATE_ENABLED;
376
	}
377
378
	/**
379
	 * set the enabled status for the user
380
	 *
381
	 * @param bool $enabled
382
	 */
383
	public function setEnabled($enabled) {
384
		if ($enabled === true) {
385
			$this->account->setState(Account::STATE_ENABLED);
386
		} else {
387
			$this->account->setState(Account::STATE_DISABLED);
388
		}
389
		$this->mapper->update($this->account);
390
391
		if ($this->eventDispatcher) {
392
			$this->eventDispatcher->dispatch(self::class . '::postSetEnabled', new GenericEvent($this));
393
		}
394
	}
395
396
	/**
397
	 * get the users email address
398
	 *
399
	 * @return string|null
400
	 * @since 9.0.0
401
	 */
402
	public function getEMailAddress() {
403
		return $this->account->getEmail();
404
	}
405
406
	/**
407
	 * get the users' quota
408
	 *
409
	 * @return string
410
	 * @since 9.0.0
411
	 */
412
	public function getQuota() {
413
		$quota = $this->account->getQuota();
414
		if ($quota === null) {
415
			return 'default';
416
		}
417
		return $quota;
418
	}
419
420
	/**
421
	 * set the users' quota
422
	 *
423
	 * @param string $quota
424
	 * @return void
425
	 * @since 9.0.0
426
	 */
427
	public function setQuota($quota) {
428
		if ($quota !== 'none' and $quota !== 'default') {
429
			$quota = OC_Helper::computerFileSize($quota);
430
			$quota = OC_Helper::humanFileSize($quota);
0 ignored issues
show
Documentation introduced by
$quota is of type false|double, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
431
		}
432
		$this->account->setQuota($quota);
433
		$this->mapper->update($this->account);
434
		$this->triggerChange('quota', $quota);
435
	}
436
437
	/**
438
	 * get the avatar image if it exists
439
	 *
440
	 * @param int $size
441
	 * @return IImage|null
442
	 * @since 9.0.0
443
	 */
444
	public function getAvatarImage($size) {
445
		// delay the initialization
446
		if ($this->avatarManager === null) {
447
			$this->avatarManager = \OC::$server->getAvatarManager();
448
		}
449
450
		$avatar = $this->avatarManager->getAvatar($this->getUID());
451
		$image = $avatar->get($size);
0 ignored issues
show
Bug Compatibility introduced by
The expression $avatar->get($size); of type boolean|OCP\IImage adds the type boolean to the return on line 453 which is incompatible with the return type declared by the interface OCP\IUser::getAvatarImage of type OCP\IImage|null.
Loading history...
452
		if ($image) {
453
			return $image;
454
		}
455
456
		return null;
457
	}
458
459
	/**
460
	 * get the federation cloud id
461
	 *
462
	 * @return string
463
	 * @since 9.0.0
464
	 */
465
	public function getCloudId() {
466
		$uid = $this->getUID();
467
		$server = $this->urlGenerator->getAbsoluteURL('/');
468
		return $uid . '@' . \rtrim($this->removeProtocolFromUrl($server), '/');
469
	}
470
471
	/**
472
	 * @param string $url
473
	 * @return string
474
	 */
475 View Code Duplication
	private function removeProtocolFromUrl($url) {
476
		if (\strpos($url, 'https://') === 0) {
477
			return \substr($url, \strlen('https://'));
478
		} elseif (\strpos($url, 'http://') === 0) {
479
			return \substr($url, \strlen('http://'));
480
		}
481
482
		return $url;
483
	}
484
485
	public function triggerChange($feature, $value = null) {
486
		if ($this->emitter && \in_array($feature, $this->account->getUpdatedFields())) {
487
			$this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Hooks\Emitter as the method emit() does only exist in the following implementations of said interface: OCA\Files_Sharing\Scanner, OC\App\CodeChecker\CodeChecker, OC\App\CodeChecker\InfoChecker, OC\Files\Cache\Scanner, OC\Files\Config\MountProviderCollection, OC\Files\Node\LazyRoot, OC\Files\Node\Root, OC\Files\ObjectStore\NoopScanner, OC\Files\Utils\Scanner, OC\Group\Manager, OC\Hooks\BasicEmitter, OC\Hooks\ForwardingEmitter, OC\Hooks\LegacyEmitter, OC\Hooks\PublicEmitter, OC\SubAdmin, OC\Updater, OC\User\Manager.

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...
488
		}
489
	}
490
491
	/**
492
	 * @return string[]
493
	 * @since 10.0.1
494
	 */
495
	public function getSearchTerms() {
496
		$terms = [];
497
		foreach ($this->mapper->findByAccountId($this->account->getId()) as $term) {
498
			$terms[] = $term->getTerm();
499
		}
500
		return $terms;
501
	}
502
503
	/**
504
	 * @param string[] $terms
505
	 * @since 10.0.1
506
	 */
507
	public function setSearchTerms(array $terms) {
508
		// Check length of terms, cut if too long
509
		$terms = \array_map(function ($term) {
510
			return \substr($term, 0, 191);
511
		}, $terms);
512
		$this->mapper->setTermsForAccount($this->account->getId(), $terms);
513
	}
514
}
515