diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index e1c15fe..4640148 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -16,6 +16,7 @@ use Drupal\Core\Lock\DatabaseLockBackend; use Drupal\Core\Lock\LockBackendInterface; use Drupal\user\Plugin\Core\Entity\User; +use Drupal\Core\Entity\EntityBCDecorator; /** * @file @@ -2055,7 +2056,9 @@ function drupal_anonymous_user() { DRUPAL_ANONYMOUS_RID => DRUPAL_ANONYMOUS_RID, ), ); - return new User($values, 'user'); + // @todo: This is really ugly but not sure how to change it. + $definitions = array(); + return new EntityBCDecorator(new User($values, 'user'), $definitions); } /** diff --git a/core/includes/errors.inc b/core/includes/errors.inc index 5fc4b7d..7bd6629 100644 --- a/core/includes/errors.inc +++ b/core/includes/errors.inc @@ -153,6 +153,7 @@ function _drupal_render_exception_safe($exception) { * TRUE if an error should be displayed. */ function error_displayable($error = NULL) { + return TRUE; $error_level = config('system.logging')->get('error_level'); $updating = (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update'); $all_errors_displayed = ($error_level == ERROR_REPORTING_DISPLAY_ALL) || diff --git a/core/includes/session.inc b/core/includes/session.inc index 31e67a6..07a8480 100644 --- a/core/includes/session.inc +++ b/core/includes/session.inc @@ -80,7 +80,13 @@ function _drupal_session_read($sid) { // cookies (eg. web crawlers). $insecure_session_name = substr(session_name(), 1); if (!isset($_COOKIE[session_name()]) && !isset($_COOKIE[$insecure_session_name])) { - $user = drupal_anonymous_user(); + $user = (object)array( + 'uid' => 0, + 'hostname' => ip_address(), + 'roles' => array( + DRUPAL_ANONYMOUS_RID => DRUPAL_ANONYMOUS_RID, + ), + ); return ''; } @@ -113,14 +119,26 @@ function _drupal_session_read($sid) { elseif ($user) { // The user is anonymous or blocked. Only preserve two fields from the // {sessions} table. - $account = drupal_anonymous_user(); + $account = (object)array( + 'uid' => 0, + 'hostname' => ip_address(), + 'roles' => array( + DRUPAL_ANONYMOUS_RID => DRUPAL_ANONYMOUS_RID, + ), + ); $account->session = $user->session; $account->timestamp = $user->timestamp; $user = $account; } else { // The session has expired. - $user = drupal_anonymous_user(); + $user = (object)array( + 'uid' => 0, + 'hostname' => ip_address(), + 'roles' => array( + DRUPAL_ANONYMOUS_RID => DRUPAL_ANONYMOUS_RID, + ), + ); $user->session = ''; } @@ -255,7 +273,13 @@ function drupal_session_initialize() { // processes (like drupal_get_token()) needs to know the future // session ID in advance. $GLOBALS['lazy_session'] = TRUE; - $user = drupal_anonymous_user(); + $user = (object) array( + 'uid' => 0, + 'hostname' => ip_address(), + 'roles' => array( + DRUPAL_ANONYMOUS_RID => DRUPAL_ANONYMOUS_RID, + ), + ); // Less random sessions (which are much faster to generate) are used for // anonymous users than are generated in drupal_session_regenerate() when // a user becomes authenticated. @@ -433,7 +457,13 @@ function _drupal_session_destroy($sid) { // Reset $_SESSION and $user to prevent a new session from being started // in drupal_session_commit(). $_SESSION = array(); - $user = drupal_anonymous_user(); + $user = (object) array( + 'uid' => 0, + 'hostname' => ip_address(), + 'roles' => array( + DRUPAL_ANONYMOUS_RID => DRUPAL_ANONYMOUS_RID, + ), + ); // Unset the session cookies. _drupal_session_delete_cookie(session_name()); diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php index 08be87c..d3a58cf 100644 --- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php +++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php @@ -90,6 +90,16 @@ public function &__get($name) { return $this->decorated->values[$name]; } + // @todo: The EntityBCDecorator tries to be too intelligent and returns + // a string but we actually want an array for roles. + if ($name == 'roles') { + $roles = array(); + foreach ($this->getOriginalEntity()->roles as $role) { + $roles[] = $role->value; + } + return $roles; + } + // We access the protected 'values' and 'fields' properties of the decorated // entity via the magic getter - which returns them by reference for us. We // do so, as providing references to these arrays would make $entity->values diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index dd87b29..8b572e2 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -1611,7 +1611,7 @@ function comment_prepare_author(Comment $comment) { if (!$account) { $account = entity_create('user', array('uid' => 0, 'name' => $comment->name->value, 'homepage' => $comment->homepage->value)); } - return $account; + return $account->getBCEntity(); } /** diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index 5cca38a..a6684c3 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -480,7 +480,7 @@ protected function drupalCreateUser(array $permissions = array(), $name = NULL) $edit['pass'] = user_password(); $edit['status'] = 1; if ($rid) { - $edit['roles'] = array($rid => $rid); + $edit['roles'] = array($rid); } $account = entity_create('user', $edit); diff --git a/core/modules/update/update.install b/core/modules/update/update.install index 2d4ec4b..3fea641 100644 --- a/core/modules/update/update.install +++ b/core/modules/update/update.install @@ -72,7 +72,7 @@ function update_uninstall() { variable_del('update_last_check'); variable_del('update_last_email_notification'); - $queue = queue('update_fetch_tasks'); + $queue = Drupal::queue('update_fetch_tasks'); $queue->deleteQueue(); } diff --git a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php index fb7cbbb..4217f70 100644 --- a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php +++ b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php @@ -7,7 +7,7 @@ namespace Drupal\user\Plugin\Core\Entity; -use Drupal\Core\Entity\Entity; +use Drupal\Core\Entity\EntityNG; use Drupal\Component\Annotation\Plugin; use Drupal\Core\Annotation\Translation; @@ -38,7 +38,7 @@ * } * ) */ -class User extends Entity { +class User extends EntityNG { /** * The user ID. @@ -59,7 +59,7 @@ class User extends Entity { * * @var string */ - public $name = ''; + public $name; /** * The user's password (hashed). @@ -73,7 +73,7 @@ class User extends Entity { * * @var string */ - public $mail = ''; + public $mail; /** * The user's default theme. @@ -109,7 +109,7 @@ class User extends Entity { * * @var integer */ - public $access = 0; + public $access; /** * The timestamp when the user last logged in. A value of 0 means the user has @@ -117,14 +117,14 @@ class User extends Entity { * * @var integer */ - public $login = 0; + public $login; /** * Whether the user is active (1) or blocked (0). * * @var integer */ - public $status = 1; + public $status; /** * The user's timezone. @@ -138,40 +138,84 @@ class User extends Entity { * * @var string */ - public $langcode = LANGUAGE_NOT_SPECIFIED; + public $langcode; /** * The user's preferred langcode for receiving emails and viewing the site. * * @var string */ - public $preferred_langcode = LANGUAGE_NOT_SPECIFIED; + public $preferred_langcode; /** * The user's preferred langcode for viewing administration pages. * * @var string */ - public $preferred_admin_langcode = LANGUAGE_NOT_SPECIFIED; + public $preferred_admin_langcode; /** * The email address used for initial account creation. * * @var string */ - public $init = ''; + public $init; /** * The user's roles. * * @var array */ - public $roles = array(); + public $roles; + + /** + * The plain data values of the contained properties. + * + * Define default values. + * + * @var array + */ + protected $values = array( + 'langcode' => array(LANGUAGE_DEFAULT => array(0 => array('value' => LANGUAGE_NOT_SPECIFIED))), + 'preferred_langcode' => array(LANGUAGE_DEFAULT => array(0 => array('value' => LANGUAGE_NOT_SPECIFIED))), + 'admin_preffered_langcode' => array(LANGUAGE_DEFAULT => array(0 => array('value' => LANGUAGE_NOT_SPECIFIED))), + 'name' => array(LANGUAGE_DEFAULT => array(0 => array('value' => ''))), + 'mail' => array(LANGUAGE_DEFAULT => array(0 => array('value' => ''))), + 'init' => array(LANGUAGE_DEFAULT => array(0 => array('value' => ''))), + 'access' => array(LANGUAGE_DEFAULT => array(0 => array('value' => 0))), + 'login' => array(LANGUAGE_DEFAULT => array(0 => array('value' => 0))), + 'status' => array(LANGUAGE_DEFAULT => array(0 => array('value' => 1))), + ); /** * Implements Drupal\Core\Entity\EntityInterface::id(). */ public function id() { - return $this->uid; + return $this->get('uid')->value; + } + + protected function init() { + parent::init(); + unset($this->access); + unset($this->created); + unset($this->init); + unset($this->login); + unset($this->mail); + unset($this->name); + unset($this->pass); + unset($this->preferred_admin_langcode); + unset($this->preferred_langcode); + unset($this->roles); + unset($this->signature); + unset($this->signature_format); + unset($this->status); + unset($this->theme); + unset($this->timezone); + unset($this->uid); + unset($this->uuid); + } + + public function &__get($name) { + return parent::__get($name); } } diff --git a/core/modules/user/lib/Drupal/user/UserAccessController.php b/core/modules/user/lib/Drupal/user/UserAccessController.php index 13b8c6b..aac9da0 100644 --- a/core/modules/user/lib/Drupal/user/UserAccessController.php +++ b/core/modules/user/lib/Drupal/user/UserAccessController.php @@ -20,7 +20,7 @@ class UserAccessController extends EntityAccessController { * Implements EntityAccessControllerInterface::viewAccess(). */ public function viewAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) { - $uid = $entity->uid; + $uid = $entity->uid->value; if (!$account) { $account = $GLOBALS['user']; } @@ -33,7 +33,7 @@ public function viewAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT } elseif (user_access('access user profiles', $account)) { // Only allow view access if the account is active. - return $entity->status; + return $entity->status->value; } } return FALSE; @@ -55,7 +55,7 @@ public function updateAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAU } // Users can always edit their own account. Users with the 'administer // users' permission can edit any account except the anonymous account. - return (($account->uid == $entity->uid) || user_access('administer users', $account)) && $entity->uid > 0; + return (($account->uid == $entity->uid->value) || user_access('administer users', $account)) && $entity->uid->value > 0; } /** @@ -68,7 +68,7 @@ public function deleteAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAU // Users with 'cancel account' permission can cancel their own account, // users with 'administer users' permission can cancel any account except // the anonymous account. - return ((($account->uid == $entity->uid) && user_access('cancel account', $account)) || user_access('administer users', $account)) && $entity->uid > 0; + return ((($account->uid == $entity->uid->value) && user_access('cancel account', $account)) || user_access('administer users', $account)) && $entity->uid->value > 0; } } diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php index 3d8e981..b0eef51 100644 --- a/core/modules/user/lib/Drupal/user/UserStorageController.php +++ b/core/modules/user/lib/Drupal/user/UserStorageController.php @@ -9,7 +9,7 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityMalformedException; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\DatabaseStorageControllerNG; /** * Controller class for users. @@ -17,7 +17,7 @@ * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding * required special handling for user objects. */ -class UserStorageController extends DatabaseStorageController { +class UserStorageController extends DatabaseStorageControllerNG { /** * Overrides Drupal\Core\Entity\DatabaseStorageController::attachLoad(). @@ -52,17 +52,17 @@ public function create(array $values) { $values['created'] = REQUEST_TIME; } // Users always have the authenticated user role. - $values['roles'][DRUPAL_AUTHENTICATED_RID] = DRUPAL_AUTHENTICATED_RID; + $values['roles'][] = DRUPAL_AUTHENTICATED_RID; - return parent::create($values); + return parent::create($values)->getBCEntity(); } /** * Overrides Drupal\Core\Entity\DatabaseStorageController::save(). */ public function save(EntityInterface $entity) { - if (empty($entity->uid)) { - $entity->uid = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField()); + if (!$entity->uid->value) { + $entity->uid->value = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField()); $entity->enforceIsNew(); } parent::save($entity); @@ -73,11 +73,11 @@ public function save(EntityInterface $entity) { */ protected function preSave(EntityInterface $entity) { // Update the user password if it has changed. - if ($entity->isNew() || (!empty($entity->pass) && $entity->pass != $entity->original->pass)) { + if ($entity->isNew() || ($entity->pass->value && $entity->pass->value != $entity->original->pass->value)) { // Allow alternate password hashing schemes. - $entity->pass = drupal_container()->get('password')->hash(trim($entity->pass)); + $entity->pass->value = drupal_container()->get('password')->hash(trim($entity->pass->value)); // Abort if the hashing failed and returned FALSE. - if (!$entity->pass) { + if (!$entity->pass->value) { throw new EntityMalformedException('The entity does not have a password.'); } } @@ -85,14 +85,14 @@ protected function preSave(EntityInterface $entity) { if (!$entity->isNew()) { // If the password is empty, that means it was not changed, so use the // original password. - if (empty($entity->pass)) { - $entity->pass = $entity->original->pass; + if (empty($entity->pass->value)) { + $entity->pass->value = $entity->original->pass->value; } } // Prepare user roles. if (isset($entity->roles)) { - $entity->roles = array_filter($entity->roles); + //$entity->roles = array_filter($entity->roles); } // Store account cancellation information. @@ -111,28 +111,28 @@ protected function postSave(EntityInterface $entity, $update) { if ($update) { // If the password has been changed, delete all open sessions for the // user and recreate the current one. - if ($entity->pass != $entity->original->pass) { - drupal_session_destroy_uid($entity->uid); - if ($entity->uid == $GLOBALS['user']->uid) { + if ($entity->pass->value != $entity->original->pass->value) { + drupal_session_destroy_uid($entity->id()); + if ($entity->uid->value == $GLOBALS['user']->uid) { drupal_session_regenerate(); } } // Remove roles that are no longer enabled for the user. - $entity->roles = array_filter($entity->roles); + //$entity->roles = array_filter($entity->roles); // Reload user roles if provided. - if ($entity->roles != $entity->original->roles) { + if ($entity->roles->getValue() != $entity->original->roles->getValue()) { db_delete('users_roles') - ->condition('uid', $entity->uid) + ->condition('uid', $entity->id()) ->execute(); $query = db_insert('users_roles')->fields(array('uid', 'rid')); - foreach (array_keys($entity->roles) as $rid) { - if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { + foreach ($entity->roles as $role) { + if (!in_array($role->value, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { $query->values(array( - 'uid' => $entity->uid, - 'rid' => $rid, + 'uid' => $entity->id(), + 'rid' => $role->value, )); } } @@ -140,14 +140,14 @@ protected function postSave(EntityInterface $entity, $update) { } // If the user was blocked, delete the user's sessions to force a logout. - if ($entity->original->status != $entity->status && $entity->status == 0) { - drupal_session_destroy_uid($entity->uid); + if ($entity->original->status->value != $entity->status->value && $entity->status->value == 0) { + drupal_session_destroy_uid($entity->id()); } // Send emails after we have the new user object. - if ($entity->status != $entity->original->status) { + if ($entity->status->value != $entity->original->status->value) { // The user's status is changing; conditionally send notification email. - $op = $entity->status == 1 ? 'status_activated' : 'status_blocked'; + $op = $entity->status->value == 1 ? 'status_activated' : 'status_blocked'; _user_mail_notify($op, $entity); } } @@ -155,11 +155,11 @@ protected function postSave(EntityInterface $entity, $update) { // Save user roles. if (count($entity->roles) > 1) { $query = db_insert('users_roles')->fields(array('uid', 'rid')); - foreach (array_keys($entity->roles) as $rid) { - if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { + foreach ($entity->roles as $role) { + if (!in_array($role->value, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { $query->values(array( - 'uid' => $entity->uid, - 'rid' => $rid, + 'uid' => $entity->id(), + 'rid' => $role->value, )); } } @@ -177,4 +177,123 @@ protected function postDelete($entities) { ->execute(); drupal_container()->get('user.data')->delete(NULL, array_keys($entities)); } + + /** + * Overrides \Drupal\Core\Entity\DataBaseStorageControllerNG::invokeHook(). + */ + protected function invokeHook($hook, EntityInterface $entity) { + $function = 'field_attach_' . $hook; + // @todo: field_attach_delete_revision() is named the wrong way round, + // consider renaming it. + if ($function == 'field_attach_revision_delete') { + $function = 'field_attach_delete_revision'; + } + if (!empty($this->entityInfo['fieldable']) && function_exists($function)) { + $function($entity->getBCEntity()); + } + + // Invoke the hook. + module_invoke_all($this->entityType . '_' . $hook, $entity->getBCEntity()); + // Invoke the respective entity-level hook. + module_invoke_all('entity_' . $hook, $entity->getBCEntity(), $this->entityType); + } + + /** + * Overrides \Drupal\Core\Entity\DataBaseStorageControllerNG::baseFieldDefinitions(). + */ + public function baseFieldDefinitions() { + $properties['uid'] = array( + 'label' => t('User ID'), + 'description' => t('The user ID.'), + 'type' => 'integer_field', + 'read-only' => TRUE, + ); + $properties['uuid'] = array( + 'label' => t('UUID'), + 'description' => t('The user UUID.'), + 'type' => 'string_field', + 'read-only' => TRUE, + ); + $properties['langcode'] = array( + 'label' => t('Language code'), + 'description' => t('The user language code.'), + 'type' => 'language_field', + ); + $properties['preferred_langcode'] = array( + 'label' => t('Language code'), + 'description' => t("The user's preferred langcode for receiving emails and viewing the site."), + 'type' => 'language_field', + ); + $properties['preferred_admin_langcode'] = array( + 'label' => t('Language code'), + 'description' => t("The user's preferred langcode for viewing administration pages."), + 'type' => 'language_field', + ); + $properties['name'] = array( + 'label' => t('Name'), + 'description' => t('The name of this user'), + 'type' => 'string_field', + ); + $properties['pass'] = array( + 'label' => t('Name'), + 'description' => t('The password of this user (hashed)'), + 'type' => 'string_field', + ); + $properties['mail'] = array( + 'label' => t('Name'), + 'description' => t('The e-mail of this user'), + 'type' => 'string_field', + ); + $properties['signature'] = array( + 'label' => t('Name'), + 'description' => t('The signature of this user'), + 'type' => 'string_field', + ); + $properties['signature_format'] = array( + 'label' => t('Name'), + 'description' => t('The signature format of this user'), + 'type' => 'string_field', + ); + $properties['theme'] = array( + 'label' => t('Theme'), + 'description' => t('The default theme of this user'), + 'type' => 'string_field', + ); + $properties['timezone'] = array( + 'label' => t('Timeone'), + 'description' => t('The timezone of this user'), + 'type' => 'string_field', + ); + $properties['status'] = array( + 'label' => t('User status'), + 'description' => t('Whether the user is active (1) or blocked (0).'), + 'type' => 'boolean_field', + ); + $properties['created'] = array( + 'label' => t('Created'), + 'description' => t('The time that the node was created.'), + 'type' => 'integer_field', + ); + $properties['access'] = array( + 'label' => t('Last access'), + 'description' => t('The time that the user last accessed the site.'), + 'type' => 'integer_field', + ); + $properties['login'] = array( + 'label' => t('Last login'), + 'description' => t('The time that the user last logged in.'), + 'type' => 'integer_field', + ); + $properties['init'] = array( + 'label' => t('Init'), + 'description' => t('The email address used for initial account creation.'), + 'type' => 'string_field', + ); + $properties['roles'] = array( + 'label' => t('Roles'), + 'description' => t('The roles the user has.'), + 'type' => 'string_field', + ); + return $properties; + } } diff --git a/core/modules/user/user.module b/core/modules/user/user.module index bdf5862..1faa9ce 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -156,7 +156,7 @@ function user_entity_bundle_info() { */ function user_uri($user) { return array( - 'path' => 'user/' . $user->uid, + 'path' => 'user/' . $user->id(), ); } @@ -293,7 +293,12 @@ function user_field_extra_fields() { * @see \Drupal\Core\Entity\Query\QueryInterface */ function user_load_multiple(array $uids = NULL, $reset = FALSE) { - return entity_load_multiple('user', $uids, $reset); + $entities = entity_load_multiple('user', $uids, $reset); + // Return BC-entities. + foreach ($entities as $id => $entity) { + $entities[$id] = $entity->getBCEntity(); + } + return $entities; } /** @@ -321,7 +326,8 @@ function user_load_multiple(array $uids = NULL, $reset = FALSE) { * @see user_load_multiple() */ function user_load($uid, $reset = FALSE) { - return entity_load('user', $uid, $reset); + $user = entity_load('user', $uid, $reset); + return $user ? $user->getBCEntity() : FALSE; } /** @@ -337,7 +343,7 @@ function user_load($uid, $reset = FALSE) { */ function user_load_by_mail($mail) { $users = entity_load_multiple_by_properties('user', array('mail' => $mail)); - return reset($users); + return reset($users)->getBCEntity(); } /** @@ -353,7 +359,7 @@ function user_load_by_mail($mail) { */ function user_load_by_name($name) { $users = entity_load_multiple_by_properties('user', array('name' => $name)); - return reset($users); + return reset($users)->getBCEntity(); } /** @@ -623,7 +629,7 @@ function user_search_execute($keys = NULL, $conditions = NULL) { /** * Implements hook_user_view(). */ -function user_user_view(User $account, EntityDisplay $display) { +function user_user_view(EntityInterface $account, EntityDisplay $display) { if ($display->getComponent('member_for')) { $account->content['member_for'] = array( '#type' => 'item', @@ -1736,7 +1742,7 @@ function user_mail($key, &$message, $params) { // allows the configuration objects to be localized for the user's language if // the locale module is enabled. $user_config_context = config_context_enter('Drupal\user\UserConfigContext'); - $user_config_context->setAccount($params['account']); + $user_config_context->setAccount($params['account']->getOriginalEntity()); $mail_config = config('user.mail'); // We do not sanitize the token replacement, since the output of this