Completed
Push — master ( ad0d0b...75c437 )
by Morris
26:55 queued 13:45
created

User::getDisplayName()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 12
nc 7
nop 0
dl 0
loc 19
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bart Visscher <[email protected]>
7
 * @author Björn Schießle <[email protected]>
8
 * @author Jörn Friedrich Dreyer <[email protected]>
9
 * @author Lukas Reschke <[email protected]>
10
 * @author Morris Jobke <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Roeland Jago Douma <[email protected]>
13
 * @author Thomas Müller <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
31
namespace OC\User;
32
33
use OC\Accounts\AccountManager;
34
use OC\Files\Cache\Storage;
35
use OC\Hooks\Emitter;
36
use OC_Helper;
37
use OCP\IAvatarManager;
38
use OCP\IImage;
39
use OCP\IURLGenerator;
40
use OCP\IUser;
41
use OCP\IConfig;
42
use OCP\UserInterface;
43
use \OCP\IUserBackend;
44
45
class User implements IUser {
46
	/** @var string $uid */
47
	private $uid;
48
49
	/** @var string $displayName */
50
	private $displayName;
51
52
	/** @var UserInterface $backend */
53
	private $backend;
54
55
	/** @var bool $enabled */
56
	private $enabled;
57
58
	/** @var Emitter|Manager $emitter */
59
	private $emitter;
60
61
	/** @var string $home */
62
	private $home;
63
64
	/** @var int $lastLogin */
65
	private $lastLogin;
66
67
	/** @var \OCP\IConfig $config */
68
	private $config;
69
70
	/** @var IAvatarManager */
71
	private $avatarManager;
72
73
	/** @var IURLGenerator */
74
	private $urlGenerator;
75
76
	/**
77
	 * @param string $uid
78
	 * @param UserInterface $backend
79
	 * @param \OC\Hooks\Emitter $emitter
80
	 * @param IConfig|null $config
81
	 * @param IURLGenerator $urlGenerator
82
	 */
83
	public function __construct($uid, $backend, $emitter = null, IConfig $config = null, $urlGenerator = null) {
84
		$this->uid = $uid;
85
		$this->backend = $backend;
86
		$this->emitter = $emitter;
87
		if(is_null($config)) {
88
			$config = \OC::$server->getConfig();
89
		}
90
		$this->config = $config;
91
		$this->urlGenerator = $urlGenerator;
92
		$enabled = $this->config->getUserValue($uid, 'core', 'enabled', 'true');
93
		$this->enabled = ($enabled === 'true');
94
		$this->lastLogin = $this->config->getUserValue($uid, 'login', 'lastLogin', 0);
0 ignored issues
show
Documentation Bug introduced by
The property $lastLogin was declared of type integer, but $this->config->getUserVa...login', 'lastLogin', 0) is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
95
		if (is_null($this->urlGenerator)) {
96
			$this->urlGenerator = \OC::$server->getURLGenerator();
97
		}
98
	}
99
100
	/**
101
	 * get the user id
102
	 *
103
	 * @return string
104
	 */
105
	public function getUID() {
106
		return $this->uid;
107
	}
108
109
	/**
110
	 * get the display name for the user, if no specific display name is set it will fallback to the user id
111
	 *
112
	 * @return string
113
	 */
114
	public function getDisplayName() {
115
		if (!isset($this->displayName)) {
116
			$displayName = '';
117
			if ($this->backend and $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) {
118
				// get display name and strip whitespace from the beginning and end of it
119
				$backendDisplayName = $this->backend->getDisplayName($this->uid);
120
				if (is_string($backendDisplayName)) {
121
					$displayName = trim($backendDisplayName);
122
				}
123
			}
124
125
			if (!empty($displayName)) {
126
				$this->displayName = $displayName;
127
			} else {
128
				$this->displayName = $this->uid;
129
			}
130
		}
131
		return $this->displayName;
132
	}
133
134
	/**
135
	 * set the displayname for the user
136
	 *
137
	 * @param string $displayName
138
	 * @return bool
139
	 */
140
	public function setDisplayName($displayName) {
141
		$displayName = trim($displayName);
142
		if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName)) {
143
			$result = $this->backend->setDisplayName($this->uid, $displayName);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OCP\UserInterface as the method setDisplayName() does only exist in the following implementations of said interface: OCA\Testing\AlternativeHomeUserBackend, OC\User\Database.

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...
144
			if ($result) {
145
				$this->displayName = $displayName;
146
				$this->triggerChange('displayName', $displayName);
147
			}
148
			return $result !== false;
149
		} else {
150
			return false;
151
		}
152
	}
153
154
	/**
155
	 * set the email address of the user
156
	 *
157
	 * @param string|null $mailAddress
158
	 * @return void
159
	 * @since 9.0.0
160
	 */
161
	public function setEMailAddress($mailAddress) {
162
		$oldMailAddress = $this->getEMailAddress();
163
		if($mailAddress === '') {
164
			$this->config->deleteUserValue($this->uid, 'settings', 'email');
165
		} else {
166
			$this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
167
		}
168
		$this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress);
169
	}
170
171
	/**
172
	 * returns the timestamp of the user's last login or 0 if the user did never
173
	 * login
174
	 *
175
	 * @return int
176
	 */
177
	public function getLastLogin() {
178
		return $this->lastLogin;
179
	}
180
181
	/**
182
	 * updates the timestamp of the most recent login of this user
183
	 */
184
	public function updateLastLoginTimestamp() {
185
		$firstTimeLogin = ($this->lastLogin === 0);
186
		$this->lastLogin = time();
187
		$this->config->setUserValue(
188
			$this->uid, 'login', 'lastLogin', $this->lastLogin);
189
190
		return $firstTimeLogin;
191
	}
192
193
	/**
194
	 * Delete the user
195
	 *
196
	 * @return bool
197
	 */
198
	public function delete() {
199
		if ($this->emitter) {
200
			$this->emitter->emit('\OC\User', 'preDelete', array($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\External\Scanner, 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...
201
		}
202
		// get the home now because it won't return it after user deletion
203
		$homePath = $this->getHome();
204
		$result = $this->backend->deleteUser($this->uid);
205
		if ($result) {
206
207
			// FIXME: Feels like an hack - suggestions?
208
209
			$groupManager = \OC::$server->getGroupManager();
210
			// We have to delete the user from all groups
211
			foreach ($groupManager->getUserGroupIds($this) as $groupId) {
212
				$group = $groupManager->get($groupId);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $group is correct as $groupManager->get($groupId) (which targets OC\Group\Manager::get()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
213
				if ($group) {
214
					\OC_Hook::emit("OC_Group", "pre_removeFromGroup", ["run" => true, "uid" => $this->uid, "gid" => $groupId]);
215
					$group->removeUser($this);
216
					\OC_Hook::emit("OC_User", "post_removeFromGroup", ["uid" => $this->uid, "gid" => $groupId]);
217
				}
218
			}
219
			// Delete the user's keys in preferences
220
			\OC::$server->getConfig()->deleteAllUserValues($this->uid);
221
222
			// Delete user files in /data/
223
			if ($homePath !== false) {
224
				// FIXME: this operates directly on FS, should use View instead...
225
				// also this is not testable/mockable...
226
				\OC_Helper::rmdirr($homePath);
227
			}
228
229
			// Delete the users entry in the storage table
230
			Storage::remove('home::' . $this->uid);
231
232
			\OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
233
			\OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
234
235
			$notification = \OC::$server->getNotificationManager()->createNotification();
236
			$notification->setUser($this->uid);
237
			\OC::$server->getNotificationManager()->markProcessed($notification);
238
239
			/** @var AccountManager $accountManager */
240
			$accountManager = \OC::$server->query(AccountManager::class);
241
			$accountManager->deleteUser($this);
242
243
			if ($this->emitter) {
244
				$this->emitter->emit('\OC\User', 'postDelete', array($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\External\Scanner, 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...
245
			}
246
		}
247
		return !($result === false);
248
	}
249
250
	/**
251
	 * Set the password of the user
252
	 *
253
	 * @param string $password
254
	 * @param string $recoveryPassword for the encryption app to reset encryption keys
255
	 * @return bool
256
	 */
257
	public function setPassword($password, $recoveryPassword = null) {
258
		if ($this->emitter) {
259
			$this->emitter->emit('\OC\User', 'preSetPassword', array($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\External\Scanner, 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...
260
		}
261
		if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
262
			$result = $this->backend->setPassword($this->uid, $password);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OCP\UserInterface as the method setPassword() does only exist in the following implementations of said interface: OCA\Testing\AlternativeHomeUserBackend, OCA\User_LDAP\User_LDAP, OCA\User_LDAP\User_Proxy, OC\User\Database.

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...
263
			if ($this->emitter) {
264
				$this->emitter->emit('\OC\User', 'postSetPassword', array($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\External\Scanner, 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...
265
			}
266
			return !($result === false);
267
		} else {
268
			return false;
269
		}
270
	}
271
272
	/**
273
	 * get the users home folder to mount
274
	 *
275
	 * @return string
276
	 */
277
	public function getHome() {
278
		if (!$this->home) {
279
			if ($this->backend->implementsActions(Backend::GET_HOME) and $home = $this->backend->getHome($this->uid)) {
280
				$this->home = $home;
281
			} elseif ($this->config) {
282
				$this->home = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
283
			} else {
284
				$this->home = \OC::$SERVERROOT . '/data/' . $this->uid;
285
			}
286
		}
287
		return $this->home;
288
	}
289
290
	/**
291
	 * Get the name of the backend class the user is connected with
292
	 *
293
	 * @return string
294
	 */
295
	public function getBackendClassName() {
296
		if($this->backend instanceof IUserBackend) {
297
			return $this->backend->getBackendName();
298
		}
299
		return get_class($this->backend);
300
	}
301
302
	/**
303
	 * check if the backend allows the user to change his avatar on Personal page
304
	 *
305
	 * @return bool
306
	 */
307
	public function canChangeAvatar() {
308
		if ($this->backend->implementsActions(Backend::PROVIDE_AVATAR)) {
309
			return $this->backend->canChangeAvatar($this->uid);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OCP\UserInterface as the method canChangeAvatar() does only exist in the following implementations of said interface: OCA\User_LDAP\User_LDAP, OCA\User_LDAP\User_Proxy.

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...
310
		}
311
		return true;
312
	}
313
314
	/**
315
	 * check if the backend supports changing passwords
316
	 *
317
	 * @return bool
318
	 */
319
	public function canChangePassword() {
320
		return $this->backend->implementsActions(Backend::SET_PASSWORD);
321
	}
322
323
	/**
324
	 * check if the backend supports changing display names
325
	 *
326
	 * @return bool
327
	 */
328
	public function canChangeDisplayName() {
329
		if ($this->config->getSystemValue('allow_user_to_change_display_name') === false) {
330
			return false;
331
		}
332
		return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
333
	}
334
335
	/**
336
	 * check if the user is enabled
337
	 *
338
	 * @return bool
339
	 */
340
	public function isEnabled() {
341
		return $this->enabled;
342
	}
343
344
	/**
345
	 * set the enabled status for the user
346
	 *
347
	 * @param bool $enabled
348
	 */
349
	public function setEnabled($enabled) {
350
		$oldStatus = $this->isEnabled();
351
		$this->enabled = $enabled;
352
		$enabled = ($enabled) ? 'true' : 'false';
353
		if ($oldStatus !== $this->enabled) {
354
			$this->triggerChange('enabled', $enabled);
355
			$this->config->setUserValue($this->uid, 'core', 'enabled', $enabled);
356
		}
357
	}
358
359
	/**
360
	 * get the users email address
361
	 *
362
	 * @return string|null
363
	 * @since 9.0.0
364
	 */
365
	public function getEMailAddress() {
366
		return $this->config->getUserValue($this->uid, 'settings', 'email', null);
367
	}
368
369
	/**
370
	 * get the users' quota
371
	 *
372
	 * @return string
373
	 * @since 9.0.0
374
	 */
375
	public function getQuota() {
376
		$quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
377
		if($quota === 'default') {
378
			$quota = $this->config->getAppValue('files', 'default_quota', 'none');
379
		}
380
		return $quota;
381
	}
382
383
	/**
384
	 * set the users' quota
385
	 *
386
	 * @param string $quota
387
	 * @return void
388
	 * @since 9.0.0
389
	 */
390
	public function setQuota($quota) {
391 View Code Duplication
		if($quota !== 'none' and $quota !== 'default') {
392
			$quota = OC_Helper::computerFileSize($quota);
393
			$quota = OC_Helper::humanFileSize($quota);
0 ignored issues
show
Documentation introduced by
$quota is of type double|false, 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...
394
		}
395
		$this->config->setUserValue($this->uid, 'files', 'quota', $quota);
396
		$this->triggerChange('quota', $quota);
397
	}
398
399
	/**
400
	 * get the avatar image if it exists
401
	 *
402
	 * @param int $size
403
	 * @return IImage|null
404
	 * @since 9.0.0
405
	 */
406
	public function getAvatarImage($size) {
407
		// delay the initialization
408
		if (is_null($this->avatarManager)) {
409
			$this->avatarManager = \OC::$server->getAvatarManager();
410
		}
411
412
		$avatar = $this->avatarManager->getAvatar($this->uid);
413
		$image = $avatar->get(-1);
0 ignored issues
show
Bug Compatibility introduced by
The expression $avatar->get(-1); of type boolean|OCP\IImage adds the type boolean to the return on line 415 which is incompatible with the return type declared by the interface OCP\IUser::getAvatarImage of type OCP\IImage|null.
Loading history...
414
		if ($image) {
415
			return $image;
416
		}
417
418
		return null;
419
	}
420
421
	/**
422
	 * get the federation cloud id
423
	 *
424
	 * @return string
425
	 * @since 9.0.0
426
	 */
427
	public function getCloudId() {
428
		$uid = $this->getUID();
429
		$server = $this->urlGenerator->getAbsoluteURL('/');
430
		$server =  rtrim( $this->removeProtocolFromUrl($server), '/');
431
		return \OC::$server->getCloudIdManager()->getCloudId($uid, $server)->getId();
432
	}
433
434
	/**
435
	 * @param string $url
436
	 * @return string
437
	 */
438 View Code Duplication
	private function removeProtocolFromUrl($url) {
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...
439
		if (strpos($url, 'https://') === 0) {
440
			return substr($url, strlen('https://'));
441
		} else if (strpos($url, 'http://') === 0) {
442
			return substr($url, strlen('http://'));
443
		}
444
445
		return $url;
446
	}
447
448
	public function triggerChange($feature, $value = null, $oldValue = null) {
449
		if ($this->emitter) {
450
			$this->emitter->emit('\OC\User', 'changeUser', array($this, $feature, $value, $oldValue));
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\External\Scanner, 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...
451
		}
452
	}
453
}
454