Skip to content

Commit

Permalink
Fix the ajax reload responses not working correctly when the page sha…
Browse files Browse the repository at this point in the history
…red cache is enabled
  • Loading branch information
qzminski committed Jul 3, 2024
1 parent 8a9fda4 commit 3f5c017
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 23 deletions.
10 changes: 10 additions & 0 deletions src/AjaxReloadManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public function hasListeners(): bool

/**
* Get the response.
*
* @deprecated
*/
public function getResponse(): Response|null
{
Expand All @@ -89,6 +91,14 @@ public function getResponse(): Response|null
return $response;
}

/**
* Get the buffers.
*/
public function getBuffers(): array
{
return $this->buffers;
}

/**
* Return true if the listener is registered.
*/
Expand Down
74 changes: 51 additions & 23 deletions src/EventListener/AjaxReloadListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@
use Codefog\HasteBundle\AjaxReloadManager;
use Contao\ContentModel;
use Contao\CoreBundle\DependencyInjection\Attribute\AsHook;
use Contao\CoreBundle\Exception\ResponseException;
use Contao\CoreBundle\Routing\ScopeMatcher;
use Contao\ModuleModel;
use Symfony\Component\Asset\Packages;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\ResponseEvent;

class AjaxReloadListener
class AjaxReloadListener implements EventSubscriberInterface
{
public function __construct(
private readonly AjaxReloadManager $manager,
private readonly Packages $packages,
private readonly RequestStack $requestStack,
private readonly ScopeMatcher $scopeMatcher,
) {
}

Expand Down Expand Up @@ -59,30 +63,54 @@ public function onGetFrontendModule(ModuleModel $model, string $buffer): string
return $buffer;
}

#[AsHook('modifyFrontendPage')]
public function onModifyFrontendPage(string $buffer, string $template): string
public function onResponse(ResponseEvent $event): void
{
if (str_starts_with($template, 'fe_')) {
if (($response = $this->manager->getResponse()) !== null) {
throw new ResponseException($response);
}

$request = $this->requestStack->getCurrentRequest();

if ($this->manager->hasListeners()) {
$buffer = str_replace(
'</body>',
sprintf('<script src="%s"></script></body>', $this->packages->getUrl('ajax-reload.js', 'codefog_haste')),
$buffer,
);

// Make sure the request is not cached by the browser alongside with the
// initial request
$request->headers->set('Vary', 'Haste-Ajax-Reload');
}
$request = $event->getRequest();

// Only handle GET requests
if (!$request->isMethod(Request::METHOD_GET)) {
return;
}

return $buffer;
// Only handle frontend requests
if (!$this->scopeMatcher->isFrontendRequest($request)) {
return;
}

$response = $event->getResponse();

// Only handle text/html responses
if ($response->headers->get('Content-Type') === 'text/html') {
return;
}

// Modify the regular response
if ($this->manager->hasListeners() && !$request->headers->has('Haste-Ajax-Reload')) {
// Vary on the header, so we don't have the same URL cached
$response->headers->set('Vary', 'Haste-Ajax-Reload', false);

// Add the necessary <script> tags
$response->setContent(str_replace(
'</body>',
sprintf('<script src="%s"></script></body>', $this->packages->getUrl('ajax-reload.js', 'codefog_haste')),
$response->getContent(),
));

return;
}

// Return the requested buffers in an ajax response
if ($request->headers->has('Haste-Ajax-Reload') && ($buffers = $this->manager->getBuffers()) !== []) {
$response->setContent(json_encode($buffers));
$response->headers->set('Content-Type', 'application/json');
}
}

public static function getSubscribedEvents(): array
{
return [
ResponseEvent::class => 'onResponse',
];
}

/**
Expand Down

0 comments on commit 3f5c017

Please sign in to comment.