AccountProxy.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <?php
  2. namespace Drupal\Core\Session;
  3. use Drupal\Core\DependencyInjection\DependencySerializationTrait;
  4. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  5. /**
  6. * A proxied implementation of AccountInterface.
  7. *
  8. * The reason why we need an account proxy is that we don't want to have global
  9. * state directly stored in the container.
  10. *
  11. * This proxy object avoids multiple invocations of the authentication manager
  12. * which can happen if the current user is accessed in constructors. It also
  13. * allows legacy code to change the current user where the user cannot be
  14. * directly injected into dependent code.
  15. */
  16. class AccountProxy implements AccountProxyInterface {
  17. use DependencySerializationTrait;
  18. /**
  19. * The instantiated account.
  20. *
  21. * @var \Drupal\Core\Session\AccountInterface
  22. */
  23. protected $account;
  24. /**
  25. * Account id.
  26. *
  27. * @var int
  28. */
  29. protected $id = 0;
  30. /**
  31. * Initial account id.
  32. *
  33. * @var int
  34. *
  35. * @deprecated in drupal:8.3.0 and is removed from drupal:9.0.0. Use
  36. * $this->id instead.
  37. */
  38. protected $initialAccountId;
  39. /**
  40. * Event dispatcher.
  41. *
  42. * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
  43. */
  44. protected $eventDispatcher;
  45. /**
  46. * AccountProxy constructor.
  47. *
  48. * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher
  49. * Event dispatcher.
  50. */
  51. public function __construct(EventDispatcherInterface $eventDispatcher = NULL) {
  52. if (!$eventDispatcher) {
  53. @trigger_error('Calling AccountProxy::__construct() without the $eventDispatcher argument is deprecated in drupal:8.8.0. The $eventDispatcher argument will be required in drupal:9.0.0. See https://www.drupal.org/node/3009387', E_USER_DEPRECATED);
  54. $eventDispatcher = \Drupal::service('event_dispatcher');
  55. }
  56. $this->eventDispatcher = $eventDispatcher;
  57. }
  58. /**
  59. * {@inheritdoc}
  60. */
  61. public function setAccount(AccountInterface $account) {
  62. // If the passed account is already proxied, use the actual account instead
  63. // to prevent loops.
  64. if ($account instanceof static) {
  65. $account = $account->getAccount();
  66. }
  67. $this->account = $account;
  68. $this->id = $account->id();
  69. $this->eventDispatcher->dispatch(AccountEvents::SET_USER, new AccountSetEvent($account));
  70. }
  71. /**
  72. * {@inheritdoc}
  73. */
  74. public function getAccount() {
  75. if (!isset($this->account)) {
  76. if ($this->id) {
  77. // After the container is rebuilt, DrupalKernel sets the initial
  78. // account to the id of the logged in user. This is necessary in order
  79. // to refresh the user account reference here.
  80. $this->setAccount($this->loadUserEntity($this->id));
  81. }
  82. else {
  83. $this->account = new AnonymousUserSession();
  84. }
  85. }
  86. return $this->account;
  87. }
  88. /**
  89. * {@inheritdoc}
  90. */
  91. public function id() {
  92. return $this->id;
  93. }
  94. /**
  95. * {@inheritdoc}
  96. */
  97. public function getRoles($exclude_locked_roles = FALSE) {
  98. return $this->getAccount()->getRoles($exclude_locked_roles);
  99. }
  100. /**
  101. * {@inheritdoc}
  102. */
  103. public function hasPermission($permission) {
  104. return $this->getAccount()->hasPermission($permission);
  105. }
  106. /**
  107. * {@inheritdoc}
  108. */
  109. public function isAuthenticated() {
  110. return $this->getAccount()->isAuthenticated();
  111. }
  112. /**
  113. * {@inheritdoc}
  114. */
  115. public function isAnonymous() {
  116. return $this->getAccount()->isAnonymous();
  117. }
  118. /**
  119. * {@inheritdoc}
  120. */
  121. public function getPreferredLangcode($fallback_to_default = TRUE) {
  122. return $this->getAccount()->getPreferredLangcode($fallback_to_default);
  123. }
  124. /**
  125. * {@inheritdoc}
  126. */
  127. public function getPreferredAdminLangcode($fallback_to_default = TRUE) {
  128. return $this->getAccount()->getPreferredAdminLangcode($fallback_to_default);
  129. }
  130. /**
  131. * {@inheritdoc}
  132. */
  133. public function getUsername() {
  134. @trigger_error('\Drupal\Core\Session\AccountInterface::getUsername() is deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0. Use \Drupal\Core\Session\AccountInterface::getAccountName() or \Drupal\user\UserInterface::getDisplayName() instead. See https://www.drupal.org/node/2572493', E_USER_DEPRECATED);
  135. return $this->getAccountName();
  136. }
  137. /**
  138. * {@inheritdoc}
  139. */
  140. public function getAccountName() {
  141. return $this->getAccount()->getAccountName();
  142. }
  143. /**
  144. * {@inheritdoc}
  145. */
  146. public function getDisplayName() {
  147. return $this->getAccount()->getDisplayName();
  148. }
  149. /**
  150. * {@inheritdoc}
  151. */
  152. public function getEmail() {
  153. return $this->getAccount()->getEmail();
  154. }
  155. /**
  156. * {@inheritdoc}
  157. */
  158. public function getTimeZone() {
  159. return $this->getAccount()->getTimeZone();
  160. }
  161. /**
  162. * {@inheritdoc}
  163. */
  164. public function getLastAccessedTime() {
  165. return $this->getAccount()->getLastAccessedTime();
  166. }
  167. /**
  168. * {@inheritdoc}
  169. */
  170. public function setInitialAccountId($account_id) {
  171. if (isset($this->account)) {
  172. throw new \LogicException('AccountProxyInterface::setInitialAccountId() cannot be called after an account was set on the AccountProxy');
  173. }
  174. $this->id = $this->initialAccountId = $account_id;
  175. }
  176. /**
  177. * Load a user entity.
  178. *
  179. * The entity manager requires additional initialization code and cache
  180. * clearing after the list of modules is changed. Therefore it is necessary to
  181. * retrieve it as late as possible.
  182. *
  183. * Because of serialization issues it is currently not possible to inject the
  184. * container into the AccountProxy. Thus it is necessary to retrieve the
  185. * entity manager statically.
  186. *
  187. * @see https://www.drupal.org/node/2430447
  188. *
  189. * @param int $account_id
  190. * The id of an account to load.
  191. *
  192. * @return \Drupal\Core\Session\AccountInterface|null
  193. * An account or NULL if none is found.
  194. */
  195. protected function loadUserEntity($account_id) {
  196. return \Drupal::entityTypeManager()->getStorage('user')->load($account_id);
  197. }
  198. }