1 | <?php |
||
2 | /** |
||
3 | * A user entity |
||
4 | * |
||
5 | * @property string $name The display name that the user will be known by in the network |
||
6 | * @property string $username The short, reference name for the user in the network |
||
7 | * @property string $email The email address to which Elgg will send email notifications |
||
8 | * @property string $language The language preference of the user (ISO 639-1 formatted) |
||
9 | * @property string $banned 'yes' if the user is banned from the network, 'no' otherwise |
||
10 | * @property string $admin 'yes' if the user is an administrator of the network, 'no' otherwise |
||
11 | * @property-read string $password_hash The hashed password of the user |
||
12 | * @property-read int $prev_last_action A UNIX timestamp of the previous last action |
||
13 | * @property-read int $last_login A UNIX timestamp of the last login |
||
14 | * @property-read int $prev_last_login A UNIX timestamp of the previous login |
||
15 | */ |
||
16 | class ElggUser extends \ElggEntity |
||
17 | implements Friendable { |
||
18 | |||
19 | /** |
||
20 | * {@inheritdoc} |
||
21 | */ |
||
22 | 828 | protected function initializeAttributes() { |
|
23 | 828 | parent::initializeAttributes(); |
|
24 | 828 | $this->attributes['subtype'] = 'user'; |
|
25 | 828 | } |
|
26 | |||
27 | /** |
||
28 | * {@inheritdoc} |
||
29 | */ |
||
30 | 828 | public function getType() { |
|
31 | 828 | return 'user'; |
|
32 | } |
||
33 | |||
34 | /** |
||
35 | * Get user language or default to site language |
||
36 | * |
||
37 | * @param string $fallback If this is provided, it will be returned if the user doesn't have a language set. |
||
38 | * If null, the site language will be returned. |
||
39 | * |
||
40 | * @return string |
||
41 | */ |
||
42 | 4 | public function getLanguage($fallback = null) { |
|
43 | 4 | if (!empty($this->language)) { |
|
44 | 4 | return $this->language; |
|
45 | } |
||
46 | if ($fallback !== null) { |
||
47 | return $fallback; |
||
48 | } |
||
49 | return elgg_get_config('language'); |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * {@inheritdoc} |
||
54 | */ |
||
55 | 458 | public function __set($name, $value) { |
|
56 | 458 | switch ($name) { |
|
57 | case 'salt': |
||
58 | case 'password': |
||
59 | _elgg_services()->logger->error("User entities no longer contain {$name}"); |
||
60 | return; |
||
61 | case 'password_hash': |
||
62 | _elgg_services()->logger->error("password_hash is a readonly attribute."); |
||
63 | return; |
||
64 | case 'email': |
||
65 | 447 | if (!validate_email_address($value)) { |
|
66 | throw new \InvalidParameterException("Email is not a valid email address"); |
||
67 | } |
||
68 | 447 | break; |
|
69 | case 'username': |
||
70 | 458 | if (!validate_username($value)) { |
|
71 | throw new \InvalidParameterException("Username is not a valid username"); |
||
72 | } |
||
73 | 458 | $existing_user = get_user_by_username($value); |
|
74 | 458 | if ($existing_user && ($existing_user->guid !== $this->guid)) { |
|
75 | throw new \InvalidParameterException("{$name} is supposed to be unique for ElggUser"); |
||
76 | } |
||
77 | 458 | break; |
|
78 | } |
||
79 | |||
80 | 458 | parent::__set($name, $value); |
|
81 | 458 | } |
|
82 | |||
83 | /** |
||
84 | * {@inheritdoc} |
||
85 | */ |
||
86 | 15 | public function getURL() { |
|
87 | |||
88 | 15 | $result = parent::getURL(); |
|
89 | 15 | if ($result !== '') { |
|
90 | 1 | return $result; |
|
91 | } |
||
92 | |||
93 | 14 | return elgg_normalize_url("user/view/{$this->guid}"); |
|
94 | } |
||
95 | |||
96 | /** |
||
97 | * Ban this user. |
||
98 | * |
||
99 | * @param string $reason Optional reason |
||
100 | * |
||
101 | * @return bool |
||
102 | */ |
||
103 | 73 | public function ban($reason = '') { |
|
104 | |||
105 | 73 | if (!$this->canEdit()) { |
|
106 | return false; |
||
107 | } |
||
108 | |||
109 | 73 | if (!elgg_trigger_event('ban', 'user', $this)) { |
|
110 | return false; |
||
111 | } |
||
112 | |||
113 | 73 | $this->ban_reason = $reason; |
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||
114 | 73 | $this->banned = 'yes'; |
|
115 | |||
116 | 73 | $this->invalidateCache(); |
|
117 | |||
118 | 73 | return true; |
|
119 | } |
||
120 | |||
121 | /** |
||
122 | * Unban this user. |
||
123 | * |
||
124 | * @return bool |
||
125 | */ |
||
126 | 2 | public function unban() { |
|
127 | |||
128 | 2 | if (!$this->canEdit()) { |
|
129 | return false; |
||
130 | } |
||
131 | |||
132 | 2 | if (!elgg_trigger_event('unban', 'user', $this)) { |
|
133 | return false; |
||
134 | } |
||
135 | |||
136 | 2 | unset($this->ban_reason); |
|
137 | 2 | $this->banned = 'yes'; |
|
138 | |||
139 | 2 | $this->invalidateCache(); |
|
140 | |||
141 | 2 | return true; |
|
142 | } |
||
143 | |||
144 | /** |
||
145 | * Is this user banned or not? |
||
146 | * |
||
147 | * @return bool |
||
148 | */ |
||
149 | 30 | public function isBanned() { |
|
150 | 30 | return $this->banned == 'yes'; |
|
151 | } |
||
152 | |||
153 | /** |
||
154 | * Is this user admin? |
||
155 | * |
||
156 | * @return bool |
||
157 | */ |
||
158 | 375 | public function isAdmin() { |
|
159 | 375 | $ia = elgg_set_ignore_access(true); |
|
160 | 375 | $is_admin = ($this->admin == 'yes'); |
|
161 | 375 | elgg_set_ignore_access($ia); |
|
162 | |||
163 | 375 | return $is_admin; |
|
164 | } |
||
165 | |||
166 | /** |
||
167 | * Make the user an admin |
||
168 | * |
||
169 | * @return bool |
||
170 | */ |
||
171 | 7 | public function makeAdmin() { |
|
172 | |||
173 | 7 | if ($this->isAdmin()) { |
|
174 | return true; |
||
175 | } |
||
176 | |||
177 | 7 | if (!elgg_trigger_event('make_admin', 'user', $this)) { |
|
178 | return false; |
||
179 | } |
||
180 | |||
181 | 7 | $this->admin = 'yes'; |
|
182 | |||
183 | 7 | $this->invalidateCache(); |
|
184 | |||
185 | 7 | return true; |
|
186 | } |
||
187 | |||
188 | /** |
||
189 | * Remove the admin flag for user |
||
190 | * |
||
191 | * @return bool |
||
192 | */ |
||
193 | 3 | public function removeAdmin() { |
|
194 | |||
195 | 3 | if (!$this->isAdmin()) { |
|
196 | 1 | return true; |
|
197 | } |
||
198 | |||
199 | 2 | if (!elgg_trigger_event('remove_admin', 'user', $this)) { |
|
200 | return false; |
||
201 | } |
||
202 | |||
203 | 2 | $this->admin = 'no'; |
|
204 | |||
205 | 2 | $this->invalidateCache(); |
|
206 | |||
207 | 2 | return true; |
|
208 | } |
||
209 | |||
210 | /** |
||
211 | * Sets the last logon time of the user to right now. |
||
212 | * |
||
213 | * @return void |
||
214 | */ |
||
215 | 4 | public function setLastLogin() { |
|
216 | |||
217 | 4 | $time = $this->getCurrentTime()->getTimestamp(); |
|
218 | |||
219 | 4 | if ($this->last_login == $time) { |
|
220 | // no change required |
||
221 | return; |
||
222 | } |
||
223 | |||
224 | // these writes actually work, we just type hint read-only. |
||
225 | 4 | $this->prev_last_login = $this->last_login; |
|
226 | 4 | $this->last_login = $time; |
|
227 | 4 | } |
|
228 | |||
229 | /** |
||
230 | * Sets the last action time of the given user to right now. |
||
231 | * |
||
232 | * @see _elgg_session_boot The session boot calls this at the beginning of every request |
||
233 | * |
||
234 | * @return void |
||
235 | */ |
||
236 | public function setLastAction() { |
||
237 | |||
238 | $time = $this->getCurrentTime()->getTimestamp(); |
||
239 | |||
240 | if ($this->last_action == $time) { |
||
241 | // no change required |
||
242 | return; |
||
243 | } |
||
244 | |||
245 | // these writes actually work, we just type hint read-only. |
||
246 | $this->prev_last_action = $this->last_action; |
||
247 | |||
248 | $this->updateLastAction($time); |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * Gets the validation status of a user. |
||
253 | * |
||
254 | * @return bool|null Null means status was not set for this user. |
||
255 | */ |
||
256 | 6 | public function isValidated() { |
|
257 | 6 | if (!isset($this->validated)) { |
|
258 | 6 | return null; |
|
259 | } |
||
260 | return (bool) $this->validated; |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * Set the validation status for a user. |
||
265 | * |
||
266 | * @param bool $status Validated (true) or unvalidated (false) |
||
267 | * @param string $method Optional method to say how a user was validated |
||
268 | * @return void |
||
269 | */ |
||
270 | 165 | public function setValidationStatus($status, $method = '') { |
|
271 | |||
272 | 165 | $this->validated = $status; |
|
0 ignored issues
–
show
|
|||
273 | 165 | $this->validated_method = $method; |
|
0 ignored issues
–
show
|
|||
274 | |||
275 | 165 | if ((bool) $status) { |
|
276 | 103 | elgg_trigger_after_event('validate', 'user', $this); |
|
277 | } else { |
||
278 | 77 | elgg_trigger_after_event('invalidate', 'user', $this); |
|
279 | } |
||
280 | 165 | } |
|
281 | |||
282 | /** |
||
283 | * Adds a user as a friend |
||
284 | * |
||
285 | * @param int $friend_guid The GUID of the user to add |
||
286 | * @param bool $create_river_item Create the river item announcing this friendship |
||
287 | * |
||
288 | * @return bool |
||
289 | */ |
||
290 | public function addFriend($friend_guid, $create_river_item = false) { |
||
291 | if (!get_user($friend_guid)) { |
||
292 | return false; |
||
293 | } |
||
294 | |||
295 | if (!add_entity_relationship($this->guid, "friend", $friend_guid)) { |
||
296 | return false; |
||
297 | } |
||
298 | |||
299 | if ($create_river_item) { |
||
300 | elgg_create_river_item([ |
||
301 | 'view' => 'river/relationship/friend/create', |
||
302 | 'action_type' => 'friend', |
||
303 | 'subject_guid' => $this->guid, |
||
304 | 'object_guid' => $friend_guid, |
||
305 | ]); |
||
306 | } |
||
307 | |||
308 | return true; |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * Removes a user as a friend |
||
313 | * |
||
314 | * @param int $friend_guid The GUID of the user to remove |
||
315 | * @return bool |
||
316 | */ |
||
317 | public function removeFriend($friend_guid) { |
||
318 | return $this->removeRelationship($friend_guid, 'friend'); |
||
319 | } |
||
320 | |||
321 | /** |
||
322 | * Determines whether or not this user is a friend of the currently logged in user |
||
323 | * |
||
324 | * @return bool |
||
325 | */ |
||
326 | public function isFriend() { |
||
327 | return $this->isFriendOf(_elgg_services()->session->getLoggedInUserGuid()); |
||
328 | } |
||
329 | |||
330 | /** |
||
331 | * Determines whether this user is friends with another user |
||
332 | * |
||
333 | * @param int $user_guid The GUID of the user to check against |
||
334 | * |
||
335 | * @return bool |
||
336 | */ |
||
337 | public function isFriendsWith($user_guid) { |
||
338 | return (bool) check_entity_relationship($this->guid, "friend", $user_guid); |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Determines whether or not this user is another user's friend |
||
343 | * |
||
344 | * @param int $user_guid The GUID of the user to check against |
||
345 | * |
||
346 | * @return bool |
||
347 | */ |
||
348 | public function isFriendOf($user_guid) { |
||
349 | return (bool) check_entity_relationship($user_guid, "friend", $this->guid); |
||
350 | } |
||
351 | |||
352 | /** |
||
353 | * {@inheritdoc} |
||
354 | */ |
||
355 | public function getFriends(array $options = []) { |
||
356 | $options['relationship'] = 'friend'; |
||
357 | $options['relationship_guid'] = $this->getGUID(); |
||
358 | $options['type'] = 'user'; |
||
359 | |||
360 | return elgg_get_entities($options); |
||
361 | } |
||
362 | |||
363 | /** |
||
364 | * {@inheritdoc} |
||
365 | */ |
||
366 | public function getFriendsOf(array $options = []) { |
||
367 | $options['relationship'] = 'friend'; |
||
368 | $options['relationship_guid'] = $this->getGUID(); |
||
369 | $options['inverse_relationship'] = true; |
||
370 | $options['type'] = 'user'; |
||
371 | |||
372 | return elgg_get_entities($options); |
||
373 | } |
||
374 | |||
375 | /** |
||
376 | * Gets the user's groups |
||
377 | * |
||
378 | * @param array $options Options array. |
||
379 | * |
||
380 | * @return array|false Array of \ElggGroup, or false, depending on success |
||
381 | */ |
||
382 | public function getGroups(array $options = []) { |
||
383 | $options['type'] = 'group'; |
||
384 | $options['relationship'] = 'member'; |
||
385 | $options['relationship_guid'] = $this->guid; |
||
386 | |||
387 | return elgg_get_entities($options); |
||
388 | } |
||
389 | |||
390 | /** |
||
391 | * {@inheritdoc} |
||
392 | */ |
||
393 | public function getObjects(array $options = []) { |
||
394 | $options['type'] = 'object'; |
||
395 | $options['owner_guid'] = $this->getGUID(); |
||
396 | |||
397 | return elgg_get_entities($options); |
||
0 ignored issues
–
show
|
|||
398 | } |
||
399 | |||
400 | /** |
||
401 | * {@inheritdoc} |
||
402 | */ |
||
403 | public function getFriendsObjects(array $options = []) { |
||
404 | $options['type'] = 'object'; |
||
405 | $options['relationship'] = 'friend'; |
||
406 | $options['relationship_guid'] = $this->getGUID(); |
||
407 | $options['relationship_join_on'] = 'container_guid'; |
||
408 | |||
409 | return elgg_get_entities($options); |
||
410 | } |
||
411 | |||
412 | /** |
||
413 | * Get a user's owner GUID |
||
414 | * |
||
415 | * Returns it's own GUID if the user is not owned. |
||
416 | * |
||
417 | * @return int |
||
418 | */ |
||
419 | 1 | public function getOwnerGUID() { |
|
420 | 1 | if ($this->owner_guid == 0) { |
|
421 | 1 | return $this->guid; |
|
422 | } |
||
423 | |||
424 | return $this->owner_guid; |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * {@inheritdoc} |
||
429 | */ |
||
430 | 1 | protected function prepareObject($object) { |
|
431 | 1 | $object = parent::prepareObject($object); |
|
432 | 1 | $object->name = $this->getDisplayName(); |
|
433 | 1 | $object->username = $this->username; |
|
434 | 1 | $object->language = $this->language; |
|
435 | 1 | unset($object->read_access); |
|
436 | 1 | return $object; |
|
437 | } |
||
438 | |||
439 | /** |
||
440 | * Can a user comment on this user? |
||
441 | * |
||
442 | * @see \ElggEntity::canComment() |
||
443 | * |
||
444 | * @param int $user_guid User guid (default is logged in user) |
||
445 | * @param bool $default Default permission |
||
446 | * @return bool |
||
447 | * @since 1.8.0 |
||
448 | */ |
||
449 | 2 | public function canComment($user_guid = 0, $default = null) { |
|
450 | 2 | return false; |
|
451 | } |
||
452 | |||
453 | /** |
||
454 | * Set the necessary metadata to store a hash of the user's password. |
||
455 | * |
||
456 | * @param string $password The password to be hashed |
||
457 | * @return void |
||
458 | * @since 1.10.0 |
||
459 | */ |
||
460 | 162 | public function setPassword($password) { |
|
461 | 162 | $this->setMetadata('password_hash', _elgg_services()->passwords->generateHash($password)); |
|
462 | 162 | } |
|
463 | |||
464 | /** |
||
465 | * Enable or disable a notification delivery method |
||
466 | * |
||
467 | * @param string $method Method name |
||
468 | * @param bool $enabled Enabled or disabled |
||
469 | * @return bool |
||
470 | */ |
||
471 | 187 | public function setNotificationSetting($method, $enabled = true) { |
|
472 | 187 | $this->{"notification:method:$method"} = (int) $enabled; |
|
473 | 187 | return (bool) $this->save(); |
|
474 | } |
||
475 | |||
476 | /** |
||
477 | * Returns users's notification settings |
||
478 | * <code> |
||
479 | * [ |
||
480 | * 'email' => true, // enabled |
||
481 | * 'ajax' => false, // disabled |
||
482 | * ] |
||
483 | * </code> |
||
484 | * |
||
485 | * @return array |
||
486 | */ |
||
487 | 21 | public function getNotificationSettings() { |
|
488 | |||
489 | 21 | $settings = []; |
|
490 | |||
491 | 21 | $methods = _elgg_services()->notifications->getMethods(); |
|
492 | 21 | foreach ($methods as $method) { |
|
493 | 21 | $settings[$method] = (bool) $this->{"notification:method:$method"}; |
|
494 | } |
||
495 | |||
496 | 21 | return $settings; |
|
497 | |||
498 | } |
||
499 | |||
500 | /** |
||
501 | * Cache the entity in a session and persisted caches |
||
502 | * |
||
503 | * @param bool $persist Store in persistent cache |
||
504 | * |
||
505 | * @return void |
||
506 | * @access private |
||
507 | * @internal |
||
508 | */ |
||
509 | 828 | public function cache($persist = true) { |
|
510 | 828 | if ($persist && $this->username) { |
|
511 | 828 | $tmp = $this->volatile; |
|
512 | |||
513 | // don't store volatile data |
||
514 | 828 | $this->volatile = []; |
|
515 | |||
516 | 828 | _elgg_services()->dataCache->usernames->save($this->username, $this); |
|
517 | |||
518 | 828 | $this->volatile = $tmp; |
|
519 | } |
||
520 | |||
521 | 828 | parent::cache($persist); |
|
522 | 828 | } |
|
523 | |||
524 | /** |
||
525 | * Invalidate cache for entity |
||
526 | * |
||
527 | * @return void |
||
528 | * @internal |
||
529 | */ |
||
530 | 457 | public function invalidateCache() { |
|
531 | 457 | if ($this->username) { |
|
532 | 457 | _elgg_services()->dataCache->usernames->delete($this->username); |
|
533 | } |
||
534 | |||
535 | 457 | parent::invalidateCache(); |
|
536 | 457 | } |
|
537 | } |
||
538 |