$id, 'type' => $type, 'message' => $message, 'scope' => $scope, 'key' => $key, ]; return $id; } public static function success(string $message, ?string $scope = null, ?string $key = null): string { return self::add('success', $message, $scope, $key); } public static function error(string $message, ?string $scope = null, ?string $key = null): string { return self::add('error', $message, $scope, $key); } public static function info(string $message, ?string $scope = null, ?string $key = null): string { return self::add('info', $message, $scope, $key); } public static function peek(?string $scope = null): array { self::ensureSession(); $messages = $_SESSION[self::SESSION_KEY] ?? []; if ($scope === null) { return $messages; } return array_values(array_filter($messages, function ($message) use ($scope) { $messageScope = $message['scope'] ?? null; return $messageScope === null || $messageScope === $scope; })); } public static function has(): bool { self::ensureSession(); return !empty($_SESSION[self::SESSION_KEY]); } public static function dismiss(string $id): void { self::ensureSession(); $messages = $_SESSION[self::SESSION_KEY] ?? []; $messages = array_values(array_filter($messages, function ($message) use ($id) { return ($message['id'] ?? '') !== $id; })); if ($messages) { $_SESSION[self::SESSION_KEY] = $messages; } else { unset($_SESSION[self::SESSION_KEY]); } } /** * Remove all flash messages matching a given key (and optionally scope). */ public static function dismissByKey(string $key, ?string $scope = null): void { self::ensureSession(); $messages = $_SESSION[self::SESSION_KEY] ?? []; $messages = array_values(array_filter($messages, function ($message) use ($key, $scope) { if (($message['key'] ?? null) !== $key) { return true; } if ($scope !== null && ($message['scope'] ?? null) !== $scope) { return true; } return false; })); if ($messages) { $_SESSION[self::SESSION_KEY] = $messages; } else { unset($_SESSION[self::SESSION_KEY]); } } // Prevents messages from being cleared on the next render — useful when a redirect chain crosses multiple pages. public static function keep(int $times = 1) { self::ensureSession(); $times = max(1, $times); $current = (int) ($_SESSION[self::KEEP_KEY] ?? 0); $_SESSION[self::KEEP_KEY] = max($current, $times); } }