AnonymousUserResponseSubscriber.php 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. <?php
  2. namespace Drupal\Core\EventSubscriber;
  3. use Drupal\Core\Cache\CacheableMetadata;
  4. use Drupal\Core\Cache\CacheableResponseInterface;
  5. use Drupal\Core\Session\AccountInterface;
  6. use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
  7. use Symfony\Component\HttpKernel\KernelEvents;
  8. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9. /**
  10. * Response subscriber to handle finished responses for the anonymous user.
  11. */
  12. class AnonymousUserResponseSubscriber implements EventSubscriberInterface {
  13. /**
  14. * The current user.
  15. *
  16. * @var \Drupal\Core\Session\AccountInterface
  17. */
  18. protected $currentUser;
  19. /**
  20. * Constructs an AnonymousUserResponseSubscriber object.
  21. *
  22. * @param \Drupal\Core\Session\AccountInterface $current_user
  23. * The current user.
  24. */
  25. public function __construct(AccountInterface $current_user) {
  26. $this->currentUser = $current_user;
  27. }
  28. /**
  29. * Adds a cache tag if the 'user.permissions' cache context is present.
  30. *
  31. * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
  32. * The event to process.
  33. */
  34. public function onRespond(FilterResponseEvent $event) {
  35. if (!$event->isMasterRequest()) {
  36. return;
  37. }
  38. if (!$this->currentUser->isAnonymous()) {
  39. return;
  40. }
  41. $response = $event->getResponse();
  42. if (!$response instanceof CacheableResponseInterface) {
  43. return;
  44. }
  45. // The 'user.permissions' cache context ensures that if the permissions for
  46. // a role are modified, users are not served stale render cache content.
  47. // But, when entire responses are cached in reverse proxies, the value for
  48. // the cache context is never calculated, causing the stale response to not
  49. // be invalidated. Therefore, when varying by permissions and the current
  50. // user is the anonymous user, also add the cache tag for the 'anonymous'
  51. // role.
  52. if (in_array('user.permissions', $response->getCacheableMetadata()->getCacheContexts())) {
  53. $per_permissions_response_for_anon = new CacheableMetadata();
  54. $per_permissions_response_for_anon->setCacheTags(['config:user.role.anonymous']);
  55. $response->addCacheableDependency($per_permissions_response_for_anon);
  56. }
  57. }
  58. /**
  59. * Registers the methods in this class that should be listeners.
  60. *
  61. * @return array
  62. * An array of event listener definitions.
  63. */
  64. public static function getSubscribedEvents() {
  65. // Priority 5, so that it runs before FinishResponseSubscriber, but after
  66. // event subscribers that add the associated cacheability metadata (which
  67. // have priority 10). This one is conditional, so must run after those.
  68. $events[KernelEvents::RESPONSE][] = ['onRespond', 5];
  69. return $events;
  70. }
  71. }