Completed
Push — master ( c38f87...350aa8 )
by Lukas
27s
created

User::getHome()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 4
nop 0
dl 0
loc 12
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\Files\Cache\Storage;
34
use OC\Hooks\Emitter;
35
use OC_Helper;
36
use OCP\IAvatarManager;
37
use OCP\IImage;
38
use OCP\IURLGenerator;
39
use OCP\IUser;
40
use OCP\IConfig;
41
use OCP\UserInterface;
42
use \OCP\IUserBackend;
43
44
class User implements IUser {
45
	/** @var string $uid */
46
	private $uid;
47
48
	/** @var string $displayName */
49
	private $displayName;
50
51
	/** @var UserInterface $backend */
52
	private $backend;
53
54
	/** @var bool $enabled */
55
	private $enabled;
56
57
	/** @var Emitter|Manager $emitter */
58
	private $emitter;
59
60
	/** @var string $home */
61
	private $home;
62
63
	/** @var int $lastLogin */
64
	private $lastLogin;
65
66
	/** @var \OCP\IConfig $config */
67
	private $config;
68
69
	/** @var IAvatarManager */
70
	private $avatarManager;
71
72
	/** @var IURLGenerator */
73
	private $urlGenerator;
74
75
	/**
76
	 * @param string $uid
77
	 * @param UserInterface $backend
78
	 * @param \OC\Hooks\Emitter $emitter
79
	 * @param IConfig|null $config
80
	 * @param IURLGenerator $urlGenerator
81
	 */
82
	public function __construct($uid, $backend, $emitter = null, IConfig $config = null, $urlGenerator = null) {
83
		$this->uid = $uid;
84
		$this->backend = $backend;
85
		$this->emitter = $emitter;
86
		if(is_null($config)) {
87
			$config = \OC::$server->getConfig();
88
		}
89
		$this->config = $config;
90
		$this->urlGenerator = $urlGenerator;
91
		$enabled = $this->config->getUserValue($uid, 'core', 'enabled', 'true');
92
		$this->enabled = ($enabled === 'true');
93
		$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...
94
		if (is_null($this->urlGenerator)) {
95
			$this->urlGenerator = \OC::$server->getURLGenerator();
96
		}
97
	}
98
99
	/**
100
	 * get the user id
101
	 *
102
	 * @return string
103
	 */
104
	public function getUID() {
105
		return $this->uid;
106
	}
107
108
	/**
109
	 * get the display name for the user, if no specific display name is set it will fallback to the user id
110
	 *
111
	 * @return string
112
	 */
113
	public function getDisplayName() {
114
		if (!isset($this->displayName)) {
115
			$displayName = '';
116
			if ($this->backend and $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) {
117
				// get display name and strip whitespace from the beginning and end of it
118
				$backendDisplayName = $this->backend->getDisplayName($this->uid);
119
				if (is_string($backendDisplayName)) {
120
					$displayName = trim($backendDisplayName);
121
				}
122
			}
123
124
			if (!empty($displayName)) {
125
				$this->displayName = $displayName;
126
			} else {
127
				$this->displayName = $this->uid;
128
			}
129
		}
130
		return $this->displayName;
131
	}
132
133
	/**
134
	 * set the displayname for the user
135
	 *
136
	 * @param string $displayName
137
	 * @return bool
138
	 */
139
	public function setDisplayName($displayName) {
140
		$displayName = trim($displayName);
141
		if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName)) {
142
			$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...
143
			if ($result) {
144
				$this->displayName = $displayName;
145
				$this->triggerChange('displayName', $displayName);
146
			}
147
			return $result !== false;
148
		} else {
149
			return false;
150
		}
151
	}
152
153
	/**
154
	 * set the email address of the user
155
	 *
156
	 * @param string|null $mailAddress
157
	 * @return void
158
	 * @since 9.0.0
159
	 */
160
	public function setEMailAddress($mailAddress) {
161
		if($mailAddress === '') {
162
			$this->config->deleteUserValue($this->uid, 'settings', 'email');
163
		} else {
164
			$this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
165
		}
166
		$this->triggerChange('eMailAddress', $mailAddress);
167
	}
168
169
	/**
170
	 * returns the timestamp of the user's last login or 0 if the user did never
171
	 * login
172
	 *
173
	 * @return int
174
	 */
175
	public function getLastLogin() {
176
		return $this->lastLogin;
177
	}
178
179
	/**
180
	 * updates the timestamp of the most recent login of this user
181
	 */
182
	public function updateLastLoginTimestamp() {
183
		$firstTimeLogin = ($this->lastLogin === 0);
184
		$this->lastLogin = time();
185
		$this->config->setUserValue(
186
			$this->uid, 'login', 'lastLogin', $this->lastLogin);
187
188
		return $firstTimeLogin;
189
	}
190
191
	/**
192
	 * Delete the user
193
	 *
194
	 * @return bool
195
	 */
196
	public function delete() {
197
		if ($this->emitter) {
198
			$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...
199
		}
200
		// get the home now because it won't return it after user deletion
201
		$homePath = $this->getHome();
202
		$result = $this->backend->deleteUser($this->uid);
203
		if ($result) {
204
205
			// FIXME: Feels like an hack - suggestions?
206
207
			$groupManager = \OC::$server->getGroupManager();
208
			// We have to delete the user from all groups
209
			foreach ($groupManager->getUserGroupIds($this) as $groupId) {
210
				$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...
211
				if ($group) {
212
					\OC_Hook::emit("OC_Group", "pre_removeFromGroup", ["run" => true, "uid" => $this->uid, "gid" => $groupId]);
213
					$group->removeUser($this);
214
					\OC_Hook::emit("OC_User", "post_removeFromGroup", ["uid" => $this->uid, "gid" => $groupId]);
215
				}
216
			}
217
			// Delete the user's keys in preferences
218
			\OC::$server->getConfig()->deleteAllUserValues($this->uid);
219
220
			// Delete user files in /data/
221
			if ($homePath !== false) {
222
				// FIXME: this operates directly on FS, should use View instead...
223
				// also this is not testable/mockable...
224
				\OC_Helper::rmdirr($homePath);
225
			}
226
227
			// Delete the users entry in the storage table
228
			Storage::remove('home::' . $this->uid);
229
230
			\OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
231
			\OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
232
233
			$notification = \OC::$server->getNotificationManager()->createNotification();
234
			$notification->setUser($this->uid);
235
			\OC::$server->getNotificationManager()->markProcessed($notification);
236
237
			if ($this->emitter) {
238
				$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...
239
			}
240
		}
241
		return !($result === false);
242
	}
243
244
	/**
245
	 * Set the password of the user
246
	 *
247
	 * @param string $password
248
	 * @param string $recoveryPassword for the encryption app to reset encryption keys
249
	 * @return bool
250
	 */
251
	public function setPassword($password, $recoveryPassword = null) {
252
		if ($this->emitter) {
253
			$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...
254
		}
255
		if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
256
			$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...
257
			if ($this->emitter) {
258
				$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...
259
			}
260
			return !($result === false);
261
		} else {
262
			return false;
263
		}
264
	}
265
266
	/**
267
	 * get the users home folder to mount
268
	 *
269
	 * @return string
270
	 */
271
	public function getHome() {
272
		if (!$this->home) {
273
			if ($this->backend->implementsActions(Backend::GET_HOME) and $home = $this->backend->getHome($this->uid)) {
274
				$this->home = $home;
275
			} elseif ($this->config) {
276
				$this->home = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
277
			} else {
278
				$this->home = \OC::$SERVERROOT . '/data/' . $this->uid;
279
			}
280
		}
281
		return $this->home;
282
	}
283
284
	/**
285
	 * Get the name of the backend class the user is connected with
286
	 *
287
	 * @return string
288
	 */
289
	public function getBackendClassName() {
290
		if($this->backend instanceof IUserBackend) {
291
			return $this->backend->getBackendName();
292
		}
293
		return get_class($this->backend);
294
	}
295
296
	/**
297
	 * check if the backend allows the user to change his avatar on Personal page
298
	 *
299
	 * @return bool
300
	 */
301
	public function canChangeAvatar() {
302
		if ($this->backend->implementsActions(Backend::PROVIDE_AVATAR)) {
303
			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...
304
		}
305
		return true;
306
	}
307
308
	/**
309
	 * check if the backend supports changing passwords
310
	 *
311
	 * @return bool
312
	 */
313
	public function canChangePassword() {
314
		return $this->backend->implementsActions(Backend::SET_PASSWORD);
315
	}
316
317
	/**
318
	 * check if the backend supports changing display names
319
	 *
320
	 * @return bool
321
	 */
322
	public function canChangeDisplayName() {
323
		if ($this->config->getSystemValue('allow_user_to_change_display_name') === false) {
324
			return false;
325
		}
326
		return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
327
	}
328
329
	/**
330
	 * check if the user is enabled
331
	 *
332
	 * @return bool
333
	 */
334
	public function isEnabled() {
335
		return $this->enabled;
336
	}
337
338
	/**
339
	 * set the enabled status for the user
340
	 *
341
	 * @param bool $enabled
342
	 */
343
	public function setEnabled($enabled) {
344
		$this->enabled = $enabled;
345
		$enabled = ($enabled) ? 'true' : 'false';
346
		$this->config->setUserValue($this->uid, 'core', 'enabled', $enabled);
347
	}
348
349
	/**
350
	 * get the users email address
351
	 *
352
	 * @return string|null
353
	 * @since 9.0.0
354
	 */
355
	public function getEMailAddress() {
356
		return $this->config->getUserValue($this->uid, 'settings', 'email', null);
357
	}
358
359
	/**
360
	 * get the users' quota
361
	 *
362
	 * @return string
363
	 * @since 9.0.0
364
	 */
365
	public function getQuota() {
366
		$quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
367
		if($quota === 'default') {
368
			$quota = $this->config->getAppValue('files', 'default_quota', 'none');
369
		}
370
		return $quota;
371
	}
372
373
	/**
374
	 * set the users' quota
375
	 *
376
	 * @param string $quota
377
	 * @return void
378
	 * @since 9.0.0
379
	 */
380
	public function setQuota($quota) {
381 View Code Duplication
		if($quota !== 'none' and $quota !== 'default') {
382
			$quota = OC_Helper::computerFileSize($quota);
383
			$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...
384
		}
385
		$this->config->setUserValue($this->uid, 'files', 'quota', $quota);
386
		$this->triggerChange('quota', $quota);
387
	}
388
389
	/**
390
	 * get the avatar image if it exists
391
	 *
392
	 * @param int $size
393
	 * @return IImage|null
394
	 * @since 9.0.0
395
	 */
396
	public function getAvatarImage($size) {
397
		// delay the initialization
398
		if (is_null($this->avatarManager)) {
399
			$this->avatarManager = \OC::$server->getAvatarManager();
400
		}
401
402
		$avatar = $this->avatarManager->getAvatar($this->uid);
403
		$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 405 which is incompatible with the return type declared by the interface OCP\IUser::getAvatarImage of type OCP\IImage|null.
Loading history...
404
		if ($image) {
405
			return $image;
406
		}
407
408
		return null;
409
	}
410
411
	/**
412
	 * get the federation cloud id
413
	 *
414
	 * @return string
415
	 * @since 9.0.0
416
	 */
417
	public function getCloudId() {
418
		$uid = $this->getUID();
419
		$server = $this->urlGenerator->getAbsoluteURL('/');
420
		$server =  rtrim( $this->removeProtocolFromUrl($server), '/');
421
		return \OC::$server->getCloudIdManager()->getCloudId($uid, $server)->getId();
422
	}
423
424
	/**
425
	 * @param string $url
426
	 * @return string
427
	 */
428 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...
429
		if (strpos($url, 'https://') === 0) {
430
			return substr($url, strlen('https://'));
431
		} else if (strpos($url, 'http://') === 0) {
432
			return substr($url, strlen('http://'));
433
		}
434
435
		return $url;
436
	}
437
438
	public function triggerChange($feature, $value = null) {
439
		if ($this->emitter) {
440
			$this->emitter->emit('\OC\User', 'changeUser', array($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\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...
441
		}
442
	}
443
}
444