ElggUser   F
last analyzed

Complexity

Total Complexity 85

Size/Duplication

Total Lines 794
Duplicated Lines 15.49 %

Coupling/Cohesion

Components 2
Dependencies 9

Test Coverage

Coverage 10.91%

Importance

Changes 0
Metric Value
dl 123
loc 794
ccs 37
cts 339
cp 0.1091
rs 1.806
c 0
b 0
f 0
wmc 85
lcom 2
cbo 9

40 Methods

Rating   Name   Duplication   Size   Complexity  
A initializeAttributes() 7 7 1
A getExternalAttributes() 0 16 1
B __construct() 40 40 11
A load() 16 16 2
A create() 0 24 2
A update() 0 23 2
A delete() 0 11 2
A getDisplayName() 0 3 1
A setDisplayName() 0 3 1
B __set() 7 38 9
A set() 0 6 1
A ban() 0 3 1
A unban() 0 3 1
A isBanned() 0 3 1
A isAdmin() 0 8 1
A makeAdmin() 0 11 3
A removeAdmin() 0 11 3
A getSites() 8 8 2
A addToSite() 8 8 2
A removeFromSite() 0 8 2
A addFriend() 0 20 4
A removeFriend() 0 16 4
A isFriend() 0 3 1
A isFriendsWith() 0 3 1
A isFriendOf() 0 3 1
A getFriends() 18 18 2
A getFriendsOf() 19 19 2
A listFriends() 0 18 2
A getGroups() 0 23 3
A listGroups() 0 17 2
A getObjects() 0 16 2
A getFriendsObjects() 0 20 2
A countObjects() 0 4 1
A getCollections() 0 4 1
A getOwnerGUID() 0 7 2
A getOwner() 0 4 1
A prepareObject() 0 8 1
A getExportableValues() 0 7 1
A canComment() 0 7 2
A setPassword() 0 5 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

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

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

1
<?php
2
/**
3
 * \ElggUser
4
 *
5
 * Representation of a "user" in the system.
6
 *
7
 * @package    Elgg.Core
8
 * @subpackage DataModel.User
9
 * 
10
 * @property      string $name          The display name that the user will be known by in the network
11
 * @property      string $username      The short, reference name for the user in the network
12
 * @property      string $email         The email address to which Elgg will send email notifications
13
 * @property      string $language      The language preference of the user (ISO 639-1 formatted)
14
 * @property      string $banned        'yes' if the user is banned from the network, 'no' otherwise
15
 * @property      string $admin         'yes' if the user is an administrator of the network, 'no' otherwise
16
 * @property-read string $password      The legacy (salted MD5) password hash of the user
17
 * @property-read string $salt          The salt used to create the legacy password hash
18
 * @property-read string $password_hash The hashed password of the user
19
 */
20
class ElggUser extends \ElggEntity
21
	implements Friendable {
22
23
	/**
24
	 * Initialize the attributes array.
25
	 * This is vital to distinguish between metadata and base attributes.
26
	 *
27
	 * @return void
28
	 */
29 2 View Code Duplication
	protected function initializeAttributes() {
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...
30 2
		parent::initializeAttributes();
31
32 2
		$this->attributes['type'] = "user";
33 2
		$this->attributes += self::getExternalAttributes();
34 2
		$this->tables_split = 2;
35 2
	}
36
37
	/**
38
	 * Get default values for attributes stored in a separate table
39
	 *
40
	 * @return array
41
	 * @access private
42
	 *
43
	 * @see \Elgg\Database\EntityTable::getEntities
44
	 */
45 2
	final public static function getExternalAttributes() {
46
		return [
47 2
			'name' => null,
48 2
			'username' => null,
49 2
			'password' => null,
50 2
			'salt' => null,
51 2
			'password_hash' => null,
52 2
			'email' => null,
53 2
			'language' => null,
54 2
			'banned' => "no",
55 2
			'admin' => 'no',
56 2
			'prev_last_action' => null,
57 2
			'last_login' => null,
58 2
			'prev_last_login' => null,
59 2
		];
60
	}
61
62
	/**
63
	 * Construct a new user entity
64
	 *
65
	 * Plugin developers should only use the constructor to create a new entity.
66
	 * To retrieve entities, use get_entity() and the elgg_get_entities* functions.
67
	 *
68
	 * @param \stdClass $row Database row result. Default is null to create a new user.
69
	 *
70
	 * @throws IOException|InvalidParameterException if there was a problem creating the user.
71
	 */
72 2 View Code Duplication
	public function __construct($row = null) {
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...
73 2
		$this->initializeAttributes();
74
75
		// compatibility for 1.7 api.
76 2
		$this->initialise_attributes(false);
0 ignored issues
show
Deprecated Code introduced by
The method ElggData::initialise_attributes() has been deprecated with message: 1.8 Use initializeAttributes()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
77
78 2
		if (!empty($row)) {
79
			// Is $row is a DB entity row
80
			if ($row instanceof \stdClass) {
81
				// Load the rest
82
				if (!$this->load($row)) {
83
					$msg = "Failed to load new " . get_class() . " for GUID:" . $row->guid;
84
					throw new \IOException($msg);
85
				}
86
			} else if (is_string($row)) {
87
				// $row is a username
88
				elgg_deprecated_notice('Passing a username to constructor is deprecated. Use get_user_by_username()', 1.9);
89
				$user = get_user_by_username($row);
90
				if ($user) {
91
					foreach ($user->attributes as $key => $value) {
92
						$this->attributes[$key] = $value;
93
					}
94
				}
95
			} else if ($row instanceof \ElggUser) {
96
				// $row is an \ElggUser so this is a copy constructor
97
				elgg_deprecated_notice('This type of usage of the \ElggUser constructor was deprecated. Please use the clone method.', 1.7);
98
				foreach ($row->attributes as $key => $value) {
99
					$this->attributes[$key] = $value;
100
				}
101
			} else if (is_numeric($row)) {
102
				// $row is a GUID so load entity
103
				elgg_deprecated_notice('Passing a GUID to constructor is deprecated. Use get_entity()', 1.9);
104
				if (!$this->load($row)) {
105
					throw new \IOException("Failed to load new " . get_class() . " from GUID:" . $row);
106
				}
107
			} else {
108
				throw new \InvalidParameterException("Unrecognized value passed to constuctor.");
109 2
			}
110 2
		}
111 2
	}
112
113
	/**
114
	 * Load the \ElggUser data from the database
115
	 *
116
	 * @param mixed $guid \ElggUser GUID or \stdClass database row from entity table
117
	 *
118
	 * @return bool
119
	 */
120 View Code Duplication
	protected function load($guid) {
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...
121
		$attr_loader = new \Elgg\AttributeLoader(get_class(), 'user', $this->attributes);
122
		$attr_loader->secondary_loader = 'get_user_entity_as_row';
123
124
		$attrs = $attr_loader->getRequiredAttributes($guid);
125
		if (!$attrs) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $attrs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
126
			return false;
127
		}
128
129
		$this->attributes = $attrs;
130
		$this->tables_loaded = 2;
131
		$this->loadAdditionalSelectValues($attr_loader->getAdditionalSelectValues());
132
		_elgg_cache_entity($this);
133
134
		return true;
135
	}
136
137
138
	/**
139
	 * {@inheritdoc}
140
	 */
141
	protected function create() {
142
		global $CONFIG;
143
	
144
		$guid = parent::create();
145
		$name = sanitize_string($this->name);
146
		$username = sanitize_string($this->username);
147
		$password = sanitize_string($this->password);
148
		$salt = sanitize_string($this->salt);
149
		$password_hash = sanitize_string($this->password_hash);
150
		$email = sanitize_string($this->email);
151
		$language = sanitize_string($this->language);
152
153
		$query = "INSERT into {$CONFIG->dbprefix}users_entity
154
			(guid, name, username, password, salt, password_hash, email, language)
155
			values ($guid, '$name', '$username', '$password', '$salt', '$password_hash', '$email', '$language')";
156
157
		$result = $this->getDatabase()->insertData($query);
158
		if ($result === false) {
159
			// TODO(evan): Throw an exception here?
160
			return false;
161
		}
162
		
163
		return $guid;
164
	}
165
	
166
	/**
167
	 * {@inheritdoc}
168
	 */
169
	protected function update() {
170
		global $CONFIG;
171
		
172
		if (!parent::update()) {
173
			return false;
174
		}
175
		
176
		$guid = (int)$this->guid;
177
		$name = sanitize_string($this->name);
178
		$username = sanitize_string($this->username);
179
		$password = sanitize_string($this->password);
180
		$salt = sanitize_string($this->salt);
181
		$password_hash = sanitize_string($this->password_hash);
182
		$email = sanitize_string($this->email);
183
		$language = sanitize_string($this->language);
184
185
		$query = "UPDATE {$CONFIG->dbprefix}users_entity
186
			SET name='$name', username='$username', password='$password', salt='$salt',
187
			password_hash='$password_hash', email='$email', language='$language'
188
			WHERE guid = $guid";
189
190
		return $this->getDatabase()->updateData($query) !== false;
191
	}
192
193
	/**
194
	 * User specific override of the entity delete method.
195
	 *
196
	 * @return bool
197
	 */
198
	public function delete() {
199
		global $USERNAME_TO_GUID_MAP_CACHE;
200
201
		// clear cache
202
		if (isset($USERNAME_TO_GUID_MAP_CACHE[$this->username])) {
203
			unset($USERNAME_TO_GUID_MAP_CACHE[$this->username]);
204
		}
205
206
		// Delete entity
207
		return parent::delete();
208
	}
209
210
	/**
211
	 * {@inheritdoc}
212
	 */
213
	public function getDisplayName() {
214
		return $this->name;
215
	}
216
217
	/**
218
	 * {@inheritdoc}
219
	 */
220
	public function setDisplayName($displayName) {
221
		$this->name = $displayName;
222
	}
223
224
	/**
225
	 * {@inheritdoc}
226
	 */
227 1
	public function __set($name, $value) {
228 1
		if (!array_key_exists($name, $this->attributes)) {
229
			parent::__set($name, $value);
230
			return;
231
		}
232
233
		switch ($name) {
234 1
			case 'prev_last_action':
235 1
			case 'last_login':
236 1 View Code Duplication
			case 'prev_last_login':
237 1
				if ($value !== null) {
238 1
					$this->attributes[$name] = (int)$value;
239 1
				} else {
240
					$this->attributes[$name] = null;
241
				}
242 1
				break;
243
244
			case 'salt':
245
			case 'password':
246
				elgg_deprecated_notice("Setting salt/password directly is deprecated. Use ElggUser::setPassword().", "1.10");
247
				$this->attributes[$name] = $value;
248
249
				// this is emptied so that the user is not left with two usable hashes
250
				$this->attributes['password_hash'] = '';
251
252
				break;
253
254
			// setting this not supported
255
			case 'password_hash':
256
				_elgg_services()->logger->error("password_hash is now an attribute of ElggUser and cannot be set.");
257
				return;
258
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
259
260
			default:
261
				parent::__set($name, $value);
262
				break;
263
		}
264 1
	}
265
266
	/**
267
	 * {@inheritdoc}
268
	 */
269
	public function set($name, $value) {
270
		elgg_deprecated_notice("Use -> instead of set()", 1.9);
271
		$this->__set($name, $value);
272
273
		return true;
274
	}
275
276
	/**
277
	 * Ban this user.
278
	 *
279
	 * @param string $reason Optional reason
280
	 *
281
	 * @return bool
282
	 */
283
	public function ban($reason = "") {
284
		return ban_user($this->guid, $reason);
285
	}
286
287
	/**
288
	 * Unban this user.
289
	 *
290
	 * @return bool
291
	 */
292
	public function unban() {
293
		return unban_user($this->guid);
294
	}
295
296
	/**
297
	 * Is this user banned or not?
298
	 *
299
	 * @return bool
300
	 */
301
	public function isBanned() {
302
		return $this->banned == 'yes';
303
	}
304
305
	/**
306
	 * Is this user admin?
307
	 *
308
	 * @return bool
309
	 */
310
	public function isAdmin() {
311
312
		// for backward compatibility we need to pull this directly
313
		// from the attributes instead of using the magic methods.
314
		// this can be removed in 1.9
315
		// return $this->admin == 'yes';
316
		return $this->attributes['admin'] == 'yes';
317
	}
318
319
	/**
320
	 * Make the user an admin
321
	 *
322
	 * @return bool
323
	 */
324
	public function makeAdmin() {
325
		// If already saved, use the standard function.
326
		if ($this->guid && !make_user_admin($this->guid)) {
327
			return false;
328
		}
329
330
		// need to manually set attributes since they've already been loaded.
331
		$this->attributes['admin'] = 'yes';
332
333
		return true;
334
	}
335
336
	/**
337
	 * Remove the admin flag for user
338
	 *
339
	 * @return bool
340
	 */
341
	public function removeAdmin() {
342
		// If already saved, use the standard function.
343
		if ($this->guid && !remove_user_admin($this->guid)) {
344
			return false;
345
		}
346
347
		// need to manually set attributes since they've already been loaded.
348
		$this->attributes['admin'] = 'no';
349
350
		return true;
351
	}
352
353
	/**
354
	 * Get sites that this user is a member of
355
	 *
356
	 * @param array $options Options array. Used to be $subtype
357
	 * @param int   $limit   The number of results to return (deprecated)
358
	 * @param int   $offset  Any indexing offset (deprecated)
359
	 *
360
	 * @return array
361
	 */
362 View Code Duplication
	public function getSites($options = "", $limit = 10, $offset = 0) {
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...
363
		if (is_string($options)) {
364
			elgg_deprecated_notice('\ElggUser::getSites() takes an options array', 1.9);
365
			return get_user_sites($this->getGUID(), $limit, $offset);
366
		}
367
368
		return parent::getSites($options);
369
	}
370
371
	/**
372
	 * Add this user to a particular site
373
	 *
374
	 * @param \ElggSite $site The site to add this user to. This used to be the
375
	 *                       the site guid (still supported by deprecated)
376
	 * @return bool
377
	 */
378 View Code Duplication
	public function addToSite($site) {
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...
379
		if (is_numeric($site)) {
380
			elgg_deprecated_notice('\ElggUser::addToSite() takes a site entity', 1.9);
381
			return add_site_user($site, $this->getGUID());
382
		}
383
384
		return parent::addToSite($site);
385
	}
386
387
	/**
388
	 * Remove this user from a particular site
389
	 *
390
	 * @param \ElggSite $site The site to remove the user from. Used to be site GUID
391
	 *
392
	 * @return bool
393
	 */
394
	public function removeFromSite($site) {
395
		if (is_numeric($site)) {
396
			elgg_deprecated_notice('\ElggUser::removeFromSite() takes a site entity', 1.9);
397
			return remove_site_user($site, $this->guid);
398
		}
399
400
		return parent::removeFromSite($site);
401
	}
402
403
	/**
404
	 * Adds a user as a friend
405
	 *
406
	 * @param int  $friend_guid       The GUID of the user to add
407
	 * @param bool $create_river_item Create the river item announcing this friendship
408
	 *
409
	 * @return bool
410
	 */
411
	public function addFriend($friend_guid, $create_river_item = false) {
412
		if (!get_user($friend_guid)) {
413
			return false;
414
		}
415
416
		if (!add_entity_relationship($this->guid, "friend", $friend_guid)) {
417
			return false;
418
		}
419
420
		if ($create_river_item) {
421
			elgg_create_river_item(array(
422
				'view' => 'river/relationship/friend/create',
423
				'action_type' => 'friend',
424
				'subject_guid' => $this->guid,
425
				'object_guid' => $friend_guid,
426
			));
427
		}
428
429
		return true;
430
	}
431
432
	/**
433
	 * Removes a user as a friend
434
	 *
435
	 * @param int $friend_guid The GUID of the user to remove
436
	 *
437
	 * @return bool
438
	 */
439
	public function removeFriend($friend_guid) {
440
		if (!get_user($friend_guid)) {
441
			return false;
442
		}
443
444
		// @todo this should be done with a plugin hook handler on the delete relationship
445
		// perform cleanup for access lists.
446
		$collections = get_user_access_collections($this->guid);
447
		if ($collections) {
448
			foreach ($collections as $collection) {
449
				remove_user_from_access_collection($friend_guid, $collection->id);
450
			}
451
		}
452
453
		return remove_entity_relationship($this->guid, "friend", $friend_guid);
454
	}
455
456
	/**
457
	 * Determines whether or not this user is a friend of the currently logged in user
458
	 *
459
	 * @return bool
460
	 */
461
	public function isFriend() {
462
		return $this->isFriendOf(_elgg_services()->session->getLoggedInUserGuid());
463
	}
464
465
	/**
466
	 * Determines whether this user is friends with another user
467
	 *
468
	 * @param int $user_guid The GUID of the user to check against
469
	 *
470
	 * @return bool
471
	 */
472
	public function isFriendsWith($user_guid) {
473
		return (bool)check_entity_relationship($this->guid, "friend", $user_guid);
474
	}
475
476
	/**
477
	 * Determines whether or not this user is another user's friend
478
	 *
479
	 * @param int $user_guid The GUID of the user to check against
480
	 *
481
	 * @return bool
482
	 */
483
	public function isFriendOf($user_guid) {
484
		return (bool)check_entity_relationship($user_guid, "friend", $this->guid);
485
	}
486
487
	/**
488
	 * Gets this user's friends
489
	 *
490
	 * @param array $options Options array. See elgg_get_entities_from_relationship()
491
	 *                       for a list of options. 'relationship_guid' is set to
492
	 *                       this entity, relationship name to 'friend' and type to 'user'.
493
	 * @param int   $limit   The number of users to retrieve (deprecated)
494
	 * @param int   $offset  Indexing offset, if any (deprecated)
495
	 *
496
	 * @return array|false Array of \ElggUser, or false, depending on success
497
	 */
498 View Code Duplication
	public function getFriends($options = array(), $limit = 10, $offset = 0) {
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...
499
		if (is_array($options)) {
500
			$options['relationship'] = 'friend';
501
			$options['relationship_guid'] = $this->getGUID();
502
			$options['type'] = 'user';
503
			return elgg_get_entities_from_relationship($options);
0 ignored issues
show
Bug Compatibility introduced by
The expression elgg_get_entities_from_relationship($options); of type false|integer|array adds the type integer to the return on line 503 which is incompatible with the return type declared by the interface Friendable::getFriends of type array|false.
Loading history...
504
		} else {
505
			elgg_deprecated_notice("\ElggUser::getFriends takes an options array", 1.9);
506
			return elgg_get_entities_from_relationship(array(
0 ignored issues
show
Bug Compatibility introduced by
The expression elgg_get_entities_from_r... 'offset' => $offset)); of type false|integer|array adds the type integer to the return on line 506 which is incompatible with the return type declared by the interface Friendable::getFriends of type array|false.
Loading history...
507
				'relationship' => 'friend',
508
				'relationship_guid' => $this->guid,
509
				'type' => 'user',
510
				'subtype' => $options,
511
				'limit' => $limit,
512
				'offset' => $offset,
513
			));
514
		}
515
	}
516
517
	/**
518
	 * Gets users who have made this user a friend
519
	 *
520
	 * @param array $options Options array. See elgg_get_entities_from_relationship()
521
	 *                       for a list of options. 'relationship_guid' is set to
522
	 *                       this entity, relationship name to 'friend', type to 'user'
523
	 *                       and inverse_relationship to true.
524
	 * @param int   $limit   The number of users to retrieve (deprecated)
525
	 * @param int   $offset  Indexing offset, if any (deprecated)
526
	 *
527
	 * @return array|false Array of \ElggUser, or false, depending on success
528
	 */
529 View Code Duplication
	public function getFriendsOf($options = array(), $limit = 10, $offset = 0) {
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...
530
		if (is_array($options)) {
531
			$options['relationship'] = 'friend';
532
			$options['relationship_guid'] = $this->getGUID();
533
			$options['inverse_relationship'] = true;
534
			$options['type'] = 'user';
535
			return elgg_get_entities_from_relationship($options);
0 ignored issues
show
Bug Compatibility introduced by
The expression elgg_get_entities_from_relationship($options); of type false|integer|array adds the type integer to the return on line 535 which is incompatible with the return type declared by the interface Friendable::getFriendsOf of type array|false.
Loading history...
536
		} else {
537
			elgg_deprecated_notice("\ElggUser::getFriendsOf takes an options array", 1.9);
538
			return elgg_get_entities_from_relationship(array(
0 ignored issues
show
Bug Compatibility introduced by
The expression elgg_get_entities_from_r... 'offset' => $offset)); of type false|integer|array adds the type integer to the return on line 538 which is incompatible with the return type declared by the interface Friendable::getFriendsOf of type array|false.
Loading history...
539
				'relationship' => 'friend',
540
				'relationship_guid' => $this->guid,
541
				'type' => 'user',
542
				'subtype' => $options,
543
				'limit' => $limit,
544
				'offset' => $offset,
545
			));
546
		}
547
	}
548
549
	/**
550
	 * Lists the user's friends
551
	 *
552
	 * @param string $subtype Optionally, the user subtype (leave blank for all)
553
	 * @param int    $limit   The number of users to retrieve
554
	 * @param array  $vars    Display variables for the user view
555
	 *
556
	 * @return string Rendered list of friends
557
	 * @since 1.8.0
558
	 * @deprecated 1.9 Use elgg_list_entities_from_relationship()
559
	 */
560
	public function listFriends($subtype = "", $limit = 10, array $vars = array()) {
561
		elgg_deprecated_notice('\ElggUser::listFriends() is deprecated. Use elgg_list_entities_from_relationship()', 1.9);
562
		$defaults = array(
563
			'type' => 'user',
564
			'relationship' => 'friend',
565
			'relationship_guid' => $this->guid,
566
			'limit' => $limit,
567
			'full_view' => false,
568
		);
569
570
		$options = array_merge($defaults, $vars);
571
572
		if ($subtype) {
573
			$options['subtype'] = $subtype;
574
		}
575
576
		return elgg_list_entities_from_relationship($options);
577
	}
578
579
	/**
580
	 * Gets the user's groups
581
	 *
582
	 * @param array $options Options array. Used to be the subtype string.
583
	 * @param int   $limit   The number of groups to retrieve (deprecated)
584
	 * @param int   $offset  Indexing offset, if any (deprecated)
585
	 *
586
	 * @return array|false Array of \ElggGroup, or false, depending on success
587
	 */
588
	public function getGroups($options = "", $limit = 10, $offset = 0) {
589
		if (is_string($options)) {
590
			elgg_deprecated_notice('\ElggUser::getGroups() takes an options array', 1.9);
591
			$subtype = $options;
592
			$options = array(
593
				'type' => 'group',
594
				'relationship' => 'member',
595
				'relationship_guid' => $this->guid,
596
				'limit' => $limit,
597
				'offset' => $offset,
598
			);
599
600
			if ($subtype) {
601
				$options['subtype'] = $subtype;
602
			}
603
		} else {
604
			$options['type'] = 'group';
605
			$options['relationship'] = 'member';
606
			$options['relationship_guid'] = $this->guid;
607
		}
608
609
		return elgg_get_entities_from_relationship($options);
610
	}
611
612
	/**
613
	 * Lists the user's groups
614
	 *
615
	 * @param string $subtype Optionally, the user subtype (leave blank for all)
616
	 * @param int    $limit   The number of users to retrieve
617
	 * @param int    $offset  Indexing offset, if any
618
	 *
619
	 * @return string
620
	 * @deprecated 1.9 Use elgg_list_entities_from_relationship()
621
	 */
622
	public function listGroups($subtype = "", $limit = 10, $offset = 0) {
623
		elgg_deprecated_notice('Elgg::listGroups is deprecated. Use elgg_list_entities_from_relationship()', 1.9);
624
		$options = array(
625
			'type' => 'group',
626
			'relationship' => 'member',
627
			'relationship_guid' => $this->guid,
628
			'limit' => $limit,
629
			'offset' => $offset,
630
			'full_view' => false,
631
		);
632
633
		if ($subtype) {
634
			$options['subtype'] = $subtype;
635
		}
636
637
		return elgg_list_entities_from_relationship($options);
638
	}
639
640
	/**
641
	 * Get an array of \ElggObject owned by this user.
642
	 *
643
	 * @param array $options Options array. See elgg_get_entities() for a list of options.
644
	 *                       'type' is set to object and owner_guid to this entity.
645
	 * @param int   $limit   Number of results to return (deprecated)
646
	 * @param int   $offset  Any indexing offset (deprecated)
647
	 *
648
	 * @return array|false
649
	 */
650
	public function getObjects($options = array(), $limit = 10, $offset = 0) {
651
		if (is_array($options)) {
652
			$options['type'] = 'object';
653
			$options['owner_guid'] = $this->getGUID();
654
			return elgg_get_entities($options);
0 ignored issues
show
Bug Compatibility introduced by
The expression elgg_get_entities($options); of type false|integer|array adds the type integer to the return on line 654 which is incompatible with the return type declared by the interface Friendable::getObjects of type array|false.
Loading history...
655
		} else {
656
			elgg_deprecated_notice("\ElggUser::getObjects takes an options array", 1.9);
657
			return elgg_get_entities(array(
0 ignored issues
show
Bug Compatibility introduced by
The expression elgg_get_entities(array(... 'offset' => $offset)); of type false|integer|array adds the type integer to the return on line 657 which is incompatible with the return type declared by the interface Friendable::getObjects of type array|false.
Loading history...
658
				'type' => 'object',
659
				'subtype' => $options,
660
				'owner_guid' => $this->getGUID(),
661
				'limit' => $limit,
662
				'offset' => $offset
663
			));
664
		}
665
	}
666
667
	/**
668
	 * Get an array of \ElggObjects owned by this user's friends.
669
	 *
670
	 * @param array $options Options array. See elgg_get_entities_from_relationship()
671
	 *                       for a list of options. 'relationship_guid' is set to
672
	 *                       this entity, type to 'object', relationship name to 'friend'
673
	 *                       and relationship_join_on to 'container_guid'.
674
	 * @param int   $limit   Number of results to return (deprecated)
675
	 * @param int   $offset  Any indexing offset (deprecated)
676
	 *
677
	 * @return array|false
678
	 */
679
	public function getFriendsObjects($options = array(), $limit = 10, $offset = 0) {
680
		if (is_array($options)) {
681
			$options['type'] = 'object';
682
			$options['relationship'] = 'friend';
683
			$options['relationship_guid'] = $this->getGUID();
684
			$options['relationship_join_on'] = 'container_guid';
685
			return elgg_get_entities_from_relationship($options);
0 ignored issues
show
Bug Compatibility introduced by
The expression elgg_get_entities_from_relationship($options); of type false|integer|array adds the type integer to the return on line 685 which is incompatible with the return type declared by the interface Friendable::getFriendsObjects of type array|false.
Loading history...
686
		} else {
687
			elgg_deprecated_notice("\ElggUser::getFriendsObjects takes an options array", 1.9);
688
			return elgg_get_entities_from_relationship(array(
0 ignored issues
show
Bug Compatibility introduced by
The expression elgg_get_entities_from_r... => 'container_guid')); of type false|integer|array adds the type integer to the return on line 688 which is incompatible with the return type declared by the interface Friendable::getFriendsObjects of type array|false.
Loading history...
689
				'type' => 'object',
690
				'subtype' => $options,
691
				'limit' => $limit,
692
				'offset' => $offset,
693
				'relationship' => 'friend',
694
				'relationship_guid' => $this->getGUID(),
695
				'relationship_join_on' => 'container_guid',
696
			));
697
		}
698
	}
699
700
	/**
701
	 * Counts the number of \ElggObjects owned by this user
702
	 *
703
	 * @param string $subtype The subtypes of the objects, if any
704
	 *
705
	 * @return int The number of \ElggObjects
706
	 * @deprecated 1.9 Use elgg_get_entities()
707
	 */
708
	public function countObjects($subtype = "") {
709
		elgg_deprecated_notice("\ElggUser::countObjects() is deprecated. Use elgg_get_entities()", 1.9);
710
		return count_user_objects($this->getGUID(), $subtype);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return count_user_object...->getGUID(), $subtype); (false|integer|array) is incompatible with the return type declared by the interface Friendable::countObjects of type integer.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
711
	}
712
713
	/**
714
	 * Get the collections associated with a user.
715
	 *
716
	 * @param string $subtype Optionally, the subtype of result we want to limit to
717
	 * @param int    $limit   The number of results to return
718
	 * @param int    $offset  Any indexing offset
719
	 *
720
	 * @return array|false
721
	 */
722
	public function getCollections($subtype = "", $limit = 10, $offset = 0) {
723
		elgg_deprecated_notice("\ElggUser::getCollections() has been deprecated", 1.8);
724
		return false;
725
	}
726
727
	/**
728
	 * Get a user's owner GUID
729
	 *
730
	 * Returns it's own GUID if the user is not owned.
731
	 *
732
	 * @return int
733
	 */
734
	public function getOwnerGUID() {
735
		if ($this->owner_guid == 0) {
736
			return $this->guid;
737
		}
738
739
		return $this->owner_guid;
740
	}
741
742
	/**
743
	 * If a user's owner is blank, return its own GUID as the owner
744
	 *
745
	 * @return int User GUID
746
	 * @deprecated 1.8 Use getOwnerGUID()
747
	 */
748
	public function getOwner() {
749
		elgg_deprecated_notice("\ElggUser::getOwner deprecated for \ElggUser::getOwnerGUID", 1.8);
750
		$this->getOwnerGUID();
0 ignored issues
show
Unused Code introduced by
The call to the method ElggUser::getOwnerGUID() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
751
	}
752
753
	/**
754
	 * {@inheritdoc}
755
	 */
756
	protected function prepareObject($object) {
757
		$object = parent::prepareObject($object);
758
		$object->name = $this->getDisplayName();
759
		$object->username = $this->username;
760
		$object->language = $this->language;
761
		unset($object->read_access);
762
		return $object;
763
	}
764
765
	// EXPORTABLE INTERFACE ////////////////////////////////////////////////////////////
766
767
	/**
768
	 * Return an array of fields which can be exported.
769
	 *
770
	 * @return array
771
	 * @deprecated 1.9 Use toObject()
772
	 */
773
	public function getExportableValues() {
774
		return array_merge(parent::getExportableValues(), array(
0 ignored issues
show
Deprecated Code introduced by
The method ElggEntity::getExportableValues() has been deprecated with message: 1.9 Use toObject()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
775
			'name',
776
			'username',
777
			'language',
778
		));
779
	}
780
781
	/**
782
	 * Can a user comment on this user?
783
	 *
784
	 * @see \ElggEntity::canComment()
785
	 * 
786
	 * @param int $user_guid User guid (default is logged in user)
787
	 * @return bool
788
	 * @since 1.8.0
789
	 */
790
	public function canComment($user_guid = 0) {
791
		$result = parent::canComment($user_guid);
792
		if ($result !== null) {
793
			return $result;
794
		}
795
		return false;
796
	}
797
798
	/**
799
	 * Set the necessary attributes to store a hash of the user's password. Also removes
800
	 * the legacy hash/salt values.
801
	 *
802
	 * @tip You must save() to persist the attributes
803
	 *
804
	 * @param string $password The password to be hashed
805
	 * @return void
806
	 * @since 1.10.0
807
	 */
808
	public function setPassword($password) {
809
		$this->attributes['salt'] = "";
810
		$this->attributes['password'] = "";
811
		$this->attributes['password_hash'] = _elgg_services()->passwords->generateHash($password);
812
	}
813
}
814