Skip to content

Instantly share code, notes, and snippets.

@nonom
Created October 24, 2022 07:28
Show Gist options
  • Save nonom/f9f39b3372ce5413712bd7c7c62c0b1d to your computer and use it in GitHub Desktop.
Save nonom/f9f39b3372ce5413712bd7c7c62c0b1d to your computer and use it in GitHub Desktop.
<?php
namespace Drupal\boost\EventSubscriber;
use Drupal\boost\BoostCacheInterface;
use Drupal\Component\Plugin\Factory\FactoryInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Render\HtmlResponse;
use Drupal\Core\Render\AttachmentsResponseProcessorInterface;
use Drupal\Core\Session\AccountProxy;
use Drupal\system\Plugin\Condition\RequestPath;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Class to return cached pages if eligible.
*/
class BoostResponseSubscriber implements EventSubscriberInterface {
/**
* The HTML response attachments processor service.
*
* @var AttachmentsResponseProcessorInterface
*/
protected AttachmentsResponseProcessorInterface $htmlResponseAttachmentsProcessor;
/**
* The current account.
*
* @var AccountProxy
*/
protected AccountProxy $account;
/**
* The Boost cache service.
*
* @var BoostCacheInterface
*/
protected BoostCacheInterface $boostCache;
/**
* The boost cache settings.
*
* @var ImmutableConfig
*/
protected ImmutableConfig $boostConfig;
/**
* The request path condition plugin.
*
* @var RequestPath
*/
protected RequestPath $condition;
/**
* Constructs a HtmlResponseSubscriber object.
*
* @param AttachmentsResponseProcessorInterface $html_response_attachments_processor
* The HTML response attachments processor service.
* @param AccountProxy $account
* Current user service.
* @param ConfigFactoryInterface $config_factory
* Config factory to get boost settings.
* @param BoostCacheInterface $boost_cache
* Plugin factory to get request_path.
* @param FactoryInterface $plugin_factory
* Plugin factory to get request_path.
*/
public function __construct(AttachmentsResponseProcessorInterface $html_response_attachments_processor,
AccountProxy $account,
ConfigFactoryInterface $config_factory,
BoostCacheInterface $boost_cache,
FactoryInterface $plugin_factory) {
$this->htmlResponseAttachmentsProcessor = $html_response_attachments_processor;
$this->account = $account;
$this->boostConfig = $config_factory->get('boost.settings');
$this->boostCache = $boost_cache;
$this->condition = $plugin_factory->createInstance('request_path');
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
KernelEvents::REQUEST => [
['onRequest', 100],
],
KernelEvents::RESPONSE => [
['onRespond', -100],
],
];
}
/**
* Process a GetResponseEvent instance.
*/
public function onRequest(RequestEvent $event) {
if ($this->account->isAuthenticated()) {
return;
}
if (!$this->checkPageCacheability()) {
return;
}
$method = $event->getRequest()->getMethod();
// Only cache GET requests.
if ($method != 'GET') {
return;
}
// Check for existing cached response.
if (($content = $this->boostCache->retrieve()) && (!$event->getRequest()->headers->get('X-Boost-Cache'))) {
$response = new Response();
$response->setContent($content);
$response->setStatusCode(Response::HTTP_OK);
$response->headers->set('X-Boost-Cache', 'partial');
$event->setResponse($response);
}
}
/**
* Processes HtmlResponse event.
*
* @param ResponseEvent $event
* The event to process.
*
* @todo , split things off into the class.
*/
public function onRespond(ResponseEvent $event) {
if ($this->account->isAuthenticated()) {
return;
}
if (!$this->checkPageCacheability()) {
return;
}
$response = $event->getResponse();
if (!$response instanceof HtmlResponse) {
return;
}
if ($response->isRedirect() || $response->isForbidden() ||
$response->isNotFound()) {
return;
}
$this->htmlResponseAttachmentsProcessor->processAttachments($response);
$content = $response->getContent();
// Create a cached response on the local file system.
$this->boostCache->index($content);
}
/**
* Check page cacheaability.
*
* @return bool
* Whether the page should be cached or not.
*/
public function checkPageCacheability(): bool
{
$visibility = $this->boostConfig->get('cacheability_pages') ?? [
'id' => 'request_path',
'pages' => '',
'negate' => 1,
];
$this->condition->setConfiguration($visibility);
return $this->condition->evaluate();
}
}
@nonom
Copy link
Author

nonom commented Oct 24, 2022

services:
boost.subscriber:
class: Drupal\boost\EventSubscriber\BoostResponseSubscriber
arguments: ['@html_response.attachments_processor', '@current_user', '@config.factory', '@boost.cache', '@plugin.manager.condition']
tags:
- {name: event_subscriber}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment