refreshless-8.x-1.x-dev/modules/refreshless_turbo/src/StackMiddleware/AdditiveLibraries.php
modules/refreshless_turbo/src/StackMiddleware/AdditiveLibraries.php
<?php
declare(strict_types=1);
namespace Drupal\refreshless_turbo\StackMiddleware;
use Drupal\refreshless\Service\PageStateFactoryInterface;
use Drupal\refreshless\Service\RequestWrapperFactoryInterface;
use function array_search;
use function array_splice;
use function implode;
use function is_int;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Additive libraries middleware.
*
* This loads the RefreshLess page state if found in the request, removes the
* 'refreshless_turbo/refreshless' library from the already loaded list, and
* then converts it to 'ajax_page_state' value, which it sets back on the
* request.
*
* @see \Drupal\Core\StackMiddleware\AjaxPageState
* Must run after core's Ajax page state middleware; if we were to run before
* it, we would have to re-compress the libraries only for core to decompress
* it again which is a bit inefficient and unnecessary.
*/
class AdditiveLibraries implements HttpKernelInterface {
/**
* Constructor; saves dependencies.
*
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $httpKernel
* The wrapped HTTP kernel.
*
* @param \Drupal\refreshless\Service\PageStateFactoryInterface $pageStateFactory
* The RefreshLess page state factory service.
*
* @param \Drupal\refreshless\Service\RequestWrapperFactoryInterface $requestWrapperFactory
* The RefreshLess request wrapper factory.
*/
public function __construct(
protected readonly HttpKernelInterface $httpKernel,
protected readonly PageStateFactoryInterface $pageStateFactory,
protected readonly RequestWrapperFactoryInterface $requestWrapperFactory,
) {}
/**
* {@inheritdoc}
*/
public function handle(
Request $request, int $type = self::MAIN_REQUEST, bool $catch = true,
): Response {
if ($type !== self::MAIN_REQUEST) {
return $this->httpKernel->handle($request, $type, $catch);
}
$requestWrapper = $this->requestWrapperFactory->fromRequest($request);
try {
$pageState = $this->pageStateFactory->fromRequest($request);
} catch (\ValueError $exception) {
$pageState = false;
}
if (
!$requestWrapper->isRefreshless() ||
$pageState === false
) {
return $this->httpKernel->handle($request, $type, $catch);
}
$libraries = $pageState->getLibraries();
/** @var int|false */
$index = array_search('refreshless_turbo/refreshless', $libraries);
if (is_int($index)) {
array_splice($libraries, $index, 1);
$pageState->setLibraries($libraries);
}
$ajaxPageState = [
'libraries' => implode(',', $libraries),
// Explicitly leave out 'theme' because that would cause Drupal to keep
// the user on whatever theme they started on, meaning we would never
// switch between the default and admin themes causing all sorts of weird
// and fun problems.
'theme_token' => $pageState->getThemeToken(),
];
if ($request->getMethod() === 'GET') {
$request->query->set(
'ajax_page_state', $ajaxPageState,
);
} else {
$request->request->set(
'ajax_page_state', $ajaxPageState,
);
}
return $this->httpKernel->handle($request, $type, $catch);
}
}
