refactor(entry-actions): dedup scope guard + guard publish cache-flush

Address code-review findings on the trip publish/unpublish toggle:

- Extract EntryScopeGuard::resolveChildOf() so resolveActiveDailyChild and
  resolveTripChild share one find() + parent-route-assert body instead of two
  copies that could drift (P1 maintainability).
- Wrap setTripPublished's post-save cache invalidation in try/catch. save() has
  already persisted the published flag to disk, so a flush failure now logs a
  loud reconciliation warning (and still returns success + the audit line)
  rather than bubbling to a bare 500 that reads as "nothing happened"
  (P2 reliability / adversarial).

Behavior-preserving; PHP lint clean; trip-publish Playwright suite 8/8.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
This commit is contained in:
2026-07-08 17:06:17 +02:00
co-authored by Claude Opus 4.8
parent 064f0f0c52
commit 5b4e31678e
2 changed files with 42 additions and 33 deletions
@@ -209,12 +209,26 @@ class EntryActionsApiController extends AbstractApiController
// store (deleteAll → APCu flushAll) AND apcu_clear_cache() directly to be
// certain, clear the compiled files, and reset the in-memory tree so the
// next request rebuilds from disk and re-reads the published flag.
$this->grav['cache']->deleteAll();
if (function_exists('apcu_clear_cache')) {
apcu_clear_cache();
// save() above is already persisted to disk. If any invalidation call
// throws, do NOT let it bubble to a plain 500 (which reads to the owner as
// "nothing happened") and skip the audit line: the on-disk flag DID change.
// Log a loud reconciliation warning instead so an operator knows to clear
// cache manually, then still report success.
try {
$this->grav['cache']->deleteAll();
if (function_exists('apcu_clear_cache')) {
apcu_clear_cache();
}
$this->grav['pages']->reset();
$this->grav['cache']->clearCache('standard');
} catch (\Throwable $e) {
$this->grav['log']->error(sprintf(
'entry-actions: trip "%s" published=%s SAVED to disk but cache invalidation failed (%s) — clear cache manually',
$slug,
$published ? 'true' : 'false',
$e->getMessage()
));
}
$this->grav['pages']->reset();
$this->grav['cache']->clearCache('standard');
// Audit trail: publish state is owner-only and changes site-wide
// visibility — record who flipped which trip to what.
$this->grav['log']->info(sprintf('entry-actions: owner "%s" set trip "%s" published=%s', $user->username, $slug, $published ? 'true' : 'false'));