diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index c46126e..864da85 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -541,6 +541,53 @@ protected function getTranslatedField($name, $langcode) { } /** + * Gets the value of a specific property of a field. + * + * Only the first delta can be accessed with this method. + * + * @param string $field_name + * The name of the field. + * @param string $property + * The field property, "value" for many field types. + * @param int $delta + * Dield value offset for mutli value fields. + * + * @return mixed + */ + public function getFieldValue($field_name, $property, $delta = 0) { + // Attempt to get the value from the values directly if the field is not + // initialized yet. + if (!isset($this->fields[$field_name])) { + $field_values = NULL; + if (isset($this->values[$field_name][$this->activeLangcode])) { + $field_values = $this->values[$field_name][$this->activeLangcode]; + } + elseif ($this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT]) { + $field_values = $this->values[$field_name][LanguageInterface::LANGCODE_DEFAULT]; + } + + if ($field_values !== NULL) { + // If there are field values, try to get the property value. + // Configurable/Multi-value fields are stored differently, try accessing + // with delta and property first, then without delta and last, if the + // value are a scalar, just return that. + if (isset($field_values[$delta][$property]) && is_array($field_values[$delta])) { + return $field_values[$delta][$property]; + } + elseif (isset($field_values[$property]) && is_array($field_values)) { + return $field_values[$property]; + } + elseif (!is_array($field_values)) { + return $field_values; + } + } + } + + // Fall back to access the property through the field object. + return $this->get($field_name)->$property; + } + + /** * {@inheritdoc} */ public function set($name, $value, $notify = TRUE) { diff --git a/core/lib/Drupal/Core/Entity/ContentEntityDeleteForm.php b/core/lib/Drupal/Core/Entity/ContentEntityDeleteForm.php index 9a70ef5..d0b29fd 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityDeleteForm.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityDeleteForm.php @@ -61,7 +61,9 @@ public function submitForm(array &$form, FormStateInterface $form_state) { // Make sure that deleting a translation does not delete the whole entity. if (!$entity->isDefaultTranslation()) { - $untranslated_entity = $entity->getUntranslated(); + // Clone the entity before deleting, as other methods will need to access + // the label and other data of the deleted translation. + $untranslated_entity = clone $entity->getUntranslated(); $untranslated_entity->removeTranslation($entity->language()->getId()); $untranslated_entity->save(); $form_state->setRedirectUrl($untranslated_entity->urlInfo('canonical')); diff --git a/core/modules/comment/src/CommentLazyBuilders.php b/core/modules/comment/src/CommentLazyBuilders.php index 730c840..b49a533 100644 --- a/core/modules/comment/src/CommentLazyBuilders.php +++ b/core/modules/comment/src/CommentLazyBuilders.php @@ -163,7 +163,7 @@ public function renderLinks($comment_entity_id, $view_mode, $langcode, $is_in_pr */ protected function buildLinks(CommentInterface $entity, EntityInterface $commented_entity) { $links = []; - $status = $commented_entity->get($entity->getFieldName())->status; + $status = $commented_entity->getFieldValue($entity->getFieldName(), 'status'); if ($status == CommentItemInterface::OPEN) { if ($entity->access('delete')) { diff --git a/core/modules/comment/src/Entity/Comment.php b/core/modules/comment/src/Entity/Comment.php index a5f1966..c7484e6 100644 --- a/core/modules/comment/src/Entity/Comment.php +++ b/core/modules/comment/src/Entity/Comment.php @@ -81,7 +81,7 @@ class Comment extends ContentEntityBase implements CommentInterface { public function preSave(EntityStorageInterface $storage) { parent::preSave($storage); - if (is_null($this->get('status')->value)) { + if (is_null($this->getStatus())) { if (\Drupal::currentUser()->hasPermission('skip comment approval')) { $this->setPublished(); } @@ -351,21 +351,25 @@ public function getParentComment() { * {@inheritdoc} */ public function getCommentedEntity() { - return $this->get('entity_id')->entity; + if ($this->getCommentedEntityTypeId() && $entity_id = $this->getCommentedEntityId()) { + return $this->entityTypeManager() + ->getStorage($this->getCommentedEntityTypeId()) + ->load($entity_id); + } } /** * {@inheritdoc} */ public function getCommentedEntityId() { - return $this->get('entity_id')->target_id; + return $this->getFieldValue('entity_id', 'target_id'); } /** * {@inheritdoc} */ public function getCommentedEntityTypeId() { - return $this->get('entity_type')->value; + return $this->getFieldValue('entity_type', 'value'); } /** @@ -380,7 +384,7 @@ public function setFieldName($field_name) { * {@inheritdoc} */ public function getFieldName() { - return $this->get('field_name')->value; + return $this->getFieldValue('field_name', 'value'); } /** @@ -481,7 +485,7 @@ public function setCreatedTime($created) { * {@inheritdoc} */ public function getStatus() { - return $this->get('status')->value; + return $this->getFieldValue('status', 'value'); } /** @@ -529,7 +533,7 @@ public function getOwner() { * {@inheritdoc} */ public function getOwnerId() { - return $this->get('uid')->target_id; + return $this->getFieldValue('uid', 'target_id'); } /** diff --git a/core/modules/user/src/Authentication/Provider/Cookie.php b/core/modules/user/src/Authentication/Provider/Cookie.php index ebcdae7..35a2469 100644 --- a/core/modules/user/src/Authentication/Provider/Cookie.php +++ b/core/modules/user/src/Authentication/Provider/Cookie.php @@ -3,9 +3,7 @@ namespace Drupal\user\Authentication\Provider; use Drupal\Core\Authentication\AuthenticationProviderInterface; -use Drupal\Core\Database\Connection; -use Drupal\Core\Session\AccountInterface; -use Drupal\Core\Session\UserSession; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Session\SessionConfigurationInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Session\SessionInterface; @@ -23,23 +21,23 @@ class Cookie implements AuthenticationProviderInterface { protected $sessionConfiguration; /** - * The database connection. + * The entity type manager. * - * @var \Drupal\Core\Database\Connection + * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ - protected $connection; + protected $entityTypeManager; /** * 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\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. */ - public function __construct(SessionConfigurationInterface $session_configuration, Connection $connection) { + public function __construct(SessionConfigurationInterface $session_configuration, EntityTypeManagerInterface $entity_type_manager) { $this->sessionConfiguration = $session_configuration; - $this->connection = $connection; + $this->entityTypeManager = $entity_type_manager; } /** @@ -53,41 +51,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->entityTypeManager->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 7529532..893d4f3 100644 --- a/core/modules/user/src/Entity/User.php +++ b/core/modules/user/src/Entity/User.php @@ -152,9 +152,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 +255,7 @@ public function getCreatedTime() { * {@inheritdoc} */ public function getLastAccessedTime() { - return $this->get('access')->value; + return $this->getFieldValue('access', 'value'); } /** @@ -272,14 +285,14 @@ public function setLastLoginTime($timestamp) { * {@inheritdoc} */ public function isActive() { - return $this->get('status')->value == 1; + return $this->getFieldValue('status', 'value') == 1; } /** * {@inheritdoc} */ public function isBlocked() { - return $this->get('status')->value == 0; + return $this->getFieldValue('status', 'value') == 0; } /** @@ -302,7 +315,7 @@ public function block() { * {@inheritdoc} */ public function getTimeZone() { - return $this->get('timezone')->value; + return $this->getFieldValue('timezone', 'value'); } /** @@ -364,7 +377,7 @@ public function getUsername() { * {@inheritdoc} */ public function getAccountName() { - return $this->get('name')->value ?: ''; + return $this->getFieldValue('name', 'value') ?: ''; } /** 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 623203e..b101fb9 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 = [], $authenticated = FALSE) { + $roles = []; + foreach ($rids as $rid) { + $roles[] = [ + 'target_id' => $rid, + ]; + } + $values = ['roles' => [LanguageInterface::LANGCODE_DEFAULT => $roles]]; + $user = $this->getMockBuilder('Drupal\user\Entity\User') ->disableOriginalConstructor() - ->setMethods(['get', 'id']) + ->setMethods(['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 = []; - foreach ($rids as $rid) { - $roles[] = (object) [ - '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 b865e95..de36217 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -775,6 +775,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 c273cb3..9739c43 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_type.manager'] tags: - { name: authentication_provider, provider_id: 'cookie', priority: 0, global: TRUE } user.data: