AccountSwitcher.php 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. <?php
  2. namespace Drupal\Core\Session;
  3. /**
  4. * An implementation of AccountSwitcherInterface.
  5. *
  6. * This allows for safe switching of user accounts by ensuring that session
  7. * data for one user is not leaked in to others. It also provides a stack that
  8. * allows reverting to a previous user after switching.
  9. */
  10. class AccountSwitcher implements AccountSwitcherInterface {
  11. /**
  12. * A stack of previous overridden accounts.
  13. *
  14. * @var \Drupal\Core\Session\AccountInterface[]
  15. */
  16. protected $accountStack = [];
  17. /**
  18. * The current user service.
  19. *
  20. * @var \Drupal\Core\Session\AccountProxyInterface
  21. */
  22. protected $currentUser = [];
  23. /**
  24. * The write-safe session handler.
  25. *
  26. * @var \Drupal\Core\Session\WriteSafeSessionHandlerInterface
  27. */
  28. protected $writeSafeHandler;
  29. /**
  30. * The original state of session saving prior to account switching.
  31. *
  32. * @var bool
  33. */
  34. protected $originalSessionSaving;
  35. /**
  36. * Constructs a new AccountSwitcher.
  37. *
  38. * @param \Drupal\Core\Session\AccountProxyInterface $current_user
  39. * The current user service.
  40. * @param \Drupal\Core\Session\WriteSafeSessionHandlerInterface $write_safe_handler
  41. * The write-safe session handler.
  42. */
  43. public function __construct(AccountProxyInterface $current_user, WriteSafeSessionHandlerInterface $write_safe_handler) {
  44. $this->currentUser = $current_user;
  45. $this->writeSafeHandler = $write_safe_handler;
  46. }
  47. /**
  48. * {@inheritdoc}
  49. */
  50. public function switchTo(AccountInterface $account) {
  51. // Prevent session information from being saved and push previous account.
  52. if (!isset($this->originalSessionSaving)) {
  53. // Ensure that only the first session saving status is saved.
  54. $this->originalSessionSaving = $this->writeSafeHandler->isSessionWritable();
  55. }
  56. $this->writeSafeHandler->setSessionWritable(FALSE);
  57. array_push($this->accountStack, $this->currentUser->getAccount());
  58. $this->currentUser->setAccount($account);
  59. return $this;
  60. }
  61. /**
  62. * {@inheritdoc}
  63. */
  64. public function switchBack() {
  65. // Restore the previous account from the stack.
  66. if (!empty($this->accountStack)) {
  67. $this->currentUser->setAccount(array_pop($this->accountStack));
  68. }
  69. else {
  70. throw new \RuntimeException('No more accounts to revert to.');
  71. }
  72. // Restore original session saving status if all account switches are
  73. // reverted.
  74. if (empty($this->accountStack)) {
  75. if ($this->originalSessionSaving) {
  76. $this->writeSafeHandler->setSessionWritable(TRUE);
  77. }
  78. }
  79. return $this;
  80. }
  81. }