Unverified Commit ce37b061 authored by Alex Pott's avatar Alex Pott
Browse files

task: #3516173 Block status code visibility condition should use a status code cache context

By: catch
By: alexpott
By: godotislate
(cherry picked from commit c2bcef50)
parent 16e91ba0
Loading
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -137,6 +137,11 @@ services:
    arguments: ['@request_stack']
    tags:
      - { name: cache.context }
  cache_context.exception_status_code:
    class: Drupal\Core\Cache\Context\ExceptionStatusCodeCacheContext
    arguments: ['@request_stack']
    tags:
      - { name: cache.context }
  cache_context.url:
    class: Drupal\Core\Cache\Context\UrlCacheContext
    arguments: ['@request_stack']
+44 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\Cache\Context;

use Drupal\Core\Cache\CacheableMetadata;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

/**
 * Defines the ExceptionStatusCodeCacheContext service.
 *
 * Cache context ID: 'exception_status_code'.
 */
class ExceptionStatusCodeCacheContext extends RequestStackCacheContextBase {

  /**
   * {@inheritdoc}
   */
  public static function getLabel(): \Stringable {
    return t('Exception status code');
  }

  /**
   * {@inheritdoc}
   */
  public function getContext(): string {
    $exception = $this->requestStack->getCurrentRequest()->attributes->get('exception');
    if ($exception instanceof HttpExceptionInterface) {
      return (string) $exception->getStatusCode();
    }
    // If there's no exception status code, usually a 200, return '0' because we
    // don't know what might be set by response subscribers.
    return '0';
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheableMetadata(): CacheableMetadata {
    return new CacheableMetadata();
  }

}
+1 −1
Original line number Diff line number Diff line
@@ -121,7 +121,7 @@ public function evaluate(): bool {
   */
  public function getCacheContexts(): array {
    $contexts = parent::getCacheContexts();
    $contexts[] = 'url.path';
    $contexts[] = 'exception_status_code';
    return $contexts;
  }

+54 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Tests\Core\Cache\Context;

use Drupal\Core\Cache\Context\ExceptionStatusCodeCacheContext;
use Drupal\Tests\UnitTestCase;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;

/**
 * Tests Drupal\Core\Cache\Context\CookiesCacheContext.
 */
#[CoversClass(ExceptionStatusCodeCacheContext::class)]
#[Group('Cache')]
class ExceptionStatusCodeCacheContextTest extends UnitTestCase {

  /**
   * Tests get context.
   */
  #[DataProvider('providerTestGetContext')]
  public function testGetContext(?\Exception $exception, string $result): void {
    $request_stack = new RequestStack();
    $request = Request::create('/', 'GET');
    if (isset($exception)) {
      $request->attributes->set('exception', $exception);
    }
    $request_stack->push($request);
    $cache_context = new ExceptionStatusCodeCacheContext($request_stack);
    $this->assertSame($cache_context->getContext(), $result);
  }

  /**
   * Provides a list of cookies and expected cache contexts.
   */
  public static function providerTestGetContext(): array {
    return [
      [new NotFoundHttpException(), '404'],
      [new AccessDeniedHttpException(), '403'],
      [new BadRequestHttpException(), '400'],
      [new MethodNotAllowedHttpException(['POST']), '405'],
      [NULL, '0'],
    ];
  }

}