cache_review-1.0.x-dev/src/StackMiddleware/CacheReview.php
src/StackMiddleware/CacheReview.php
<?php
namespace Drupal\cache_review\StackMiddleware;
use Drupal\cache_review\Form\CacheReviewConfigForm;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Show cache variables before page load.
*/
class CacheReview implements HttpKernelInterface {
use StringTranslationTrait;
/**
* The wrapped HTTP kernel.
*
* @var \Symfony\Component\HttpKernel\HttpKernelInterface
*/
protected $httpKernel;
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The renderer configuration array.
*
* @var array
*/
protected $rendererConfig;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The response object.
*
* @var \Symfony\Component\HttpFoundation\Response
*/
protected $response;
/**
* The date formatter service.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/**
* Constructs a PageCache object.
*
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
* The decorated kernel.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param array $renderer_config
* The renderer configuration array.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory for retrieving required config objects.
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
* The date formatter service.
*/
public function __construct(HttpKernelInterface $http_kernel, ModuleHandlerInterface $module_handler, array $renderer_config, RequestStack $request_stack, ConfigFactoryInterface $config_factory, DateFormatterInterface $date_formatter) {
$this->httpKernel = $http_kernel;
$this->moduleHandler = $module_handler;
$this->rendererConfig = $renderer_config;
$this->requestStack = $request_stack;
$this->configFactory = $config_factory;
$this->dateFormatter = $date_formatter;
}
/**
* {@inheritdoc}
*/
public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = TRUE): Response {
$message = $page_cache_info = $ipc = $dpc = $dpc_header = '';
if (!isset($this->response)) {
$this->response = $this->httpKernel->handle($request, $type, $catch);
}
$content = $this->response->getContent();
// Check if it needs to show cache info on admin routes.
$cache_review_config = $this->configFactory->get(CacheReviewConfigForm::CACHE_REVIEW_CONF);
if (!$cache_review_config->get('check_admin_routes')) {
if ($route_object = $request->attributes->get('_route_object')) {
if ($route_object->getOption('_admin_route')) {
return $this->response;
}
}
}
// Bypass JS and CSS requests from cache reviewing.
if ($request->get('_route') == 'system.js_asset' || $request->get('_route') == 'system.css_asset') {
return $this->response;
}
// Add Big Pipe module status.
$big_pipe_status = $this->moduleHandler->moduleExists('big_pipe') ? 'enabled' : 'disabled';
$big_pipe_message = $this->t('<br><small>Big Pipe status: @status</small><br>', ['@status' => $big_pipe_status]);
// Get APC values.
$apc = $this->rendererConfig['auto_placeholder_conditions'];
// Get IPC and DPC cache values.
if (!$this->moduleHandler->moduleExists('page_cache')) {
$message .= $this->t("The module IPC (page_cache) <b>disabled</b><br>");
}
else {
$ipc = $this->response->headers->get('X-Drupal-Cache') ?? '';
}
if (!$this->moduleHandler->moduleExists('dynamic_page_cache')) {
$message .= $this->t("The module dynamic_page_cache disabled<br>");
}
else {
$dpc_header = DynamicPageCacheSubscriber::HEADER;
$dpc = $this->response->headers->get(DynamicPageCacheSubscriber::HEADER) ?? '';
}
if ($this->response->isSuccessful()) {
$ipc_dpc_output = $this->t("IPC response status 'X-Drupal-Cache': <b>@ipc</b><br>DPC response status '@dpc_header': <b>@dpc</b>", [
'@ipc' => $ipc,
'@dpc_header' => $dpc_header,
'@dpc' => $dpc,
]);
$page_cache_info = $message . $ipc_dpc_output;
}
$apc_text = !empty($apc) ? json_encode($apc) : '{}';
$timezone = date_default_timezone_get();
$time = $this->dateFormatter->format(time(), 'custom', 'H:i:s', $timezone);
$label = $this->t('Page Cache Status | @time', ['@time' => $time]);
$apc_link_title = $this->t('If we have an item on the page with appropriate auto_placeholder_conditions, and it is not wrapped automatically or by developer into lazy-builder (so it will not have placeholder), in this case the cache options of such item (like max-age = 0) will bubble up in html to page level and will disable cache for whole request.');
$auto_placeholder_link = sprintf('<a href="https://www.drupal.org/docs/drupal-apis/render-api/auto-placeholdering" target="_blank" title="%s">auto_placeholder_conditions</a>', $apc_link_title);
$miss_hit_text = $this->t('MISS = cache can be created, refresh page. HIT = you see page data from cache');
$info = sprintf("<ul><li>%s</li><li>%s</li><li>%s<br>%s: %s.</li></ul>",
$this->t("Note: timezone for anonymous is set to 'GTM'"),
$this->t('<b>C</b> - item cached, <b>L</b> - item wrapped by Lazy builder, <b>N</b> - no specific cache properties'),
$this->t('If <span class=\"cache_caught\">C, N</span> are in bold, it means that items has cache options matched to the'), $auto_placeholder_link, $apc_text);
$content = sprintf('<div class="cache-status-wrapper"><details><summary class="cache-status-label">%s </summary><div class="cache-designation">%s %s <br><small>(%s)</small>%s</div></details></div>%s', $label, $info, $page_cache_info, $miss_hit_text, $big_pipe_message, $content);
$this->response->setContent($content);
return $this->response;
}
}
