Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.00% covered (warning)
88.00%
22 / 25
75.00% covered (warning)
75.00%
6 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
Env
88.00% covered (warning)
88.00%
22 / 25
75.00% covered (warning)
75.00%
6 / 8
20.69
0.00% covered (danger)
0.00%
0 / 1
 load
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 require
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 validate
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
7
 string
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 bool
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 int
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isBoolean
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
3.04
 isInteger
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Config;
6
7use Cosray\Exception\InvalidEnvironment;
8
9use function Cosray\env;
10
11final class Env
12{
13    /** @var list<string> */
14    private const BOOLEAN = ['APP_DEBUG', 'SITE_SESSION_ENABLED', 'SESSION_COOKIE_SECURE'];
15
16    /** @var list<string> */
17    private const INTEGER = [
18        'AUTH_REMEMBER_LIFETIME',
19        'SESSION_COOKIE_LIFETIME',
20        'SESSION_IDLE_TIMEOUT',
21    ];
22
23    public static function load(): self
24    {
25        return new self();
26    }
27
28    /** @param non-empty-string|list<non-empty-string> $variables */
29    public function require(string|array $variables): void
30    {
31        $missing = array_filter((array) $variables, static fn(string $key): bool => env($key) === null);
32
33        if ($missing !== []) {
34            throw new InvalidEnvironment(
35                'Missing required environment variable(s): ' . implode(', ', $missing),
36            );
37        }
38    }
39
40    public function validate(): void
41    {
42        foreach (self::BOOLEAN as $key) {
43            $value = env($key);
44
45            if ($value !== null && !self::isBoolean($value)) {
46                throw new InvalidEnvironment("Environment variable {$key} must be a boolean.");
47            }
48        }
49
50        foreach (self::INTEGER as $key) {
51            $value = env($key);
52
53            if ($value !== null && !self::isInteger($value)) {
54                throw new InvalidEnvironment("Environment variable {$key} must be an integer.");
55            }
56        }
57    }
58
59    public function string(string $key, ?string $default = null): ?string
60    {
61        $value = env($key, $default);
62
63        return $value === null ? null : (string) $value;
64    }
65
66    public function bool(string $key, bool $default): bool
67    {
68        return filter_var(env($key, $default), FILTER_VALIDATE_BOOL);
69    }
70
71    public function int(string $key, int $default): int
72    {
73        return (int) env($key, $default);
74    }
75
76    private static function isBoolean(mixed $value): bool
77    {
78        if (is_bool($value)) {
79            return true;
80        }
81
82        return (
83            is_string($value)
84                && in_array(strtolower($value), ['1', '0', 'true', 'false', 'on', 'off', 'yes', 'no'], true)
85        );
86    }
87
88    private static function isInteger(mixed $value): bool
89    {
90        return is_int($value) || is_string($value) && ctype_digit($value);
91    }
92}