diff --git a/core/modules/user/src/Authentication/Provider/Cookie.php b/core/modules/user/src/Authentication/Provider/Cookie.php index 2f8624e..dd2b319 100644 --- a/core/modules/user/src/Authentication/Provider/Cookie.php +++ b/core/modules/user/src/Authentication/Provider/Cookie.php @@ -3,7 +3,7 @@ namespace Drupal\user\Authentication\Provider; use Drupal\Core\Authentication\AuthenticationProviderInterface; -use Drupal\Core\Database\Connection; +use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\UserSession; use Drupal\Core\Session\SessionConfigurationInterface; @@ -23,23 +23,23 @@ class Cookie implements AuthenticationProviderInterface { protected $sessionConfiguration; /** - * The database connection. + * The entity manager. * - * @var \Drupal\Core\Database\Connection + * @var \Drupal\Core\Entity\EntityManagerInterface */ - protected $connection; + protected $entityManager; /** * Constructs a new cookie authentication provider. * * @param \Drupal\Core\Session\SessionConfigurationInterface $session_configuration * The session configuration. - * @param \Drupal\Core\Database\Connection $connection - * The database connection. + * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager + * The entity manager. */ - public function __construct(SessionConfigurationInterface $session_configuration, Connection $connection) { + public function __construct(SessionConfigurationInterface $session_configuration, EntityManagerInterface $entity_manager) { $this->sessionConfiguration = $session_configuration; - $this->connection = $connection; + $this->entityManager = $entity_manager; } /** @@ -53,41 +53,14 @@ public function applies(Request $request) { * {@inheritdoc} */ public function authenticate(Request $request) { - return $this->getUserFromSession($request->getSession()); - } - - /** - * Returns the UserSession object for the given session. - * - * @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session - * The session. - * - * @return \Drupal\Core\Session\AccountInterface|NULL - * The UserSession object for the current user, or NULL if this is an - * anonymous session. - */ - protected function getUserFromSession(SessionInterface $session) { - if ($uid = $session->get('uid')) { - // @todo Load the User entity in SessionHandler so we don't need queries. - // @see https://www.drupal.org/node/2345611 - $values = $this->connection - ->query('SELECT * FROM {users_field_data} u WHERE u.uid = :uid AND u.default_langcode = 1', [':uid' => $uid]) - ->fetchAssoc(); - - // Check if the user data was found and the user is active. - if (!empty($values) && $values['status'] == 1) { - // Add the user's roles. - $rids = $this->connection - ->query('SELECT roles_target_id FROM {user__roles} WHERE entity_id = :uid', [':uid' => $values['uid']]) - ->fetchCol(); - $values['roles'] = array_merge([AccountInterface::AUTHENTICATED_ROLE], $rids); - - return new UserSession($values); + if ($uid = $request->getSession()->get('uid')) { + /** @var \Drupal\user\UserInterface $user */ + if ($user = $this->entityManager->getStorage('user')->load($uid)) { + if ($user->isActive()) { + return $user; + } } } - - // This is an anonymous session. - return NULL; } } diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php index 4896bad..0a6f97b 100644 --- a/core/modules/user/src/Entity/User.php +++ b/core/modules/user/src/Entity/User.php @@ -44,7 +44,8 @@ * entity_keys = { * "id" = "uid", * "langcode" = "langcode", - * "uuid" = "uuid" + * "uuid" = "uuid", + * "status" = "status" * }, * links = { * "canonical" = "/user/{user}", @@ -152,9 +153,22 @@ public function getRoles($exclude_locked_roles = FALSE) { } } - foreach ($this->get('roles') as $role) { - if ($role->target_id) { - $roles[] = $role->target_id; + // Optimize for the case where the field object has not been initialized + // yet, directly access the values. + if (!isset($this->fields['roles'])) { + if (isset($this->values['roles'][LanguageInterface::LANGCODE_DEFAULT][0])) { + foreach ($this->values['roles'][LanguageInterface::LANGCODE_DEFAULT] as $values) { + if (isset($values['target_id'])) { + $roles[] = $values['target_id']; + } + } + } + } + else { + foreach ($this->get('roles') as $role) { + if ($role->target_id) { + $roles[] = $role->target_id; + } } } @@ -242,7 +256,15 @@ public function getCreatedTime() { * {@inheritdoc} */ public function getLastAccessedTime() { - return $this->get('access')->value; + // Optimize for the case where the field object has not been initialized + // yet, directly access the value. + // @todo Use getFieldValue(), see https://www.drupal.org/node/2580551. + if (!isset($this->fields['access']) && isset($this->values['access'][LanguageInterface::LANGCODE_DEFAULT][0]['value'])) { + return $this->values['access'][LanguageInterface::LANGCODE_DEFAULT][0]['value']; + } + else { + return $this->get('access')->value; + } } /** @@ -272,14 +294,14 @@ public function setLastLoginTime($timestamp) { * {@inheritdoc} */ public function isActive() { - return $this->get('status')->value == 1; + return $this->getEntityKey('status') == 1; } /** * {@inheritdoc} */ public function isBlocked() { - return $this->get('status')->value == 0; + return $this->getEntityKey('status') == 0; } /** @@ -302,7 +324,15 @@ public function block() { * {@inheritdoc} */ public function getTimeZone() { - return $this->get('timezone')->value; + // Optimize for the case where the field object has not been initialized + // yet, directly access the value. + // @todo Use getFieldValue(), see https://www.drupal.org/node/2580551. + if (!isset($this->fields['timezone']) && isset($this->values['timezone'][LanguageInterface::LANGCODE_DEFAULT][0]['value'])) { + return $this->values['timezone'][LanguageInterface::LANGCODE_DEFAULT][0]['value']; + } + else { + return $this->get('timezone')->value; + } } /** @@ -364,7 +394,16 @@ public function getUsername() { * {@inheritdoc} */ public function getAccountName() { - return $this->get('name')->value ?: ''; + // Optimize for the case where the field object has not been initialized + // yet, directly access the value. + // @todo Use getFieldValue(), see https://www.drupal.org/node/2580551. + if (!isset($this->fields['name']) && isset($this->values['name'][LanguageInterface::LANGCODE_DEFAULT][0]['value'])) { + return $this->values['name'][LanguageInterface::LANGCODE_DEFAULT][0]['value']; + } + else { + return $this->get('name')->value; + } + return ''; } /** diff --git a/core/modules/user/tests/src/Unit/Plugin/Core/Entity/UserTest.php b/core/modules/user/tests/src/Unit/Plugin/Core/Entity/UserTest.php index f3a5424..3a7fd25 100644 --- a/core/modules/user/tests/src/Unit/Plugin/Core/Entity/UserTest.php +++ b/core/modules/user/tests/src/Unit/Plugin/Core/Entity/UserTest.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\user\Unit\Plugin\Core\Entity; +use Drupal\Core\Language\LanguageInterface; use Drupal\Tests\Core\Session\UserSessionTest; use Drupal\user\RoleInterface; @@ -15,24 +16,28 @@ class UserTest extends UserSessionTest { * {@inheritdoc} */ protected function createUserSession(array $rids = array(), $authenticated = FALSE) { + $roles = array(); + foreach ($rids as $rid) { + $roles[] = array( + 'target_id' => $rid, + ); + } + $values = ['roles' => [LanguageInterface::LANGCODE_DEFAULT => $roles]]; + $user = $this->getMockBuilder('Drupal\user\Entity\User') ->disableOriginalConstructor() - ->setMethods(array('get', 'id')) + ->setMethods(array('id')) ->getMock(); + + $reflect = new \ReflectionObject($user); + $property = $reflect->getProperty('values'); + $property->setAccessible(TRUE); + $property->setValue($user, $values); + $user->expects($this->any()) ->method('id') // @todo Also test the uid = 1 handling. ->will($this->returnValue($authenticated ? 2 : 0)); - $roles = array(); - foreach ($rids as $rid) { - $roles[] = (object) array( - 'target_id' => $rid, - ); - } - $user->expects($this->any()) - ->method('get') - ->with('roles') - ->will($this->returnValue($roles)); return $user; } diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 0e9cedb..dcb9f29 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -761,6 +761,7 @@ function _user_cancel($edit, $account, $method) { // regenerate it because batch API uses the session ID, we will regenerate it // in _user_cancel_session_regenerate(). if ($account->id() == \Drupal::currentUser()->id()) { + \Drupal::request()->getSession()->remove('uid'); \Drupal::currentUser()->setAccount(new AnonymousUserSession()); } } diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml index 8fc9bf5..a2c373b 100644 --- a/core/modules/user/user.services.yml +++ b/core/modules/user/user.services.yml @@ -17,7 +17,7 @@ services: - { name: access_check, applies_to: _user_is_logged_in } user.authentication.cookie: class: Drupal\user\Authentication\Provider\Cookie - arguments: ['@session_configuration', '@database'] + arguments: ['@session_configuration', '@entity.manager'] tags: - { name: authentication_provider, provider_id: 'cookie', priority: 0, global: TRUE } user.data: