comparison core/modules/user/src/Entity/User.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
1 <?php
2
3 namespace Drupal\user\Entity;
4
5 use Drupal\Core\Entity\ContentEntityBase;
6 use Drupal\Core\Entity\EntityChangedTrait;
7 use Drupal\Core\Entity\EntityStorageInterface;
8 use Drupal\Core\Entity\EntityTypeInterface;
9 use Drupal\Core\Field\BaseFieldDefinition;
10 use Drupal\Core\Language\LanguageInterface;
11 use Drupal\user\RoleInterface;
12 use Drupal\user\UserInterface;
13
14 /**
15 * Defines the user entity class.
16 *
17 * The base table name here is plural, despite Drupal table naming standards,
18 * because "user" is a reserved word in many databases.
19 *
20 * @ContentEntityType(
21 * id = "user",
22 * label = @Translation("User"),
23 * handlers = {
24 * "storage" = "Drupal\user\UserStorage",
25 * "storage_schema" = "Drupal\user\UserStorageSchema",
26 * "access" = "Drupal\user\UserAccessControlHandler",
27 * "list_builder" = "Drupal\user\UserListBuilder",
28 * "views_data" = "Drupal\user\UserViewsData",
29 * "route_provider" = {
30 * "html" = "Drupal\user\Entity\UserRouteProvider",
31 * },
32 * "form" = {
33 * "default" = "Drupal\user\ProfileForm",
34 * "cancel" = "Drupal\user\Form\UserCancelForm",
35 * "register" = "Drupal\user\RegisterForm"
36 * },
37 * "translation" = "Drupal\user\ProfileTranslationHandler"
38 * },
39 * admin_permission = "administer users",
40 * base_table = "users",
41 * data_table = "users_field_data",
42 * label_callback = "user_format_name",
43 * translatable = TRUE,
44 * entity_keys = {
45 * "id" = "uid",
46 * "langcode" = "langcode",
47 * "uuid" = "uuid"
48 * },
49 * links = {
50 * "canonical" = "/user/{user}",
51 * "edit-form" = "/user/{user}/edit",
52 * "cancel-form" = "/user/{user}/cancel",
53 * "collection" = "/admin/people",
54 * },
55 * field_ui_base_route = "entity.user.admin_form",
56 * common_reference_target = TRUE
57 * )
58 */
59 class User extends ContentEntityBase implements UserInterface {
60
61 use EntityChangedTrait;
62
63 /**
64 * Stores a reference for a reusable anonymous user entity.
65 *
66 * @var \Drupal\user\UserInterface
67 */
68 protected static $anonymousUser;
69
70 /**
71 * {@inheritdoc}
72 */
73 public function isNew() {
74 return !empty($this->enforceIsNew) || $this->id() === NULL;
75 }
76
77 /**
78 * {@inheritdoc}
79 */
80 public function preSave(EntityStorageInterface $storage) {
81 parent::preSave($storage);
82
83 // Make sure that the authenticated/anonymous roles are not persisted.
84 foreach ($this->get('roles') as $index => $item) {
85 if (in_array($item->target_id, [RoleInterface::ANONYMOUS_ID, RoleInterface::AUTHENTICATED_ID])) {
86 $this->get('roles')->offsetUnset($index);
87 }
88 }
89
90 // Store account cancellation information.
91 foreach (['user_cancel_method', 'user_cancel_notify'] as $key) {
92 if (isset($this->{$key})) {
93 \Drupal::service('user.data')->set('user', $this->id(), substr($key, 5), $this->{$key});
94 }
95 }
96 }
97
98 /**
99 * {@inheritdoc}
100 */
101 public function postSave(EntityStorageInterface $storage, $update = TRUE) {
102 parent::postSave($storage, $update);
103
104 if ($update) {
105 $session_manager = \Drupal::service('session_manager');
106 // If the password has been changed, delete all open sessions for the
107 // user and recreate the current one.
108 if ($this->pass->value != $this->original->pass->value) {
109 $session_manager->delete($this->id());
110 if ($this->id() == \Drupal::currentUser()->id()) {
111 \Drupal::service('session')->migrate();
112 }
113 }
114
115 // If the user was blocked, delete the user's sessions to force a logout.
116 if ($this->original->status->value != $this->status->value && $this->status->value == 0) {
117 $session_manager->delete($this->id());
118 }
119
120 // Send emails after we have the new user object.
121 if ($this->status->value != $this->original->status->value) {
122 // The user's status is changing; conditionally send notification email.
123 $op = $this->status->value == 1 ? 'status_activated' : 'status_blocked';
124 _user_mail_notify($op, $this);
125 }
126 }
127 }
128
129 /**
130 * {@inheritdoc}
131 */
132 public static function postDelete(EntityStorageInterface $storage, array $entities) {
133 parent::postDelete($storage, $entities);
134
135 $uids = array_keys($entities);
136 \Drupal::service('user.data')->delete(NULL, $uids);
137 }
138
139 /**
140 * {@inheritdoc}
141 */
142 public function getRoles($exclude_locked_roles = FALSE) {
143 $roles = [];
144
145 // Users with an ID always have the authenticated user role.
146 if (!$exclude_locked_roles) {
147 if ($this->isAuthenticated()) {
148 $roles[] = RoleInterface::AUTHENTICATED_ID;
149 }
150 else {
151 $roles[] = RoleInterface::ANONYMOUS_ID;
152 }
153 }
154
155 foreach ($this->get('roles') as $role) {
156 if ($role->target_id) {
157 $roles[] = $role->target_id;
158 }
159 }
160
161 return $roles;
162 }
163
164 /**
165 * {@inheritdoc}
166 */
167 public function hasRole($rid) {
168 return in_array($rid, $this->getRoles());
169 }
170
171 /**
172 * {@inheritdoc}
173 */
174 public function addRole($rid) {
175
176 if (in_array($rid, [RoleInterface::AUTHENTICATED_ID, RoleInterface::ANONYMOUS_ID])) {
177 throw new \InvalidArgumentException('Anonymous or authenticated role ID must not be assigned manually.');
178 }
179
180 $roles = $this->getRoles(TRUE);
181 $roles[] = $rid;
182 $this->set('roles', array_unique($roles));
183 }
184
185 /**
186 * {@inheritdoc}
187 */
188 public function removeRole($rid) {
189 $this->set('roles', array_diff($this->getRoles(TRUE), [$rid]));
190 }
191
192 /**
193 * {@inheritdoc}
194 */
195 public function hasPermission($permission) {
196 // User #1 has all privileges.
197 if ((int) $this->id() === 1) {
198 return TRUE;
199 }
200
201 return $this->getRoleStorage()->isPermissionInRoles($permission, $this->getRoles());
202 }
203
204 /**
205 * {@inheritdoc}
206 */
207 public function getPassword() {
208 return $this->get('pass')->value;
209 }
210
211 /**
212 * {@inheritdoc}
213 */
214 public function setPassword($password) {
215 $this->get('pass')->value = $password;
216 return $this;
217 }
218
219 /**
220 * {@inheritdoc}
221 */
222 public function getEmail() {
223 return $this->get('mail')->value;
224 }
225
226 /**
227 * {@inheritdoc}
228 */
229 public function setEmail($mail) {
230 $this->get('mail')->value = $mail;
231 return $this;
232 }
233
234 /**
235 * {@inheritdoc}
236 */
237 public function getCreatedTime() {
238 return $this->get('created')->value;
239 }
240
241 /**
242 * {@inheritdoc}
243 */
244 public function getLastAccessedTime() {
245 return $this->get('access')->value;
246 }
247
248 /**
249 * {@inheritdoc}
250 */
251 public function setLastAccessTime($timestamp) {
252 $this->get('access')->value = $timestamp;
253 return $this;
254 }
255
256 /**
257 * {@inheritdoc}
258 */
259 public function getLastLoginTime() {
260 return $this->get('login')->value;
261 }
262
263 /**
264 * {@inheritdoc}
265 */
266 public function setLastLoginTime($timestamp) {
267 $this->get('login')->value = $timestamp;
268 return $this;
269 }
270
271 /**
272 * {@inheritdoc}
273 */
274 public function isActive() {
275 return $this->get('status')->value == 1;
276 }
277
278 /**
279 * {@inheritdoc}
280 */
281 public function isBlocked() {
282 return $this->get('status')->value == 0;
283 }
284
285 /**
286 * {@inheritdoc}
287 */
288 public function activate() {
289 $this->get('status')->value = 1;
290 return $this;
291 }
292
293 /**
294 * {@inheritdoc}
295 */
296 public function block() {
297 $this->get('status')->value = 0;
298 return $this;
299 }
300
301 /**
302 * {@inheritdoc}
303 */
304 public function getTimeZone() {
305 return $this->get('timezone')->value;
306 }
307
308 /**
309 * {@inheritdoc}
310 */
311 public function getPreferredLangcode($fallback_to_default = TRUE) {
312 $language_list = $this->languageManager()->getLanguages();
313 $preferred_langcode = $this->get('preferred_langcode')->value;
314 if (!empty($preferred_langcode) && isset($language_list[$preferred_langcode])) {
315 return $language_list[$preferred_langcode]->getId();
316 }
317 else {
318 return $fallback_to_default ? $this->languageManager()->getDefaultLanguage()->getId() : '';
319 }
320 }
321
322 /**
323 * {@inheritdoc}
324 */
325 public function getPreferredAdminLangcode($fallback_to_default = TRUE) {
326 $language_list = $this->languageManager()->getLanguages();
327 $preferred_langcode = $this->get('preferred_admin_langcode')->value;
328 if (!empty($preferred_langcode) && isset($language_list[$preferred_langcode])) {
329 return $language_list[$preferred_langcode]->getId();
330 }
331 else {
332 return $fallback_to_default ? $this->languageManager()->getDefaultLanguage()->getId() : '';
333 }
334 }
335
336 /**
337 * {@inheritdoc}
338 */
339 public function getInitialEmail() {
340 return $this->get('init')->value;
341 }
342
343 /**
344 * {@inheritdoc}
345 */
346 public function isAuthenticated() {
347 return $this->id() > 0;
348 }
349 /**
350 * {@inheritdoc}
351 */
352 public function isAnonymous() {
353 return $this->id() == 0;
354 }
355
356 /**
357 * {@inheritdoc}
358 */
359 public function getUsername() {
360 return $this->getAccountName();
361 }
362
363 /**
364 * {@inheritdoc}
365 */
366 public function getAccountName() {
367 return $this->get('name')->value ?: '';
368 }
369
370 /**
371 * {@inheritdoc}
372 */
373 public function getDisplayName() {
374 $name = $this->getAccountName() ?: \Drupal::config('user.settings')->get('anonymous');
375 \Drupal::moduleHandler()->alter('user_format_name', $name, $this);
376 return $name;
377 }
378
379 /**
380 * {@inheritdoc}
381 */
382 public function setUsername($username) {
383 $this->set('name', $username);
384 return $this;
385 }
386
387 /**
388 * {@inheritdoc}
389 */
390 public function setExistingPassword($password) {
391 $this->get('pass')->existing = $password;
392 }
393
394 /**
395 * {@inheritdoc}
396 */
397 public function checkExistingPassword(UserInterface $account_unchanged) {
398 return strlen($this->get('pass')->existing) > 0 && \Drupal::service('password')->check(trim($this->get('pass')->existing), $account_unchanged->getPassword());
399 }
400
401 /**
402 * Returns an anonymous user entity.
403 *
404 * @return \Drupal\user\UserInterface
405 * An anonymous user entity.
406 */
407 public static function getAnonymousUser() {
408 if (!isset(static::$anonymousUser)) {
409
410 // @todo Use the entity factory once available, see
411 // https://www.drupal.org/node/1867228.
412 $entity_manager = \Drupal::entityManager();
413 $entity_type = $entity_manager->getDefinition('user');
414 $class = $entity_type->getClass();
415
416 static::$anonymousUser = new $class([
417 'uid' => [LanguageInterface::LANGCODE_DEFAULT => 0],
418 'name' => [LanguageInterface::LANGCODE_DEFAULT => ''],
419 // Explicitly set the langcode to ensure that field definitions do not
420 // need to be fetched to figure out a default.
421 'langcode' => [LanguageInterface::LANGCODE_DEFAULT => LanguageInterface::LANGCODE_NOT_SPECIFIED]
422 ], $entity_type->id());
423 }
424 return clone static::$anonymousUser;
425 }
426
427 /**
428 * {@inheritdoc}
429 */
430 public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
431 /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
432 $fields = parent::baseFieldDefinitions($entity_type);
433
434 $fields['uid']->setLabel(t('User ID'))
435 ->setDescription(t('The user ID.'));
436
437 $fields['uuid']->setDescription(t('The user UUID.'));
438
439 $fields['langcode']->setLabel(t('Language code'))
440 ->setDescription(t('The user language code.'))
441 ->setDisplayOptions('form', ['region' => 'hidden']);
442
443 $fields['preferred_langcode'] = BaseFieldDefinition::create('language')
444 ->setLabel(t('Preferred language code'))
445 ->setDescription(t("The user's preferred language code for receiving emails and viewing the site."))
446 // @todo: Define this via an options provider once
447 // https://www.drupal.org/node/2329937 is completed.
448 ->addPropertyConstraints('value', [
449 'AllowedValues' => ['callback' => __CLASS__ . '::getAllowedConfigurableLanguageCodes'],
450 ]);
451
452 $fields['preferred_admin_langcode'] = BaseFieldDefinition::create('language')
453 ->setLabel(t('Preferred admin language code'))
454 ->setDescription(t("The user's preferred language code for viewing administration pages."))
455 // @todo: A default value of NULL is ignored, so we have to specify
456 // an empty field item structure instead. Fix this in
457 // https://www.drupal.org/node/2318605.
458 ->setDefaultValue([0 => ['value' => NULL]])
459 // @todo: Define this via an options provider once
460 // https://www.drupal.org/node/2329937 is completed.
461 ->addPropertyConstraints('value', [
462 'AllowedValues' => ['callback' => __CLASS__ . '::getAllowedConfigurableLanguageCodes'],
463 ]);
464
465 // The name should not vary per language. The username is the visual
466 // identifier for a user and needs to be consistent in all languages.
467 $fields['name'] = BaseFieldDefinition::create('string')
468 ->setLabel(t('Name'))
469 ->setDescription(t('The name of this user.'))
470 ->setRequired(TRUE)
471 ->setConstraints([
472 // No Length constraint here because the UserName constraint also covers
473 // that.
474 'UserName' => [],
475 'UserNameUnique' => [],
476 ]);
477 $fields['name']->getItemDefinition()->setClass('\Drupal\user\UserNameItem');
478
479 $fields['pass'] = BaseFieldDefinition::create('password')
480 ->setLabel(t('Password'))
481 ->setDescription(t('The password of this user (hashed).'))
482 ->addConstraint('ProtectedUserField');
483
484 $fields['mail'] = BaseFieldDefinition::create('email')
485 ->setLabel(t('Email'))
486 ->setDescription(t('The email of this user.'))
487 ->setDefaultValue('')
488 ->addConstraint('UserMailUnique')
489 ->addConstraint('UserMailRequired')
490 ->addConstraint('ProtectedUserField');
491
492 $fields['timezone'] = BaseFieldDefinition::create('string')
493 ->setLabel(t('Timezone'))
494 ->setDescription(t('The timezone of this user.'))
495 ->setSetting('max_length', 32)
496 // @todo: Define this via an options provider once
497 // https://www.drupal.org/node/2329937 is completed.
498 ->addPropertyConstraints('value', [
499 'AllowedValues' => ['callback' => __CLASS__ . '::getAllowedTimezones'],
500 ]);
501
502 $fields['status'] = BaseFieldDefinition::create('boolean')
503 ->setLabel(t('User status'))
504 ->setDescription(t('Whether the user is active or blocked.'))
505 ->setDefaultValue(FALSE);
506
507 $fields['created'] = BaseFieldDefinition::create('created')
508 ->setLabel(t('Created'))
509 ->setDescription(t('The time that the user was created.'));
510
511 $fields['changed'] = BaseFieldDefinition::create('changed')
512 ->setLabel(t('Changed'))
513 ->setDescription(t('The time that the user was last edited.'))
514 ->setTranslatable(TRUE);
515
516 $fields['access'] = BaseFieldDefinition::create('timestamp')
517 ->setLabel(t('Last access'))
518 ->setDescription(t('The time that the user last accessed the site.'))
519 ->setDefaultValue(0);
520
521 $fields['login'] = BaseFieldDefinition::create('timestamp')
522 ->setLabel(t('Last login'))
523 ->setDescription(t('The time that the user last logged in.'))
524 ->setDefaultValue(0);
525
526 $fields['init'] = BaseFieldDefinition::create('email')
527 ->setLabel(t('Initial email'))
528 ->setDescription(t('The email address used for initial account creation.'))
529 ->setDefaultValue('');
530
531 $fields['roles'] = BaseFieldDefinition::create('entity_reference')
532 ->setLabel(t('Roles'))
533 ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
534 ->setDescription(t('The roles the user has.'))
535 ->setSetting('target_type', 'user_role');
536
537 return $fields;
538 }
539
540 /**
541 * Returns the role storage object.
542 *
543 * @return \Drupal\user\RoleStorageInterface
544 * The role storage object.
545 */
546 protected function getRoleStorage() {
547 return \Drupal::entityManager()->getStorage('user_role');
548 }
549
550 /**
551 * Defines allowed timezones for the field's AllowedValues constraint.
552 *
553 * @return string[]
554 * The allowed values.
555 */
556 public static function getAllowedTimezones() {
557 return array_keys(system_time_zones());
558 }
559
560 /**
561 * Defines allowed configurable language codes for AllowedValues constraints.
562 *
563 * @return string[]
564 * The allowed values.
565 */
566 public static function getAllowedConfigurableLanguageCodes() {
567 return array_keys(\Drupal::languageManager()->getLanguages(LanguageInterface::STATE_CONFIGURABLE));
568 }
569
570 }