Verified Commit 766f3263 authored by Dave Long's avatar Dave Long
Browse files

Issue #3493858 by vidorado, xavier.masson, smustgrave: Extend ViewsBlockBase...

Issue #3493858 by vidorado, xavier.masson, smustgrave: Extend ViewsBlockBase to merge cache metadata from display handler

(cherry picked from commit 1ad501aa)
parent 0cf4a33c
Loading
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

namespace Drupal\views\Plugin\Block;

use Drupal\Core\Cache\Cache;
use Drupal\Core\Url;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
@@ -86,6 +87,30 @@ public static function create(ContainerInterface $container, array $configuratio
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    $contexts = $this->view->display_handler->getCacheMetadata()->getCacheContexts();
    return Cache::mergeContexts(parent::getCacheContexts(), $contexts);
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    $tags = $this->view->display_handler->getCacheMetadata()->getCacheTags();
    return Cache::mergeTags(parent::getCacheTags(), $tags);
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheMaxAge() {
    $max_age = $this->view->display_handler->getCacheMetadata()->getCacheMaxAge();
    return Cache::mergeMaxAges(parent::getCacheMaxAge(), $max_age);
  }

  /**
   * {@inheritdoc}
   */
+88 −3
Original line number Diff line number Diff line
@@ -4,7 +4,11 @@

namespace Drupal\Tests\views\Unit\Plugin\Block;

use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Plugin\Context\ContextInterface;
use Drupal\Tests\UnitTestCase;
use Drupal\views\Plugin\Block\ViewsBlock;

@@ -60,14 +64,25 @@ class ViewsBlockTest extends UnitTestCase {
   * {@inheritdoc}
   */
  protected function setUp(): void {
    // @todo Change the autogenerated stub.
    parent::setUp();

    $container = new ContainerBuilder();

    $cache_context_manager = $this->createMock(CacheContextsManager::class);
    $cache_context_manager->expects($this->any())
      ->method('getAll')
      ->willReturn([]);
    $cache_context_manager->expects($this->any())
      ->method('assertValidTokens')
      ->willReturn(TRUE);
    $container->set('cache_contexts_manager', $cache_context_manager);

    $condition_plugin_manager = $this->createMock('Drupal\Core\Executable\ExecutableManagerInterface');
    $condition_plugin_manager->expects($this->any())
      ->method('getDefinitions')
      ->willReturn([]);
    $container = new ContainerBuilder();
    $container->set('plugin.manager.condition', $condition_plugin_manager);

    \Drupal::setContainer($container);

    $this->executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
@@ -84,7 +99,7 @@ protected function setUp(): void {

    $this->executable->display_handler = $this->getMockBuilder('Drupal\views\Plugin\views\display\Block')
      ->disableOriginalConstructor()
      ->onlyMethods([])
      ->onlyMethods(['getCacheMetadata'])
      ->getMock();

    $this->view = $this->getMockBuilder('Drupal\views\Entity\View')
@@ -155,6 +170,76 @@ public function testBuild(): void {
    $this->assertEquals($build, $plugin->build());
  }

  /**
   * Tests that cacheable metadata is retrieved from the view and merged with block cacheable metadata.
   *
   * @dataProvider providerTestCacheableMetadata
   *
   * @see \Drupal\views\Plugin\block\ViewsBlock::build()
   */
  public function testCacheableMetadata(int $blockCacheMaxAge, int $viewCacheMaxAge, int $expectedCacheMaxAge): void {

    $blockCacheTags = ['block-cachetag-1', 'block-cachetag-2'];
    $blockCacheContexts = ['block-cache-context-1', 'block-cache-context-2'];

    $viewCacheTags = ['view-cachetag-1', 'view-cachetag-2'];
    $viewCacheContexts = ['view-cache-context-1', 'view-cache-context-2'];

    // Mock view cache metadata.
    $viewCacheMetadata = $this->createMock(CacheableMetadata::class);
    $viewCacheMetadata
      ->method('getCacheTags')
      ->willReturn($viewCacheTags);
    $viewCacheMetadata
      ->method('getCacheContexts')
      ->willReturn($viewCacheContexts);
    $viewCacheMetadata
      ->method('getCacheMaxAge')
      ->willReturn($viewCacheMaxAge);
    $this->executable->display_handler
      ->method('getCacheMetadata')
      ->willReturn($viewCacheMetadata);

    // Mock block context.
    $blockContext = $this->createMock(ContextInterface::class);
    $blockContext
      ->method('getCacheTags')
      ->willReturn($blockCacheTags);
    $blockContext
      ->method('getCacheContexts')
      ->willReturn($blockCacheContexts);
    $blockContext
      ->method('getCacheMaxAge')
      ->willReturn($blockCacheMaxAge);

    // Create the views block.
    $block_id = 'views_block:test_view-block_1';
    $config = [];
    $definition = [
      'provider' => 'views',
    ];
    $plugin = new ViewsBlock($config, $block_id, $definition, $this->executableFactory, $this->storage, $this->account);
    $plugin->setContext('context_name', $blockContext);

    // Assertions.
    $this->assertEmpty(array_diff(Cache::mergeTags($viewCacheTags, $blockCacheTags), $plugin->getCacheTags()));
    $this->assertEmpty(array_diff(Cache::mergeContexts($viewCacheContexts, $blockCacheContexts), $plugin->getCacheContexts()));
    $this->assertEquals($expectedCacheMaxAge, $plugin->getCacheMaxAge());
  }

  /**
   * Data provider for ::testCacheableMetadata()
   */
  public static function providerTestCacheableMetadata(): array {
    return [
      'View expires before' => [500, 1000, 500],
      'Block expires before' => [1000, 500, 500],
      'Only block is permanent' => [Cache::PERMANENT, 500, 500],
      'Only view is permanent' => [500, Cache::PERMANENT, 500],
      'Both view and block are permanent' => [Cache::PERMANENT, Cache::PERMANENT, Cache::PERMANENT],
    ];
  }

  /**
   * Tests the build method.
   *