Architektonické presety
Deväť skladateľných presetov, každý postavený na chybe, ktorá sa reálne dostala do vydania. Zavolajte ho na najvyššej úrovni Pest arch súboru; test si zaregistruje sám. Arch súbor naviažte na svoj TestCase postavený na PackageTestCase — uses(TestCase::class)->in('Arch', …) v tests/Pest.php, ako v Inštalácii: swappableModelsAreNotFinal číta predvolenú hodnotu konfigurácie zo spustenej aplikácie a bez nej zlyhá s návodom.
use RoundlyConsulting\Testing\Arch\ArchPresets;
ArchPresets::strictTypes(string $namespace, array $ignoring = []);
ArchPresets::finalByDefault(string $namespace, array $ignoring = []);
ArchPresets::swappableModelsAreNotFinal(array $map); // [Shop::class => 'shops.shop_model']
ArchPresets::noLocalCryptoPrimitives(string $namespace, array $ignoring = []);
ArchPresets::modelsResolveThroughSeam(string $srcDir, string $seamDir = 'Support', array $modelKeys = []);
ArchPresets::morphColumnsUseTheSeam(string $migrationsDir); // no raw $table->morphs()
ArchPresets::runtimeRequireIsWhitelisted(string $composerJson, array $alsoAllow = []);
ArchPresets::noDebuggingLeftovers(array $ignoring = [], ?string $srcDir = null); // dd/dump/ray/var_dump/print_r, ->dd()
ArchPresets::modelsGoThroughTheFacade(string $namespace, array $ignoring = []); // models/traits never call actions
// Helpers the presets build on
ArchPresets::shadowedClassesAreFinal(string $namespace, array $exemptions); // only if you use ->ignoring()
ArchPresets::exemptionsExist(array $exemptions, string $for, ?string $within = null); // the pin the presets register for youČo ktorý stráži
| Preset | Pravidlo — a chyba, ktorej predchádza |
|---|---|
strictTypes | Každý súbor deklaruje strict_types=1, takže sa nevkradne tichá konverzia typov. |
finalByDefault | Triedy sú predvolene final; abstraktné triedy sa vylúčia automaticky (abstract final je v PHP fatálna chyba). Predchádza nechceným bodom rozšírenia. |
swappableModelsAreNotFinal | Každý namapovaný model nie je final a jeho konfiguračný kľúč predvolene ukazuje práve naň. final na vymeniteľnom modeli spôsobil fatálnu chybu PHP hneď pri výmene — a vyšiel sedemkrát. |
noLocalCryptoPrimitives | Žiadne lokálne kryptografické primitíva (ArchPresets::CRYPTO_PRIMITIVES — hash, hash_hmac, openssl_*, sodium_*, random_bytes, random_int, base64_* a ďalšie). hash_equals je zámerne povolené: je to porovnanie v konštantnom čase priamo v PHP. |
modelsResolveThroughSeam | Žiadne static::query(), self::query() ani new static v statickom kontexte modelu a konfiguračné literály výmeny sa smú vyskytnúť len v adresári seamu. Takéto obídenie raz rozbilo autorizáciu. |
morphColumnsUseTheSeam | Žiadne surové morphs(), nullableMorphs() ani ich uuid/ulid varianty v adresári migrácií — polymorfné stĺpce musia ísť cez makro morphKey() z package toolkitu. Chýbajúci alebo prázdny adresár zlyhá. |
runtimeRequireIsWhitelisted | require v composer.json obsahuje len php, ext-*, illuminate/*, laravel/*, symfony/* a roundly-consulting/*, plus presné názvy v $alsoAllow. Každý nepovolený vendor sa uvedie menom. |
noDebuggingLeftovers | Žiadne dd, dump, ray, var_dump ani print_r — ani pomocníci, ktorých Laravel vešia na vlastné objekty: ->dd(), ->ddRawSql(), ->dumpRawSql(). Hľadá sa v tokenoch zdrojového kódu, predvolene v <cwd>/src, takže ray() zachytí aj bez nainštalovaného balíka debuggera Ray. Reťazené ->dump() je zámerne povolené, keďže $yaml->dump() je bežné API. |
modelsGoThroughTheFacade | Žiadna metóda ani trait modelu neodkazuje na menný priestor Actions balíka, takže každá zmena ide cez manažér a fake() fasády ju vidí — pozrite Kontrakt fasády. |
strictTypes, finalByDefault a noLocalCryptoPrimitives stoja na arch vrstve Pestu a vracajú arch expectation. Zvyšných šesť vyjadruje to, čo arch vrstva Pestu nedokáže, a namiesto toho registruje test it() založený na tokenoch či reflexii.
Vlastný arch test Pestu prejde aj nad prázdnou množinou, preto každý z týchto troch presetov viazaných na menný priestor registruje aj sprievodný test („preset: … has something to check“), ktorý zlyhá, keď sa menný priestor cez PSR-4 mapu Composera nepreloží na nič (jedno preklepnuté písmeno) alebo keď $ignoring vylúči všetko, čo obsahuje.
Typický arch súbor
<?php
declare(strict_types=1);
use RoundlyConsulting\Shops\Exceptions\ShopsException;
use RoundlyConsulting\Shops\Shops\Shop;
use RoundlyConsulting\Testing\Arch\ArchPresets;
ArchPresets::strictTypes('RoundlyConsulting\Shops');
// Exempt the intentional extension points through the checked parameter…
ArchPresets::finalByDefault('RoundlyConsulting\Shops', [Shop::class, ShopsException::class]);
// …and pin the swappable model with the counter-weight preset.
ArchPresets::swappableModelsAreNotFinal([Shop::class => 'shops.shop_model']);
ArchPresets::noLocalCryptoPrimitives('RoundlyConsulting\Shops');
ArchPresets::modelsResolveThroughSeam(__DIR__.'/../src', 'Support');
ArchPresets::morphColumnsUseTheSeam(__DIR__.'/../database/migrations');
ArchPresets::runtimeRequireIsWhitelisted(__DIR__.'/../composer.json');
ArchPresets::noDebuggingLeftovers();
ArchPresets::modelsGoThroughTheFacade('RoundlyConsulting\Shops');Zámerné napätie
finalByDefault chce mať každú triedu final; swappableModelsAreNotFinal zakazuje final na modeli vymeniteľnom cez konfiguráciu. Toto napätie je zámerné — spúšťajte oba: vymeniteľné modely z prvého vylúčte cez $ignoring a druhým ich pripnite. Prázdna mapa zlyhá, namiesto toho aby prešla naprázdno. Rovnaká kontrola existuje aj pre jednotlivý model ako expectation a ako statické zrkadlo:
expect(Shop::class)->toBeSwappableVia('shops.shop_model');
// The same check for plain PHPUnit
Assert::modelIsSwappableVia(Shop::class, 'shops.shop_model');Všetky tri čítajú predvolenú hodnotu konfigurácie, preto potrebujú spustenú aplikáciu — naviažte súbor na svoj TestCase postavený na PackageTestCase.
Deklarácia kľúčov pre modelsResolveThroughSeam
Bez deklarácie odvodzuje polovica pre zatúlané literály kľúče výmeny z ich tvaru — model, models alebo *_model — a stráži len tie. Ak má niektorý váš kľúč výmeny iný tvar, zoznam deklarujte. Deklarované kľúče sa zjednotia s odvodenými a deklarovaný kľúč, ktorý nezodpovedá žiadnemu literálu vo vašom kóde, zlyhá:
ArchPresets::modelsResolveThroughSeam(__DIR__.'/../src', 'Support', [
'alerts.alert', 'alerts.health-check', 'alerts.silence-model', 'alerts.history.model',
]);Polovica pre neskoré statické viazanie sa uplatní len v statickom kontexte. V inštančnej metóde self::query() už pracuje s triedou $this za behu — teda s nakonfigurovanou — takže je správne a nenahlási sa. Zákaz sa navyše týka len tried, ktoré rozširujú Model.
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.