cache_review-1.0.x-dev/src/Controller/CacheReviewController.php

src/Controller/CacheReviewController.php
<?php

namespace Drupal\cache_review\Controller;

use Drupal\Core\Block\BlockManagerInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Link;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\Security\TrustedCallbackInterface;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class with demo cache pages.
 */
class CacheReviewController implements ContainerInjectionInterface, TrustedCallbackInterface {

  use StringTranslationTrait;

  /**
   * The route provider to load routes by name.
   *
   * @var \Drupal\Core\Routing\RouteProviderInterface
   */
  protected $routeProvider;

  /**
   * The block manager.
   *
   * @var \Drupal\Core\Block\BlockManagerInterface
   */
  protected $blockManager;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;

  /**
   * The renderer.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * Path to module.
   *
   * @var string
   */
  protected $modulePath;

  /**
   * The date formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected $dateFormatter;

  /**
   * Construct for CacheReview object.
   *
   * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
   *   The route provider.
   * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
   *   The block manager.
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   The current user.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer.
   * @param \Drupal\Core\Extension\ModuleExtensionList $module_extension_list
   *   The module extension list.
   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
   *   The date formatter service.
   */
  public function __construct(RouteProviderInterface $route_provider, BlockManagerInterface $block_manager, AccountInterface $current_user, RendererInterface $renderer, ModuleExtensionList $module_extension_list, DateFormatterInterface $date_formatter) {
    $this->routeProvider = $route_provider;
    $this->blockManager = $block_manager;
    $this->currentUser = $current_user;
    $this->renderer = $renderer;
    $this->modulePath = $module_extension_list->getPath('cache_review');
    $this->dateFormatter = $date_formatter;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('router.route_provider'),
      $container->get('plugin.manager.block'),
      $container->get('current_user'),
      $container->get('renderer'),
      $container->get('extension.list.module'),
      $container->get('date.formatter'),
    );
  }

  /**
   * Displays a demo page with links for testing.
   *
   * @return array
   *   Render array for the CacheReview demo page.
   *
   * @see cache_review.page
   */
  public function page() {
    $build['links'] = [];
    $build['links']['#markup'] = '';

    $routingFilePath = DRUPAL_ROOT . '/' . $this->modulePath . '/cache_review.routing.yml';
    $routingFileContents = file_get_contents($routingFilePath);
    $results = Yaml::decode($routingFileContents);
    foreach ($results as $id => $result) {
      $routeName = $id;
      $route = $this->routeProvider->getRouteByName($routeName);

      $route_title = $route->getDefault('_title');
      if ($routeName === 'cache_review.page') {
        continue;
      }

      $build['links']['#markup'] .= Link::createFromRoute($route_title, $routeName, [], [
        'absolute' => TRUE,
        'https' => TRUE,
        'attributes' => ['target' => '_blank'],
      ])->toString() . '<br>';
    }

    return $build;
  }

  /**
   * Displays cached page with different max-age for items.
   *
   * @return array
   *   Render array for the CacheReview demo page.
   *
   * @see cache_review.cached_max_age
   */
  public function cachedMaxAge() {
    $build['intro'] = [
      '#markup' => $this->t('<i>After loading or cache clearing, this page should be MISS and after next loading becomes HIT (it depends on your auto_placeholder_conditions, look at Page Cache Status). The functionality was tested with auto_placeholder_conditions: {"max-age":0,"contexts":["session","user"],"tags":[]}.<br>Try to change cache options in cache_review\Controller\CacheReviewController::cachedMaxAge and see result.<br>Pay attention to time indicators - the section from cache will have obsolete time. Try to reload page after several seconds and updating one of section due to max-age will lead to rebuild cache whole page because of bubbling cache properties.<br>On the other page we have an example with lazy wrapper to restrict changing data inside separate section only.</i><br>'),
    ];
    $time = sprintf('<span class="date">%s </span>', $this->getTimeValue());
    $option_title = $this->t('Cache options:');

    // 01 Permanent section.
    $image_url = "/$this->modulePath/images/drupal_tm.png";
    $image = '<img src="' . $image_url . '" width="300" alt="Test image">';

    $cache_permanent = [
      'max-age' => Cache::PERMANENT,
      'tags' => ['user:1'],
    ];
    $build['permanent'] = [
      '#markup' => sprintf('(01) %s<br><small>%s</small><br><b>%s %s</b><br>%s<hr>', $time, $this->randomText(), $option_title, json_encode($cache_permanent), $image),
      '#cache' => $cache_permanent,
    ];

    // 02-03 Section with ancestors.
    $cache_child_1 = [
      'max-age' => 20,
    ];
    $cache_child_2 = [
      'max-age' => 30,
      'keys' => ['demo_child'],
    ];
    $build['parent_item'] = [
      '#type' => 'item',
      '#prefix' => '<div id="parent_item">',
      '#suffix' => '</div>',
    ];
    $build['parent_item']['child_item_one'] = [
      '#markup' => sprintf('(02) %s<br><small>%s</small><br><b>%s %s</b><hr>', $time, $this->randomText(), $option_title, json_encode($cache_child_1)),
      '#cache' => $cache_child_1,
      '#prefix' => '<div id="child_item_one">',
      '#suffix' => '</div>',
    ];
    $build['parent_item']['child_item_two'] = [
      '#markup' => sprintf('(03) %s<br><small>%s</small><br><b>%s %s</b><hr>', $time, $this->randomText(), $option_title, json_encode($cache_child_2)),
      '#cache' => $cache_child_2,
      '#prefix' => '<div id="child_item_two">',
      '#suffix' => '</div>',
    ];

    // 04 Section with context url.
    $cache_contexts_url = [
      'contexts' => ['url.query_args'],
    ];
    $build['contexts_url'] = [
      '#type' => 'markup',
      '#markup' => sprintf('(04) %s<br><small>%s</small><br><b>%s %s</b></div><hr>', $time, $this->randomText(), $option_title, json_encode($cache_contexts_url)),
      '#prefix' => '<div id="cache_contexts_url">',
      '#suffix' => '</div>',
      '#cache' => $cache_contexts_url,
    ];

    return $build;
  }

  /**
   * Displays page with lazy, context and keys.
   *
   * @return array
   *   Render array for the CacheReview demo page.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   *
   * @see cache_review.uncacheable_lazy_keys
   */
  public function uncacheableLazyKeys() {
    $build['intro'] = [
      '#markup' => $this->t('<i>This page should be not cached (due to context = user in section (02)), except some sections (it depends on your auto_placeholder_conditions). The functionality was tested with auto_placeholder_conditions: {"max-age":0,"contexts":["session","user"],"tags":[]}.<br>The items (04) and (05) built with lazy and are not cached because of options. Try to change cache options in cache_review\Controller\CacheReviewController::uncacheableLazyKeys, play with url query arguments, keys and see the result.<br>Pay attention to time indicators. The section from cache will have obsolete time.<br></i>'),
    ];
    $time = sprintf('<span class="date">%s </span>', $this->getTimeValue());
    $option_title = $this->t('Cache options:');

    $image_url = "/$this->modulePath/images/drupal_tm.png";
    $image = '<img src="' . $image_url . '" width="200" alt="Test image">';

    // 00 Block with context.
    $block = $this->blockManager->createInstance('cache_review_block_no_lazy', [
      'context_option' => 'url',
    ])->build();
    $build['block_uncached'] = [
      '#markup' => $this->renderer->render($block),
    ];

    // 01 Permanent section with max-age.
    $cache_permanent = [
      'max-age' => Cache::PERMANENT,
    ];
    $build['permanent'] = [
      '#markup' => sprintf('(01) %s<br><small>%s</small><br><b>%s %s</b><br>%s<hr>', $time, $this->randomText(), $option_title, json_encode($cache_permanent), $image),
      '#cache' => $cache_permanent,
    ];

    // 02 Section with contexts and keys.
    $cache_contexts_and_key = [
      'contexts' => ['user', 'url.query_args'],
      'keys' => ['demo_contexts_key'],
    ];
    $build['contexts_and_key'] = [
      '#type' => 'markup',
      '#markup' => sprintf('(02) %s<br><small>%s</small><br><b>%s %s</b></div><hr>',
        $time, $this->randomText(), $option_title, json_encode($cache_contexts_and_key)),
      '#prefix' => '<div id="cache_contexts_and_key">',
      '#suffix' => '</div>',
      '#cache' => $cache_contexts_and_key,
    ];

    // 03 Section with contexts parameters and keys.
    $cache_contexts_param_and_key = [
      'contexts' => ['url.query_args:test'],
      'keys' => ['demo_contexts_key_test'],
    ];
    $build['contexts_param_and_key'] = [
      '#type' => 'markup',
      '#markup' => sprintf('(03) %s<br><small>%s</small><br><b>%s %s</b></div><hr>',
        $time, $this->randomText(), $option_title, json_encode($cache_contexts_param_and_key)),
      '#prefix' => '<div id="contexts_param_and_key">',
      '#suffix' => '</div>',
      '#cache' => $cache_contexts_param_and_key,
    ];

    // 04 Section with lazy builder and context.
    $build['lazy_contexts_session'] = [
      '#lazy_builder' => [static::class . '::lazyBuilderContext', [$time]],
      '#cache' => [
        'contexts' => ['session'],
      ],
    ];

    // 05 Section with lazy builder and create_placeholder.
    $build['lazy_create_placeholder'] = [
      '#lazy_builder' => [static::class . '::lazyBuilderPlaceholder', [$time]],
      '#create_placeholder' => TRUE,
    ];

    return $build;
  }

  /**
   * Builds content for lazy builder with context.
   *
   * @param string $time
   *   Current time.
   *
   * @return string[]
   *   Lazy markup content.
   */
  public static function lazyBuilderContext($time) {
    return [
      '#type' => 'markup',
      '#markup' => sprintf(' (04) %s %s<hr>', $time, t('This item has <b>#lazy_builder</b> and context <b>session</b>. As result - item is not cached.<hr>')),
      '#prefix' => '<div id="lazy_contexts_param">',
      '#suffix' => '</div>',
    ];
  }

  /**
   * Builds content for lazy builder with create_placeholder options.
   *
   * @param string $time
   *   Current time.
   *
   * @return string[]
   *   Lazy markup content.
   */
  public static function lazyBuilderPlaceholder($time) {
    return [
      '#type' => 'markup',
      '#markup' => sprintf(' (05) %s %s<hr>', $time, t('This item has <b>#lazy_builder</b> and <b>#create_placeholder</b> options. Item is not cached.')),
      '#prefix' => '<div id="lazy_placeholder_param">',
      '#suffix' => '</div>',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public static function trustedCallbacks() {
    return [
      'lazyBuilderContext',
      'lazyBuilderPlaceholder',
    ];
  }

  /**
   * Displays Cached page with lazy items.
   *
   * @return array
   *   Render array for the demo page.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   *
   * @see cache_review.cached_lazy
   */
  public function cachedLazy() {
    $build['intro'] = [
      '#markup' => $this->t('<i>After loading or cache clearing, this page should be MISS and after next loading becomes HIT (it depends on your auto_placeholder_conditions, look at Page Cache Status). The functionality was tested with auto_placeholder_conditions: {"max-age":0,"contexts":["session","user"],"tags":[]}.<br>The block (00) with lazy is not cached. The next lazy item (04) is cached because of context value. Try to change cache options in cache_review\Controller\CacheReviewController::cachedLazy and see the result. Pay attention to time indicators. The sections from cache will have obsolete time.<br></i>'),
    ];
    $time = sprintf('<span class="date">%s </span>', $this->getTimeValue());
    $option_title = $this->t('Cache options:');

    // 00 Block from lazy builder.
    $build['block_lazy'] = $this->blockManager->createInstance('cache_review_block_lazy', [
      'context_option' => 'user',
    ])->build();

    // 01 Permanent section with max-age -1 and keys.
    // Note! 'max-age' => '-1' is equal 'max-age' => 0.
    $cache_permanent = [
      'max-age' => Cache::PERMANENT,
      'keys' => ['keys_permanent_test'],
    ];
    $build['permanent'] = [
      '#markup' => sprintf('(01) %s<br><small>%s</small><br><b>%s %s</b><br><hr>', $time, $this->randomText(), $option_title, json_encode($cache_permanent)),
      '#cache' => $cache_permanent,
    ];

    // 02 Section with ancestor with no cache options.
    $build['parent_item']['child_item'] = [
      '#markup' => sprintf('(02) %s<br>%s <small>%s</small><br><b>%s ---</b><hr>', $time, $this->t('This section without cache options.'), $this->randomText(), $option_title),
    ];

    // 03 Section with context.
    $cache_options = [
      'contexts' => ['url.query_args'],
    ];
    $build['cache_contexts'] = [
      '#type' => 'markup',
      '#markup' => sprintf('(03) %s<br><small>%s</small><br><b>%s %s</b></div><hr>',
        $time, $this->randomText(), $option_title, json_encode($cache_options)),
      '#prefix' => '<div id="cache_contexts">',
      '#suffix' => '</div>',
      '#cache' => $cache_options,
    ];

    // 04 Section with calling Lazy Builder via service.
    $account = $this->currentUser;
    $context_option = 'url';
    $build['lazy_item'] = [
      // Can accept scalar values only.
      '#lazy_builder' => [
        'cache_review.lazy_builder:lazyBuilderCustom',
        [$account->id(), $context_option],
      ],
      '#cache' => [
        'contexts' => [$context_option],
      ],
    ];

    return $build;
  }

  /**
   * Helper to get some random text.
   */
  private function randomText() {
    $str = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent nec ante auctor, feugiat sem nec, mollis mi Vestibulum leo quam, facilisis non porttitor et.Cursus sit amet dictum sit amet. Mi in nulla posuere sollicitudin aliquam. Adipiscing diam donec adipiscing tristique. Tristique senectus et netus et malesuada fames ac turpis.';
    $words = str_word_count($str, 1);
    shuffle($words);
    return implode(' ', $words);
  }

  /**
   * Get current time value, considering timezone.
   *
   * @return string
   *   The current time formatted.
   */
  private function getTimeValue() {
    if ($this->currentUser->isAnonymous()) {
      date_default_timezone_set('GMT');
    }
    $timezone = date_default_timezone_get();

    return $this->dateFormatter->format(time(), 'custom', 'H:i:s', $timezone);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc