Page context menu: Purge from SSR cache
SsrPurgeItemProvider adds the item behind Clear cache for real pages (doktype < 199) whenever the purge endpoint is configured. The callback module posts the page uid to the new vitec_ssr_purge_page ajax route, which resolves the page path through the site router, purges it via SsrPurgeService (trigger contextmenu:username, logged as usual) and reports back as a toast notification. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fa63871da7
commit
5b524bfce9
4 files changed
+132
No files matched your search
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evomedien\Vitec\ContextMenu;
|
||||
|
||||
use TYPO3\CMS\Backend\ContextMenu\ItemProviders\AbstractProvider;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
|
||||
/**
|
||||
* Page tree context menu: "Purge from SSR cache" - evicts exactly this
|
||||
* page from the SSR node's full-page cache, with toast feedback.
|
||||
* Shown only for real pages and only while the purge endpoint is
|
||||
* configured (var/vitec-ssr-purge.env).
|
||||
*/
|
||||
final class SsrPurgeItemProvider extends AbstractProvider
|
||||
{
|
||||
protected $itemsConfiguration = [
|
||||
'ssrPurge' => [
|
||||
'type' => 'item',
|
||||
'label' => 'Purge from SSR cache',
|
||||
'iconIdentifier' => 'actions-system-cache-clear-impact-medium',
|
||||
'callbackAction' => 'ssrPurge',
|
||||
],
|
||||
];
|
||||
|
||||
public function canHandle(): bool
|
||||
{
|
||||
return $this->table === 'pages';
|
||||
}
|
||||
|
||||
/**
|
||||
* Below the core PageProvider (100): we run after it and splice our
|
||||
* item into the finished menu, right behind "Clear cache".
|
||||
*/
|
||||
public function getPriority(): int
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
public function addItems(array $items): array
|
||||
{
|
||||
if (!is_readable(Environment::getVarPath() . '/vitec-ssr-purge.env')) {
|
||||
return $items;
|
||||
}
|
||||
$page = BackendUtility::getRecord('pages', (int)$this->identifier, 'uid,doktype');
|
||||
if ($page === null || (int)$page['doktype'] >= 199) {
|
||||
// Spacers, folders, recycler - nothing cached for those.
|
||||
return $items;
|
||||
}
|
||||
$this->initDisabledItems();
|
||||
$localItems = $this->prepareItems($this->itemsConfiguration);
|
||||
if (isset($items['clearCache'])) {
|
||||
$new = [];
|
||||
foreach ($items as $key => $item) {
|
||||
$new[$key] = $item;
|
||||
if ($key === 'clearCache') {
|
||||
$new = array_merge($new, $localItems);
|
||||
}
|
||||
}
|
||||
return $new;
|
||||
}
|
||||
return array_merge($items, $localItems);
|
||||
}
|
||||
|
||||
protected function getAdditionalAttributes(string $itemName): array
|
||||
{
|
||||
return ['data-callback-module' => '@evomedien/vitec/ssr-context-menu.js'];
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,11 @@ use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Http\JsonResponse;
|
||||
use TYPO3\CMS\Core\Http\RedirectResponse;
|
||||
use TYPO3\CMS\Core\Http\RequestFactory;
|
||||
use TYPO3\CMS\Core\Messaging\FlashMessage;
|
||||
use TYPO3\CMS\Core\Site\SiteFinder;
|
||||
use TYPO3\CMS\Core\Messaging\FlashMessageService;
|
||||
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
@@ -100,6 +102,32 @@ final class SsrController
|
||||
return new RedirectResponse((string)$this->uriBuilder->buildUriFromRoute('web_vitecssr'), 303);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax route vitec_ssr_purge_page: purge exactly one page, called by
|
||||
* the page tree context menu item (ssr-context-menu.js).
|
||||
*/
|
||||
public function purgePage(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$body = (array)($request->getParsedBody() ?? []);
|
||||
$pageUid = (int)($body['pageUid'] ?? ($request->getQueryParams()['pageUid'] ?? 0));
|
||||
if ($pageUid <= 0) {
|
||||
return new JsonResponse(['success' => false, 'message' => 'No page uid given'], 400);
|
||||
}
|
||||
try {
|
||||
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($pageUid);
|
||||
$path = $site->getRouter()->generateUri($pageUid)->getPath() ?: '/';
|
||||
} catch (\Throwable) {
|
||||
return new JsonResponse(['success' => false, 'message' => 'Page has no routable URL (folder?)']);
|
||||
}
|
||||
$user = (string)($GLOBALS['BE_USER']->user['username'] ?? '?');
|
||||
$result = $this->purgeService->purge([$path], 'contextmenu:' . $user);
|
||||
return new JsonResponse([
|
||||
'success' => $result['success'],
|
||||
'path' => $path,
|
||||
'message' => 'HTTP ' . $result['httpCode'] . ' - ' . $result['message'],
|
||||
]);
|
||||
}
|
||||
|
||||
private function rows(string $table, int $limit): array
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -27,4 +27,10 @@ return [
|
||||
'path' => '/vitec/product/field/save',
|
||||
'target' => ProductTextImportController::class . '::fieldSave',
|
||||
],
|
||||
// Context menu "Purge from SSR cache" (SsrPurgeItemProvider +
|
||||
// Resources/Public/Javascript/ssr-context-menu.js).
|
||||
'vitec_ssr_purge_page' => [
|
||||
'path' => '/vitec/ssr/purge-page',
|
||||
'target' => \Evomedien\Vitec\Controller\Backend\SsrController::class . '::purgePage',
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Context menu action "Purge from SSR cache" (SsrPurgeItemProvider).
|
||||
* Posts the page uid to the vitec_ssr_purge_page ajax route and shows
|
||||
* the outcome as a backend notification.
|
||||
*/
|
||||
import AjaxRequest from '@typo3/core/ajax/ajax-request.js';
|
||||
import Notification from '@typo3/backend/notification.js';
|
||||
|
||||
class SsrContextMenuActions {
|
||||
ssrPurge(table, uid) {
|
||||
new AjaxRequest(TYPO3.settings.ajaxUrls.vitec_ssr_purge_page)
|
||||
.post({ pageUid: uid })
|
||||
.then(async (response) => {
|
||||
const data = await response.resolve();
|
||||
if (data.success) {
|
||||
Notification.success('SSR cache purged', data.path + ' (' + data.message + ')', 5);
|
||||
} else {
|
||||
Notification.error('SSR purge failed', data.message || 'Unknown error', 8);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
Notification.error('SSR purge failed', 'Request error - see purge protocol in the VITEC SSR module', 8);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new SsrContextMenuActions();
|
||||
Reference in new issue
Block a user