the offered files of one kind, in the order they were offered */ public function of(string $kind): array { $files = $this->read()[$kind] ?? []; return array_values(array_filter($files, 'is_string')); } public function has(string $kind, string $file): bool { return in_array($file, $this->of($kind), true); } /** Offers a file or takes the offer back; answers whether that changed anything. */ public function set(string $kind, string $file, bool $offered): bool { if (!in_array($kind, self::KINDS, true)) { throw new InvalidArgumentException("Unknown kind: {$kind}"); } $all = $this->read(); $files = $this->of($kind); $has = in_array($file, $files, true); if ($has === $offered) { return false; } $all[$kind] = $offered ? [...$files, $file] : array_values(array_diff($files, [$file])); $json = json_encode($all, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); if ($json === false) { throw new RuntimeException('Cannot encode the demo files'); } AtomicFile::write($this->path, $json . "\n", AtomicFile::HIDDEN, 'demo file list'); return true; } /** @return array> */ private function read(): array { if (!is_file($this->path)) { return []; } $raw = file_get_contents($this->path); $data = $raw === false ? null : json_decode($raw, true); return is_array($data) ? $data : []; } }