$params */ public function handle(Request $request, array $params): Response { $submitted = (string) ($request->post['_csrf'] ?? ''); $expected = (string) ($request->cookies['__csrf'] ?? ''); $secret = (string) ($request->server['__csrf_secret'] ?? ''); if ($secret === '' || $expected === '' || !CsrfToken::verify($submitted, $secret, $expected)) { return Response::html(403, '

Forbidden

'); } try { $draft = ScenarioDraft::fromPost($request->post); $scenario = $draft->toScenario(); ScenarioValidator::validate($scenario); } catch (\InvalidArgumentException $exception) { return $this->renderForm($request, $params['id'] ?? 'new', $request->cookies['__csrf'] ?? '', $exception->getMessage(), $request->post); } $json = json_encode($this->scenarioToArray($scenario), JSON_THROW_ON_ERROR); $url = (string) ($params['id'] ?? $scenario->id); $safeUrl = json_encode($url, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); $body = << Saved

Scenario saved.

HTML; return Response::html(200, $body); } /** @param array $post */ private function renderForm(Request $request, string $scenarioId, string $csrf, string $error, array $post): Response { $error = Escape::html($error); $csrf = Escape::html($csrf); $scenarioId = Escape::html($scenarioId); $old = array_intersect_key($post, array_flip([ 'id', 'name', 'battlefieldWidth', 'battlefieldHeight', 'victoryCondition', 'holdRoundsRequired', ])); $old = array_map(static fn ($v): string => is_scalar($v) ? (string) $v : '', $old); $teamA = $post['teamA']['units'] ?? []; $teamB = $post['teamB']['units'] ?? []; ob_start(); require_once __DIR__ . '/../../Views/layout.php'; require __DIR__ . '/../../Views/team-editor.php'; $body = (string) ob_get_clean(); return Response::html(200, $body); } /** @return array */ private function scenarioToArray(\BattleForge\Domain\Scenario $scenario): array { return \BattleForge\Application\ScenarioSerializer::scenarioToArray($scenario); } }