72 lines
2.3 KiB
PHP
72 lines
2.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace BattleForge\Http\Handlers;
|
|
|
|
use BattleForge\Application\ScenarioSerializer;
|
|
use BattleForge\Domain\ScenarioValidator;
|
|
use BattleForge\Http\Request;
|
|
use BattleForge\Http\Response;
|
|
use InvalidArgumentException;
|
|
|
|
final class GetBundledScenario
|
|
{
|
|
private const ID_PATTERN = '/^[a-z0-9-]+$/';
|
|
|
|
public function __construct(private readonly string $scenariosDir)
|
|
{
|
|
}
|
|
|
|
/** @param array<string, string> $params */
|
|
public function handle(Request $request, array $params): Response
|
|
{
|
|
$id = (string) ($params['id'] ?? '');
|
|
|
|
if (preg_match(self::ID_PATTERN, $id) !== 1) {
|
|
return Response::json(404, ['error' => 'not found']);
|
|
}
|
|
|
|
$manifestPath = $this->scenariosDir . '/manifest.json';
|
|
$manifest = [];
|
|
if (is_file($manifestPath)) {
|
|
$decoded = json_decode((string) file_get_contents($manifestPath), true);
|
|
if (is_array($decoded)) {
|
|
$manifest = $decoded;
|
|
}
|
|
}
|
|
|
|
if (!isset($manifest[$id])) {
|
|
return Response::json(404, ['error' => 'not found']);
|
|
}
|
|
|
|
$fixturePath = $this->scenariosDir . '/' . $id . '.json';
|
|
$real = realpath($fixturePath);
|
|
$realDir = realpath($this->scenariosDir);
|
|
$insideBase = $real !== false
|
|
&& $realDir !== false
|
|
&& str_starts_with($real, $realDir . DIRECTORY_SEPARATOR);
|
|
if ($insideBase === false || !is_file($real)) {
|
|
return Response::json(404, ['error' => 'not found']);
|
|
}
|
|
|
|
$data = json_decode((string) file_get_contents($real), true, flags: JSON_THROW_ON_ERROR);
|
|
if (!is_array($data)) {
|
|
return Response::json(500, ['error' => 'fixture invalid', 'details' => ['Fixture JSON is not an object.']]);
|
|
}
|
|
|
|
try {
|
|
$scenario = ScenarioSerializer::scenarioFromArray($data);
|
|
} catch (InvalidArgumentException $exception) {
|
|
return Response::json(500, ['error' => 'fixture invalid', 'details' => [$exception->getMessage()]]);
|
|
}
|
|
|
|
$errors = ScenarioValidator::validate($scenario);
|
|
if ($errors !== []) {
|
|
return Response::json(500, ['error' => 'fixture invalid', 'details' => $errors]);
|
|
}
|
|
|
|
return Response::json(200, ScenarioSerializer::scenarioToArray($scenario));
|
|
}
|
|
}
|