Validácia konfigurácie
Config dodáva opakujúci sa mechanizmus — prečítať kľúč, overiť jeho tvar a pri nesprávnej konfigurácii viditeľne zlyhať — pričom doménové hranice zostávajú vo vašom kóde. Každý čítač je prísny: predvolená hodnota platí len pre nenastavený kľúč — chýbajúci, null alebo prázdny ('' či len medzery, čo vznikne z riadka KEY= u hostiteľa) — a každá iná neplatná hodnota vyhodí InvalidConfigurationException s názvom kľúča aj hodnoty. Statické čítače čítajú globálny konfiguračný repozitár:
use RoundlyConsulting\PackageToolkit\Support\Config;
// Strict config readers: the default applies only to a key that is not set (absent, null, or
// blank like a host's KEY=); an invalid value throws InvalidConfigurationException naming
// the key and the value.
Config::integer('comments.per_page', 20, min: 1, max: 100); // '20' → 20; '' → 20; 'five', '5.5', '1e3' throw
Config::float('comments.sample_rate', 1.0, min: 0, max: 1); // '0.25' → 0.25; '1e3', '0,5', '.5' throw
Config::requireString('comments.table'); // not set (absent or blank) throws missing
Config::string('comments.queue', 'default'); // blank COMMENTS_QUEUE= → 'default'; 5 throws
Config::list('comments.locales', ['en']); // 'en, sk' → ['en', 'sk']; ',' → ['en']
Config::enum('comments.hash_algo', HashAlgorithm::class); // no default: missing throws too
Config::enum('comments.sort', Sort::class, Sort::Newest); // absent → Sort::Newest; 'neweset' throws
Config::oneOf('comments.renderer', ['markdown', 'plain'], 'markdown'); // absent → 'markdown'; 'html' throws
Config::boolean('comments.allow_guests', false); // 'on'/'off' etc.; 'ture' throws
Config::requireSecret('comments.akismet_key'); // errors name the type, never the value| Prístup | Nenastavená (chýba, null alebo prázdna) | Hodnota neplatná |
|---|---|---|
integer(string $key, int $default, ?int $min = null, ?int $max = null) | Vráti $default — s rovnakou kontrolou rozsahu ako každá iná hodnota. | Vyhodí výnimku, ak nejde o int ani o kanonické celé číslo v reťazci ('30', '-5', ' 30 '); 'five', '5.5', '1e3' či pretekajúce číslo neprejdú a rovnako ani hodnota mimo $min / $max. |
float(string $key, float $default, ?float $min = null, ?float $max = null) | Vráti $default — tiež s kontrolou rozsahu; predvolená hodnota NAN alebo nekonečno vyhodí výnimku. | Vyhodí výnimku, ak nejde o int, konečný float ani kanonické desatinné číslo v reťazci ('0.25', '-0.5', ' 1 '); '1e3', '0,5', '.5', '5.', '+1' či 'NAN' neprejdú a rovnako ani hodnota mimo $min / $max. |
requireString(string $key) | Vyhodí missing — povinná hodnota nie je nastavená; prázdny reťazec alebo reťazec len z medzier sa počíta ako nenastavený. | Pre čokoľvek, čo nie je reťazec (int, bool, pole), vyhodí notAString. |
string(string $key, string $default) | Vráti $default — aj pri prázdnom KEY= u hostiteľa. | Pre čokoľvek, čo nie je reťazec (int, float, bool, pole), vyhodí notAString. Zadaný reťazec sa vráti neorezaný. |
list(string $key, array $default, ?Closure $each = null) | Vráti $default — aj keď hodnota neobsahuje žiadnu položku (',', []). | Vyhodí výnimku pre hodnotu, ktorá nie je poľom ani reťazcom, pre položku poľa, ktorá nie je reťazcom, a pre položku, pre ktorú $each nevráti true. |
enum(string $key, string $enum, ?BackedEnum $default = null) | Vráti $default; bez predvolenej hodnoty vyhodí výnimku. | Vyhodí výnimku so zoznamom povolených hodnôt — aj vtedy, keď je predvolená hodnota zadaná. Prípad enumu prejde; hodnota sa porovná presne a s rozlíšením veľkosti písmen po prevode na typ, ktorým je enum podložený. |
oneOf(string $key, array $allowed, string $default) | Vráti $default — ten však musí byť v $allowed. | Vyhodí výnimku so zoznamom $allowed, ak nejde o reťazec z neho (presne, s rozlíšením veľkosti písmen). |
boolean(string $key, bool $default = false) | Vráti $default. | Vyhodí výnimku, ak nejde o true / 1 / on / yes alebo false / 0 / off / no (bez ohľadu na veľkosť písmen, orezané). |
secret(string $key) | Vráti null. | Pre čokoľvek, čo nie je reťazec, vyhodí notAString a hodnotu opíše len jej typom. |
requireSecret(string $key) | Vyhodí missing. | Ako secret(): hodnotu opíše len jej typom. |
secretList(string $key, ?Closure $each = null) | Vráti [] — aj keď hodnota neobsahuje žiadnu položku. | Ako list(), no hodnotu či položku opíše len jej typom. |
Každá správa má rovnaký tvar — Configuration value [comments.per_page] must be between 1 and 100, [500] given. — takže kľúč aj chybnú hodnotu máte vždy priamo pred sebou. list() namiesto hodnoty uvedie chybnú položku (… must contain only valid items, [de] given.). Výnimkou sú čítače tajných hodnôt: hodnotu opíšu len jej typom ([int] given.) — pozrite časť Tajné hodnoty v konfigurácii a fasádach.
Celé čísla
Každá hodnota z env je reťazec, preto integer() prijme int alebo kanonické celé číslo v reťazci: voliteľné -, desiatkové číslice, okolité medzery sa ignorujú ('30', '-5', ' 30 '). Prázdne '' sa počíta ako nenastavené a vráti predvolenú hodnotu. Odmietne to, čo by hrubé pretypovanie (int) potichu zmenilo na iné číslo — 'five', '5.5', '5abc', '1e3', '0x10', '+5', pretekajúce číslo, float, bool aj pole vyhodia výnimku. Kontrola rozsahu $min / $max platí aj pre predvolenú hodnotu:
use RoundlyConsulting\PackageToolkit\Support\Config;
// .env: COMMENTS_PER_PAGE=" 30 " — surrounding whitespace is ignored
Config::integer('comments.per_page', 20, min: 1, max: 100); // 30
// COMMENTS_PER_PAGE unset, or blank (COMMENTS_PER_PAGE=) — not set, so the default,
// range-checked like any other value
Config::integer('comments.per_page', 20, min: 1, max: 100); // 20
// .env: COMMENTS_PER_PAGE=1e3 — not a canonical integer string
Config::integer('comments.per_page', 20, min: 1, max: 100);
// throws: Configuration value [comments.per_page] must be an integer, [1e3] given.
// .env: COMMENTS_PER_PAGE=500 — out of range
// throws: Configuration value [comments.per_page] must be between 1 and 100, [500] given.Desatinné čísla
float() číta desatinné nastavenie, napríklad mieru vzorkovania. Prijme int, konečný float alebo kanonické desatinné číslo v reťazci: voliteľné -, číslice, prípadne bodka a za ňou číslice, okolité medzery sa ignorujú ('0.25', '-0.5', ' 1 ', '3', '007.50'). Výsledok je vždy float ('3' → 3.0). Všetko ostatné vyhodí must be a decimal number — 'abc', '1e3', '0,5', '+1', '.5', '5.', '1.2.3', '0x1A', 'NAN', 'INF', reťazec príliš dlhý na float, floaty NAN a INF, bool aj pole. '.5' a '5.' sa odmietnu, nie odhadnú, rovnako ako pri integer(). $min a $max sú inkluzívne a navzájom nezávislé a správa ich vypíše tak, ako boli zadané (must be between 0 and 1, at least 0.5). Ak kľúč nie je nastavený, použije sa predvolená hodnota, skontroluje sa jej rozsah a odmietne sa, ak je NAN alebo nekonečno:
use RoundlyConsulting\PackageToolkit\Support\Config;
// .env: COMMENTS_SAMPLE_RATE=0.25
Config::float('comments.sample_rate', 1.0, min: 0, max: 1); // 0.25
// COMMENTS_SAMPLE_RATE unset, or blank — the default, range-checked too
Config::float('comments.sample_rate', 1.0, min: 0, max: 1); // 1.0
// .env: COMMENTS_SAMPLE_RATE=0,5 — not a canonical decimal string
// throws: Configuration value [comments.sample_rate] must be a decimal number, [0,5] given.
// .env: COMMENTS_SAMPLE_RATE=1.5 — out of range
// throws: Configuration value [comments.sample_rate] must be between 0 and 1, [1.5] given.Voliteľné reťazce
string() slúži pre reťazcové nastavenie s predvolenou hodnotou z balíka — názov fronty, guard, audience či prefix rout. Nenastavená hodnota vrátane prázdneho COMMENTS_QUEUE= u hostiteľa vráti predvolenú hodnotu tam, kde by (string) config(...) vrátilo ''. Zadaný reťazec sa vráti tak, ako je, nikdy neorezaný, takže tajná hodnota či vzor si zachová každý znak; čokoľvek, čo nie je reťazec (int, float, bool, pole), vyhodí must be a non-empty string. Prepínač, ktorý by prázdnu hodnotu prepustil, neexistuje — prázdna hodnota vždy znamená predvolenú — a samotná predvolená hodnota sa vráti tak, ako je, bez kontroly:
use RoundlyConsulting\PackageToolkit\Support\Config;
// .env: COMMENTS_QUEUE= — blank, so the default; (string) config(...) would give ''
Config::string('comments.queue', 'default'); // 'default'
// config('comments.queue') === 5 — not a string
// throws: Configuration value [comments.queue] must be a non-empty string, [5] given.Zoznamy
list() je jeden čítač pre oba spôsoby, akými sa zoznam dostane do konfigurácie: publikovaný konfiguračný súbor obsahuje PHP pole, premenná prostredia reťazec oddelený čiarkami. Voliteľnou closure $each overíte každú položku:
// config/comments.php
return [
'locales' => env('COMMENTS_LOCALES'), // 'en, sk' from env, or publish an array here
];
// In your package
$locales = Config::list('comments.locales', ['en'], fn (string $locale): bool => in_array($locale, ['en', 'sk', 'de'], true));
// .env: COMMENTS_LOCALES="en, fr"
// throws: Configuration value [comments.locales] must contain only valid items, [fr] given.| Hodnota v konfigurácii | Výsledok |
|---|---|
['en', 'sk'], ' en, sk ', 'en,,sk', [' en ', '', 'sk'] | ['en', 'sk'] |
['x' => 'en', 'y' => 'sk'] | ['en', 'sk'] — kľúče sa zahodia, indexy sa prečíslujú |
| Nenastavená: chýbajúca, null, '' alebo len medzery | $default |
| Bez položiek: ',', ' , ', [] alebo [' ', ''] | $default |
| 5, 1.5, true, objekt | Vyhodí must be a list of strings (an array or a comma-separated string). |
| Pole s položkou, ktorá nie je reťazcom: ['en', 5], ['en', null] | Vyhodí must contain only string items, [5] given. |
| Položka, pre ktorú $each nevráti true | Vyhodí must contain only valid items, [de] given. |
- Položky sa orežú a prázdne vypadnú. Vnútorné medzery a duplikáty zostanú ('en GB' je stále jedna položka; 'a,a' je ['a', 'a']) a čiarka vnútri položky poľa sa nerozdelí.
- Zoznam bez položiek sa počíta ako nenastavený, rovnako ako prázdna hodnota, takže platí predvolená hodnota. Hostiteľ preto nemôže nastaviť prázdny zoznam namiesto neprázdneho predvoleného — ak musí byť možné „nič“, dodajte ako predvolenú hodnotu [].
- Predvolená hodnota sa normalizuje rovnako (orezanie, vypustenie prázdnych, prečíslovanie) a keď sa vracia, prejde aj cez $each — tak ako integer() kontroluje rozsah predvolenej hodnoty. Predvolená hodnota, ktorú $each odmietne, vyhodí výnimku.
- $each je Closure(string): bool a dostane každú orezanú položku. Položku prijme len návratová hodnota true, takže closure, ktorá vracia 1 z preg_match(), odmietne všetko — porovnávajte cez === 1.
- list je v PHP rezervované slovo, no platný názov metódy: Config::list() aj $validator->list() fungujú na PHP 8.4 a Pint aj Larastan ich akceptujú.
Enumy a pevné slovníky
enum() prijme prípad enumu alebo jeho hodnotu, porovnanú presne a s rozlíšením veľkosti písmen ('UUID' sa nezhoduje s 'uuid'). Hodnota sa najprv prevedie na typ, ktorým je enum podložený — '2' nájde prípad enumu podloženého typom int (podľa pravidiel pre celé čísla vyššie) a int nájde číselný prípad enumu podloženého reťazcom. Čokoľvek iné vyhodí výnimku so zoznamom povolených hodnôt, aj keď je predvolená hodnota zadaná; TypeError nikdy neunikne. oneOf() má rovnaký kontrakt pre obyčajný slovník reťazcov bez enumu:
use RoundlyConsulting\PackageToolkit\Support\Config;
enum Priority: int
{
case Low = 1;
case High = 2;
}
// .env: COMMENTS_PRIORITY=2 — every env value is a string
Config::enum('comments.priority', Priority::class); // Priority::High
// .env: COMMENTS_PRIORITY=2.0 — not a canonical integer string, so it names no case
Config::enum('comments.priority', Priority::class, Priority::Low); // throws — a default never stands in for a typo
Config::enum('comments.priority', Priority::class); // throws InvalidConfigurationExceptionNenastavená verzus neplatná hodnota
Prázdna hodnota nie je preklep: '' alebo len medzery — čo vznikne z riadka KEY= u hostiteľa — sa počíta ako nenastavená a dostane predvolenú hodnotu rovnako ako chýbajúci kľúč. requireString(), requireSecret() a enum() volaný bez predvolenej hodnoty sa nemajú k čomu vrátiť, preto tam prázdna hodnota vyhodí missing. Predvolená hodnota však nikdy nezakryje preklep. Hodnota z env, ktorá je zadaná, no nesprávna — preklep v enume, boolean zapísaný ako 'disabled', renderer mimo slovníka — zastaví aplikáciu so správou s názvom kľúča aj hodnoty, namiesto toho, aby sa potichu použila predvolená hodnota:
use RoundlyConsulting\PackageToolkit\Enums\KeyType;
use RoundlyConsulting\PackageToolkit\Support\Config;
// config('comments.key_type') === 'uudi' — a typo
Config::enum('comments.key_type', KeyType::class, KeyType::BigInt);
// throws InvalidConfigurationException — the default covers only a key that is not set:
// Configuration value [comments.key_type] must be one of [bigint, uuid, ulid], [uudi] given.
// .env: COMMENTS_ALLOW_GUESTS=disabled
Config::boolean('comments.allow_guests', false);
// throws InvalidConfigurationException:
// Configuration value [comments.allow_guests] must be a boolean (true/false, 1/0, on/off or yes/no), [disabled] given.
// config('comments.renderer') === 'html'
Config::oneOf('comments.renderer', ['markdown', 'plain'], 'markdown');
// throws InvalidConfigurationException:
// Configuration value [comments.renderer] must be one of [markdown, plain], [html] given.Prepínače v phpunit.xml
V phpunit.xml píšte on/off alebo 1/0, nikdy true/false. PHPUnit zmení value="false" na prázdny reťazec, ktorý prísne čítače považujú za nenastavený — namiesto „off“ sa teda použije predvolená hodnota. value="off" alebo value="0" sa do boolean() dostane presne tak, ako je zapísané:
<!-- Arrives as '' — not set, so boolean() returns the default, not false -->
<env name="COMMENTS_ALLOW_GUESTS" value="false"/>
<!-- Reaches boolean() as written: false -->
<env name="COMMENTS_ALLOW_GUESTS" value="off"/>Validácia vstupu DTO
Statické prístupy čítajú globálny konfiguračný repozitár podľa kľúča. Keď DTO overuje pole, ktoré dostalo (fromArray()), čítanie repozitára by prepustilo hodnotu, ktorú volajúci vôbec neodovzdal — preto spustite validátor naviazaný na toto pole cez Config::for(). Kľúče podporujú bodkovú notáciu. Ako druhý argument uveďte vlastnú triedu výnimky vášho balíka a chybná konfigurácia sa prejaví cez vašu hierarchiu, nie cez hierarchiu toolkitu:
use RoundlyConsulting\PackageToolkit\Support\Config;
final readonly class PasskeyConfig
{
public static function fromArray(array $config): self
{
$v = Config::for($config, PasskeyException::class);
return new self(
timeout: $v->integer('timeout', 60, min: 1, max: 300), // validates the 99999 you were handed
trust: $v->enum('attestation', TrustMode::class), // a typo throws PasskeyException, never a silent downgrade
rpId: $v->requireString('rp_id'),
);
}
}Vlastná výnimka, globálna konfigurácia
Config::using() poskytne rovnaký validátor s určenou výnimkou, ale naďalej číta globálny repozitár — pre konfiguráciu, ktorú balík vlastní celú. Určená trieda musí prijať textovú správu; správa toolkitu sa zachová:
use RoundlyConsulting\PackageToolkit\Support\Config;
$v = Config::using(CommentsException::class);
$perPage = $v->integer('comments.per_page', 20, min: 1, max: 100);
$algo = $v->enum('comments.hash_algo', HashAlgorithm::class);
// a misconfiguration throws CommentsException, carrying the toolkit's messageObe vracajú ConfigValidator so všetkými jedenástimi čítačmi, ktoré majú statické prístupy — integer(), float(), requireString(), string(), list(), enum(), oneOf(), boolean(), secret(), requireSecret() a secretList() — takže aj prepínač v odovzdanom poli viditeľne zlyhá. ConfigValidator::forArray() a ConfigValidator::forRepository() sú konštruktory, na ktorých stoja:
$v = Config::for($config, PasskeyException::class);
$v->boolean('user_verification', true); // absent or blank → true; 'ture' throws PasskeyException
Config::using(PasskeyException::class)->boolean('passkeys.enabled', false);Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.