NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky
Testing for Laravel

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

PresetPravidlo — a chyba, ktorej predchádza
strictTypesKaždý súbor deklaruje strict_types=1, takže sa nevkradne tichá konverzia typov.
finalByDefaultTriedy sú predvolene final; abstraktné triedy sa vylúčia automaticky (abstract final je v PHP fatálna chyba). Predchádza nechceným bodom rozšírenia.
swappableModelsAreNotFinalKaž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á.
runtimeRequireIsWhitelistedrequire 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 kryptomien

Odoslaní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.