Releaser & uppdateringar
En översikt av förändringar i Radix. För fullständig historik och taggar/versioner, se GitHub‑releaser.
v1.2.8 ORM: förbättrad relationsladdning och query-stöd
Framework Senaste
Den här releasen innehåller en större förbättring av ORM-lagrets relationer, eager loading
och constrained loading. Fokus har varit att göra relationerna mer konsekventa, mer
testbara och enklare att använda tillsammans med QueryBuilder.
Alla ändringar är verifierade med:
PHPUnit: grönt
PHPStan: grönt
GitHub Actions: grönt
Infection: 5360 / 5360 mutanter dödade
Mutation Code Coverage: 100%
Covered Code MSI: 100%
Nytt och förbättrat
Förbättrad relationsstatus på modeller
Modeller har nu bättre stöd för att hantera laddade relationer.
Nya/uppdaterade metoder:
$model->relationLoaded('relation');
$model->unsetRelation('relation');
$model->withoutRelations();
relationLoaded() använder intern relations-cache och kan skilja mellan:
relation saknas
och:
relation är laddad men värdet är null
Det är särskilt viktigt för one-relationer som hasOne, belongsTo och hasOneThrough.
Bättre dynamisk access till laddade relationer
Om en relation redan är laddad returnerar modellens dynamiska property-access nu den
laddade relationsdatan före relationsobjektet.
Exempel:
$user->load('posts');
$posts = $user->posts;
Relationens metod fungerar fortfarande som tidigare:
$relation = $user->posts();
Det innebär:
$user->posts() => relationsobjekt
$user->posts => laddad relationsdata, om relationen är laddad
Säkrare relation-validering
relationExists() har förbättrats så att interna modellmetoder inte längre räknas som relationer.
Exempel på metoder som inte ska accepteras som relationer:
save
delete
load
toArray
Det gör både load() och eager loading säkrare och mer konsekvent.
loadMissing() respekterar laddade null-relationer
loadMissing() laddar nu bara relationer som faktiskt saknas.
En relation som redan är laddad med värdet null betraktas som laddad och laddas inte om.
Query-stöd på relationer
Flera relationstyper har fått eller förbättrat stöd för query().
Relationer med query-stöd:
HasMany
HasOne
BelongsTo
BelongsToMany
HasManyThrough
HasOneThrough
Det gör att relationer kan användas mer konsekvent tillsammans med QueryBuilder.
Exempel:
$user->posts()
->query()
->where('published', '=', 1)
->orderBy('created_at', 'DESC')
->get();
Constrained relation loading
Model::load() hanterar nu QueryBuilder-typade closures mer konsekvent.
Exempel:
$user->load([
'posts' => function (QueryBuilder $query): void {
$query->where('published', '=', 1);
},
]);
För many-relationer sparas resultatet som en Collection.
$posts = $user->getRelation('posts');
För one-relationer sparas resultatet som en modell eller null.
$profile = $user->getRelation('profile');
Relation cardinality
Relationer kan nu ange om de representerar en eller flera modeller.
Nya metoder på relationer:
$relation->isOne();
$relation->isMany();
Exempel:
$user->profile()->isOne(); // true
$user->posts()->isMany(); // true
Det används internt för att avgöra om constrained loading ska använda:
$query->first();
eller:
$query->get();
Bättre eager loading
Eager loading använder nu samma relation-validering som modellens load().
Det betyder att relationer kontrolleras via modellens relationslogik i stället för enkel method_exists()-kontroll.
Exempel:
$users = User::with(['profile', 'posts'])->get();
Med constraints:
$users = User::with([
'posts' => function (QueryBuilder $query): void {
$query->where('published', '=', 1);
},
])->get();
Mindre reflection i Model::load()
Model::load() använder nu publika relation-getters där det går, och faller bara tillbaka till
reflection när det behövs för bakåtkompatibilitet.
Exempel på metadata som nu kan läsas via publikt API:
getForeignKey()
getLocalKeyName()
getRelatedModelClass()
getRelatedTable()
Det gör relationerna lättare att introspektera och minskar beroendet av privata properties.
Förbättrade relationer
HasMany
HasMany har fått:
query()
getLocalKeyName()
isMany()
isOne()
Exempel:
$posts = $user->posts()
->query()
->where('published', '=', 1)
->get();
Om parent saknar local key används en tom-resultat-query:
WHERE (1 = 0)
HasOne
HasOne har fått:
query()
getLocalKeyName()
isMany()
isOne()
Exempel:
$profile = $user->profile()
->query()
->where('active', '=', 1)
->first();
BelongsTo
BelongsTo har fått:
query()
isMany()
isOne()
Exempel:
$author = $post->user()
->query()
->where('active', '=', 1)
->first();
BelongsToMany
BelongsToMany::query() har förbättrats.
Förbättringar:
stabilare pivot-join via raw join
bättre hantering när parent saknar id
stöd för whereRaw('1 = 0') vid tomt resultat
fortsatt stöd för withPivot()
befintlig builder återanvänds när query() redan har byggts
Exempel:
$roles = $user->roles()
->query()
->where('roles.active', '=', 1)
->get();
Pivot-kolumner:
$roles = $user->roles()
->withPivot('created_by', 'created_at')
->query()
->get();
HasManyThrough
HasManyThrough har fått query-stöd.
Exempel:
$votes = $category->votes()
->query()
->where('points', '>', 0)
->get();
HasOneThrough
HasOneThrough har fått query-stöd.
Exempel:
$topVote = $category->topVote()
->query()
->where('points', '>', 0)
->first();
Bättre testtäckning
Den här releasen lägger till och förbättrar tester för:
relation state
relationLoaded()
unsetRelation()
withoutRelations()
relationExists()
Model::load()
loadMissing()
QueryBuilder-constraints
HasMany::query()
HasOne::query()
BelongsTo::query()
BelongsToMany::query()
HasManyThrough::query()
HasOneThrough::query()
relation cardinality
eager loading
pivot select
fallback via reflection
getQuery/query relation resolution
Mutation testing visar:
5360 mutations were generated
5360 mutants were killed by Test Framework
Mutation Code Coverage: 100%
Covered Code MSI: 100%
Bakåtkompatibilitet
Ändringarna är gjorda med bakåtkompatibilitet i åtanke.
Befintlig användning fungerar fortfarande:
$user->posts()->get();
$user->profile()->first();
$user->load('posts');
$user->loadMissing('profile');
Reflection-fallbacks finns kvar där äldre/custom relationer kan sakna nya publika getters.
Det finns dock ett mer korrekt beteende vid QueryBuilder-typade closures:
$user->load([
'profile' => function (QueryBuilder $query): void {
$query->where('active', '=', 1);
},
]);
One-relationer lagras nu som:
Model|null
Many-relationer lagras som:
Collection
Det är mer konsekvent med relationens cardinality.
Rekommenderad uppgradering
Efter uppdatering rekommenderas:
composer update
composer dump-autoload
Kör sedan projektets tester:
composer test
composer stan
Om appen har egna relationer bör du särskilt verifiera:
load()
loadMissing()
with()
withCount()
withSum()
belongsToMany()
withPivot()
Sammanfattning
Den här releasen gör ORM-relationer mer konsekventa, säkrare och bättre integrerade med
QueryBuilder.
Största förbättringarna är:
query-stöd på alla centrala relationstyper
bättre constrained loading
korrekt hantering av one/many-relationer
säkrare relation-validering
mindre reflection
starkare test- och mutationstäckning
och constrained loading. Fokus har varit att göra relationerna mer konsekventa, mer
testbara och enklare att använda tillsammans med QueryBuilder.
Alla ändringar är verifierade med:
PHPUnit: grönt
PHPStan: grönt
GitHub Actions: grönt
Infection: 5360 / 5360 mutanter dödade
Mutation Code Coverage: 100%
Covered Code MSI: 100%
Nytt och förbättrat
Förbättrad relationsstatus på modeller
Modeller har nu bättre stöd för att hantera laddade relationer.
Nya/uppdaterade metoder:
$model->relationLoaded('relation');
$model->unsetRelation('relation');
$model->withoutRelations();
relationLoaded() använder intern relations-cache och kan skilja mellan:
relation saknas
och:
relation är laddad men värdet är null
Det är särskilt viktigt för one-relationer som hasOne, belongsTo och hasOneThrough.
Bättre dynamisk access till laddade relationer
Om en relation redan är laddad returnerar modellens dynamiska property-access nu den
laddade relationsdatan före relationsobjektet.
Exempel:
$user->load('posts');
$posts = $user->posts;
Relationens metod fungerar fortfarande som tidigare:
$relation = $user->posts();
Det innebär:
$user->posts() => relationsobjekt
$user->posts => laddad relationsdata, om relationen är laddad
Säkrare relation-validering
relationExists() har förbättrats så att interna modellmetoder inte längre räknas som relationer.
Exempel på metoder som inte ska accepteras som relationer:
save
delete
load
toArray
Det gör både load() och eager loading säkrare och mer konsekvent.
loadMissing() respekterar laddade null-relationer
loadMissing() laddar nu bara relationer som faktiskt saknas.
En relation som redan är laddad med värdet null betraktas som laddad och laddas inte om.
Query-stöd på relationer
Flera relationstyper har fått eller förbättrat stöd för query().
Relationer med query-stöd:
HasMany
HasOne
BelongsTo
BelongsToMany
HasManyThrough
HasOneThrough
Det gör att relationer kan användas mer konsekvent tillsammans med QueryBuilder.
Exempel:
$user->posts()
->query()
->where('published', '=', 1)
->orderBy('created_at', 'DESC')
->get();
Constrained relation loading
Model::load() hanterar nu QueryBuilder-typade closures mer konsekvent.
Exempel:
$user->load([
'posts' => function (QueryBuilder $query): void {
$query->where('published', '=', 1);
},
]);
För many-relationer sparas resultatet som en Collection.
$posts = $user->getRelation('posts');
För one-relationer sparas resultatet som en modell eller null.
$profile = $user->getRelation('profile');
Relation cardinality
Relationer kan nu ange om de representerar en eller flera modeller.
Nya metoder på relationer:
$relation->isOne();
$relation->isMany();
Exempel:
$user->profile()->isOne(); // true
$user->posts()->isMany(); // true
Det används internt för att avgöra om constrained loading ska använda:
$query->first();
eller:
$query->get();
Bättre eager loading
Eager loading använder nu samma relation-validering som modellens load().
Det betyder att relationer kontrolleras via modellens relationslogik i stället för enkel method_exists()-kontroll.
Exempel:
$users = User::with(['profile', 'posts'])->get();
Med constraints:
$users = User::with([
'posts' => function (QueryBuilder $query): void {
$query->where('published', '=', 1);
},
])->get();
Mindre reflection i Model::load()
Model::load() använder nu publika relation-getters där det går, och faller bara tillbaka till
reflection när det behövs för bakåtkompatibilitet.
Exempel på metadata som nu kan läsas via publikt API:
getForeignKey()
getLocalKeyName()
getRelatedModelClass()
getRelatedTable()
Det gör relationerna lättare att introspektera och minskar beroendet av privata properties.
Förbättrade relationer
HasMany
HasMany har fått:
query()
getLocalKeyName()
isMany()
isOne()
Exempel:
$posts = $user->posts()
->query()
->where('published', '=', 1)
->get();
Om parent saknar local key används en tom-resultat-query:
WHERE (1 = 0)
HasOne
HasOne har fått:
query()
getLocalKeyName()
isMany()
isOne()
Exempel:
$profile = $user->profile()
->query()
->where('active', '=', 1)
->first();
BelongsTo
BelongsTo har fått:
query()
isMany()
isOne()
Exempel:
$author = $post->user()
->query()
->where('active', '=', 1)
->first();
BelongsToMany
BelongsToMany::query() har förbättrats.
Förbättringar:
stabilare pivot-join via raw join
bättre hantering när parent saknar id
stöd för whereRaw('1 = 0') vid tomt resultat
fortsatt stöd för withPivot()
befintlig builder återanvänds när query() redan har byggts
Exempel:
$roles = $user->roles()
->query()
->where('roles.active', '=', 1)
->get();
Pivot-kolumner:
$roles = $user->roles()
->withPivot('created_by', 'created_at')
->query()
->get();
HasManyThrough
HasManyThrough har fått query-stöd.
Exempel:
$votes = $category->votes()
->query()
->where('points', '>', 0)
->get();
HasOneThrough
HasOneThrough har fått query-stöd.
Exempel:
$topVote = $category->topVote()
->query()
->where('points', '>', 0)
->first();
Bättre testtäckning
Den här releasen lägger till och förbättrar tester för:
relation state
relationLoaded()
unsetRelation()
withoutRelations()
relationExists()
Model::load()
loadMissing()
QueryBuilder-constraints
HasMany::query()
HasOne::query()
BelongsTo::query()
BelongsToMany::query()
HasManyThrough::query()
HasOneThrough::query()
relation cardinality
eager loading
pivot select
fallback via reflection
getQuery/query relation resolution
Mutation testing visar:
5360 mutations were generated
5360 mutants were killed by Test Framework
Mutation Code Coverage: 100%
Covered Code MSI: 100%
Bakåtkompatibilitet
Ändringarna är gjorda med bakåtkompatibilitet i åtanke.
Befintlig användning fungerar fortfarande:
$user->posts()->get();
$user->profile()->first();
$user->load('posts');
$user->loadMissing('profile');
Reflection-fallbacks finns kvar där äldre/custom relationer kan sakna nya publika getters.
Det finns dock ett mer korrekt beteende vid QueryBuilder-typade closures:
$user->load([
'profile' => function (QueryBuilder $query): void {
$query->where('active', '=', 1);
},
]);
One-relationer lagras nu som:
Model|null
Many-relationer lagras som:
Collection
Det är mer konsekvent med relationens cardinality.
Rekommenderad uppgradering
Efter uppdatering rekommenderas:
composer update
composer dump-autoload
Kör sedan projektets tester:
composer test
composer stan
Om appen har egna relationer bör du särskilt verifiera:
load()
loadMissing()
with()
withCount()
withSum()
belongsToMany()
withPivot()
Sammanfattning
Den här releasen gör ORM-relationer mer konsekventa, säkrare och bättre integrerade med
QueryBuilder.
Största förbättringarna är:
query-stöd på alla centrala relationstyper
bättre constrained loading
korrekt hantering av one/many-relationer
säkrare relation-validering
mindre reflection
starkare test- och mutationstäckning
v1.2.7 Fix: SecurityHeaders
Framework
Liten fix i middleware SecurityHeaders tagit tagit bort dublicerade setHeaders.
v1.2.6 Säkerhet: stöd för Cross-Origin-Resource-Policy
Framework
Denna release lägger till stöd för att konfigurera HTTP-headern Cross-Origin-Resource-Policy
via Radix SecurityHeaders middleware.
Headern kan användas för att styra hur resurser från applikationen får användas av andra
origins, och ger ett extra skyddslager mot oönskad cross-origin-användning av resurser.
Ny valfri miljövariabel: SECURITY_CORP=same-origin
Tillåtna värden:
same-origin
same-site
cross-origin
off
Rekommenderad standard för vanliga installationer är same-origin.
Det passar när webb, API och statiska resurser ligger på samma origin, exempelvis:
https://example.com
https://example.com/api/v1/...
https://example.com/assets/...
Använd same-site om applikationen är uppdelad på flera subdomäner inom samma site,
exempelvis:
https://app.example.com
https://api.example.com
https://static.example.com
Använd cross-origin endast om resurser från applikationen behöver kunna användas av
externa domäner.
Använd off om headern inte ska sättas av frameworkets SecurityHeaders middleware.
Ändringen är bakåtkompatibel. Befintliga applikationer som saknar SECURITY_CORP
påverkas inte automatiskt. Headern sätts endast när värdet är konfigurerat.
EnvValidator har uppdaterats för att validera SECURITY_CORP när variabeln är satt.
Ogiltiga värden stoppas tidigt med ett tydligt konfigurationsfel.
Testsviten har utökats för att säkerställa att SECURITY_CORP=same-origin accepteras, att
ogiltiga värden nekas och att befintlig bakåtkompatibilitet bibehålls.
För de flesta projekt rekommenderas:
SECURITY_CORP=same-origin
Om Apache eller annan webbserver används för att servera statiska filer direkt kan
motsvarande header även sättas på webbservernivå för att även omfatta exempelvis
JavaScript, CSS, bilder och fonter.
via Radix SecurityHeaders middleware.
Headern kan användas för att styra hur resurser från applikationen får användas av andra
origins, och ger ett extra skyddslager mot oönskad cross-origin-användning av resurser.
Ny valfri miljövariabel: SECURITY_CORP=same-origin
Tillåtna värden:
same-origin
same-site
cross-origin
off
Rekommenderad standard för vanliga installationer är same-origin.
Det passar när webb, API och statiska resurser ligger på samma origin, exempelvis:
https://example.com
https://example.com/api/v1/...
https://example.com/assets/...
Använd same-site om applikationen är uppdelad på flera subdomäner inom samma site,
exempelvis:
https://app.example.com
https://api.example.com
https://static.example.com
Använd cross-origin endast om resurser från applikationen behöver kunna användas av
externa domäner.
Använd off om headern inte ska sättas av frameworkets SecurityHeaders middleware.
Ändringen är bakåtkompatibel. Befintliga applikationer som saknar SECURITY_CORP
påverkas inte automatiskt. Headern sätts endast när värdet är konfigurerat.
EnvValidator har uppdaterats för att validera SECURITY_CORP när variabeln är satt.
Ogiltiga värden stoppas tidigt med ett tydligt konfigurationsfel.
Testsviten har utökats för att säkerställa att SECURITY_CORP=same-origin accepteras, att
ogiltiga värden nekas och att befintlig bakåtkompatibilitet bibehålls.
För de flesta projekt rekommenderas:
SECURITY_CORP=same-origin
Om Apache eller annan webbserver används för att servera statiska filer direkt kan
motsvarande header även sättas på webbservernivå för att även omfatta exempelvis
JavaScript, CSS, bilder och fonter.
v1.2.5 Canonical URL middleware, Redirect responses
Framework
Redirect responses
RedirectResponse har uppdaterats för att stödja valfri redirect-statuskod.
Tidigare skickade RedirectResponse alltid 302. Den kan nu ta emot en andra parameter för statuskod, med
fortsatt bakåtkompatibel default på 302.
Exempel:
new RedirectResponse('/login') ger 302
new RedirectResponse('/new-url', 301) ger 301
Även redirect()-helpern har uppdaterats på samma sätt:
redirect('/login') ger 302
redirect('/new-url', 301) ger 301
Statuskoden valideras så att endast redirect-koder inom intervallet 300–399 accepteras.
Detta gör det möjligt att använda permanenta redirects utan att behöva bygga en vanlig Response manuellt.
Canonical URL middleware
Ett nytt middleware har lagts till:
Radix\Middleware\Middlewares\CanonicalUrl
Middlewaret använder APP_URL som canonical URL och redirectar inkommande requests till rätt scheme och host när de inte matchar.
Exempel:
APP_URL=https://example.com
En request till:
http://www.example.com/about
redirectas permanent till:
https://example.com/about
Redirecten använder 301 via RedirectResponse.
Middlewaret hanterar bland annat:
canonical scheme och host från APP_URL
case-insensitive jämförelse av scheme och host
HTTPS=on, HTTPS=ON, HTTPS=1 och HTTPS som integer 1
HTTP_X_FORWARDED_PROTO=https
host med port, t.ex. example.com:8080
saknad eller ogiltig APP_URL
saknad eller ogiltig current host
tom eller icke-sträng REQUEST_URI
lokal utvecklingsmiljö där redirect ska undvikas
Följande hosts behandlas som lokala och redirectas inte:
localhost
127.0.0.1
*.test
*.local
Exempel på registrering som middleware-alias:
'canonical' => \Radix\Middleware\Middlewares\CanonicalUrl::class
Exempel på användning:
$router->middleware('canonical')
eller som del av en middlewaregrupp, t.ex. web.
Pagination
Pagination-renderingen i paginate_links() har uppdaterats för att vara mer framework-neutral och bättre kompatibel med strikt CSP.
Tidigare renderades pagination med Tailwind-specifika utility-klasser och inline-style, t.ex. style="line-height:1". Det är nu borttaget.
paginate_links() renderar nu semantiska Radix-klasser i stället:
radix-pagination
radix-pagination--mobile
radix-pagination--desktop
radix-pagination__inner
radix-pagination__link
radix-pagination__link--active
radix-pagination__link--disabled
radix-pagination__link--first
radix-pagination__link--previous
radix-pagination__link--next
radix-pagination__link--last
radix-pagination__ellipsis
Det gör att radix-framework inte längre förutsätter Tailwind för paginationens markup. Styling kan i stället läggas i
applikationen, t.ex. i radix-app.
Exempel på enkel CSS-styling i en app:
.radix-pagination { display: flex; justify-content: center; }
.radix-pagination__inner { display: flex; align-items: center; gap: 0.25rem; }
.radix-pagination__link { display: inline-flex; align-items: center; justify-content: center; min-width: 2.25rem; height: 2.25rem; padding: 0 0.75rem; border-radius: 0.375rem; text-decoration: none; }
.radix-pagination__link--active { font-weight: 600; }
.radix-pagination__link--disabled { opacity: 0.5; pointer-events: none; }
.radix-pagination__ellipsis { padding: 0 0.5rem; }
Honeypot helper
honeypot_field() har uppdaterats för att vara kompatibel med strikt CSP.
Tidigare renderades honeypot-fält med inline-style, t.ex. style="display:none;".
Det har ersatts med en CSS-klass:
radix-honeypot
Applikationen ansvarar för att dölja fältet via CSS.
Exempel:
.radix-honeypot { display: none; }
Det gör att helpern kan användas tillsammans med en CSP som inte tillåter inline CSS, t.ex. style-src 'self'.
CSP-kompatibilitet
Flera delar har uppdaterats för att fungera bättre med striktare Content Security Policy.
Fokus har varit att ta bort inline-style från framework-genererad HTML och i stället använda semantiska klasser som
applikationen kan styla själv.
Detta påverkar framför allt:
pagination via paginate_links()
honeypot-fält via honeypot_field()
redirect-flöden där permanenta redirects nu kan skapas direkt med RedirectResponse
Quality
Ändringarna har täckts med tester för både normalfall och edge cases.
Följande har körts och verifierats:
composer stan
composer test
composer infect
Tester har lagts till för bland annat:
default redirect-status 302
explicit permanent redirect 301
redirect-statusens gränsvärden 300 och 399
ogiltiga redirect-statuskoder
canonical redirects
pass-through när request redan matchar canonical URL
lokal utvecklingsmiljö
proxy headers
uppercase scheme/host/header-värden
saknade eller ogiltiga servervärden
pagination-rendering utan Tailwind-specifika klasser och inline styles
honeypot-rendering utan inline styles
RedirectResponse har uppdaterats för att stödja valfri redirect-statuskod.
Tidigare skickade RedirectResponse alltid 302. Den kan nu ta emot en andra parameter för statuskod, med
fortsatt bakåtkompatibel default på 302.
Exempel:
new RedirectResponse('/login') ger 302
new RedirectResponse('/new-url', 301) ger 301
Även redirect()-helpern har uppdaterats på samma sätt:
redirect('/login') ger 302
redirect('/new-url', 301) ger 301
Statuskoden valideras så att endast redirect-koder inom intervallet 300–399 accepteras.
Detta gör det möjligt att använda permanenta redirects utan att behöva bygga en vanlig Response manuellt.
Canonical URL middleware
Ett nytt middleware har lagts till:
Radix\Middleware\Middlewares\CanonicalUrl
Middlewaret använder APP_URL som canonical URL och redirectar inkommande requests till rätt scheme och host när de inte matchar.
Exempel:
APP_URL=https://example.com
En request till:
http://www.example.com/about
redirectas permanent till:
https://example.com/about
Redirecten använder 301 via RedirectResponse.
Middlewaret hanterar bland annat:
canonical scheme och host från APP_URL
case-insensitive jämförelse av scheme och host
HTTPS=on, HTTPS=ON, HTTPS=1 och HTTPS som integer 1
HTTP_X_FORWARDED_PROTO=https
host med port, t.ex. example.com:8080
saknad eller ogiltig APP_URL
saknad eller ogiltig current host
tom eller icke-sträng REQUEST_URI
lokal utvecklingsmiljö där redirect ska undvikas
Följande hosts behandlas som lokala och redirectas inte:
localhost
127.0.0.1
*.test
*.local
Exempel på registrering som middleware-alias:
'canonical' => \Radix\Middleware\Middlewares\CanonicalUrl::class
Exempel på användning:
$router->middleware('canonical')
eller som del av en middlewaregrupp, t.ex. web.
Pagination
Pagination-renderingen i paginate_links() har uppdaterats för att vara mer framework-neutral och bättre kompatibel med strikt CSP.
Tidigare renderades pagination med Tailwind-specifika utility-klasser och inline-style, t.ex. style="line-height:1". Det är nu borttaget.
paginate_links() renderar nu semantiska Radix-klasser i stället:
radix-pagination
radix-pagination--mobile
radix-pagination--desktop
radix-pagination__inner
radix-pagination__link
radix-pagination__link--active
radix-pagination__link--disabled
radix-pagination__link--first
radix-pagination__link--previous
radix-pagination__link--next
radix-pagination__link--last
radix-pagination__ellipsis
Det gör att radix-framework inte längre förutsätter Tailwind för paginationens markup. Styling kan i stället läggas i
applikationen, t.ex. i radix-app.
Exempel på enkel CSS-styling i en app:
.radix-pagination { display: flex; justify-content: center; }
.radix-pagination__inner { display: flex; align-items: center; gap: 0.25rem; }
.radix-pagination__link { display: inline-flex; align-items: center; justify-content: center; min-width: 2.25rem; height: 2.25rem; padding: 0 0.75rem; border-radius: 0.375rem; text-decoration: none; }
.radix-pagination__link--active { font-weight: 600; }
.radix-pagination__link--disabled { opacity: 0.5; pointer-events: none; }
.radix-pagination__ellipsis { padding: 0 0.5rem; }
Honeypot helper
honeypot_field() har uppdaterats för att vara kompatibel med strikt CSP.
Tidigare renderades honeypot-fält med inline-style, t.ex. style="display:none;".
Det har ersatts med en CSS-klass:
radix-honeypot
Applikationen ansvarar för att dölja fältet via CSS.
Exempel:
.radix-honeypot { display: none; }
Det gör att helpern kan användas tillsammans med en CSP som inte tillåter inline CSS, t.ex. style-src 'self'.
CSP-kompatibilitet
Flera delar har uppdaterats för att fungera bättre med striktare Content Security Policy.
Fokus har varit att ta bort inline-style från framework-genererad HTML och i stället använda semantiska klasser som
applikationen kan styla själv.
Detta påverkar framför allt:
pagination via paginate_links()
honeypot-fält via honeypot_field()
redirect-flöden där permanenta redirects nu kan skapas direkt med RedirectResponse
Quality
Ändringarna har täckts med tester för både normalfall och edge cases.
Följande har körts och verifierats:
composer stan
composer test
composer infect
Tester har lagts till för bland annat:
default redirect-status 302
explicit permanent redirect 301
redirect-statusens gränsvärden 300 och 399
ogiltiga redirect-statuskoder
canonical redirects
pass-through när request redan matchar canonical URL
lokal utvecklingsmiljö
proxy headers
uppercase scheme/host/header-värden
saknade eller ogiltiga servervärden
pagination-rendering utan Tailwind-specifika klasser och inline styles
honeypot-rendering utan inline styles
v1.2.4 Förbättrad view-cache och asset-hantering
Framework
Den här releasen förbättrar RadixTemplateViewer och versioned_file() för mer flexibel och robust hantering av frontend-assets.
Nytt och förbättrat
versioned_file() är nu mer generell och stödjer dynamiska paths bättre.
Assets kan placeras i t.ex. /assets/css, /assets/js, /build och /dist.
View-cache-key påverkas nu av relevanta CSS/JS/MJS-assets.
Asset-signaturen skannar endast relevanta asset-kataloger och ignorerar tunga mappar som uploads, images och media.
Asset-signaturen cache:as per viewer-instans för bättre prestanda.
Förbättrad stabilitet mellan Linux och Windows genom konsekvent path-normalisering.
Filter-cache-key inkluderar nu både filternamn och filtertyper.
Cache
View-cache ligger fortsatt som standard i:
text ROOT_PATH/cache/views
VIEWS_CACHE_PATH stöds fortfarande, och APP_ENV=dev/development inaktiverar fortsatt view-cache.
Kvalitet
Verifierat med:
PHPUnit grönt
PHPStan grönt
Infection på RadixTemplateViewer: 5153/5153 mutanter dödade, 100% MSI
Bakåtkompatibilitet
versioned_file() har nu tom sträng som standardfallback. För specifika fallback-värden, ange dem explicit:
php versioned_file($avatarPath, '/images/graphics/avatar.png')
Nytt och förbättrat
versioned_file() är nu mer generell och stödjer dynamiska paths bättre.
Assets kan placeras i t.ex. /assets/css, /assets/js, /build och /dist.
View-cache-key påverkas nu av relevanta CSS/JS/MJS-assets.
Asset-signaturen skannar endast relevanta asset-kataloger och ignorerar tunga mappar som uploads, images och media.
Asset-signaturen cache:as per viewer-instans för bättre prestanda.
Förbättrad stabilitet mellan Linux och Windows genom konsekvent path-normalisering.
Filter-cache-key inkluderar nu både filternamn och filtertyper.
Cache
View-cache ligger fortsatt som standard i:
text ROOT_PATH/cache/views
VIEWS_CACHE_PATH stöds fortfarande, och APP_ENV=dev/development inaktiverar fortsatt view-cache.
Kvalitet
Verifierat med:
PHPUnit grönt
PHPStan grönt
Infection på RadixTemplateViewer: 5153/5153 mutanter dödade, 100% MSI
Bakåtkompatibilitet
versioned_file() har nu tom sträng som standardfallback. För specifika fallback-värden, ange dem explicit:
php versioned_file($avatarPath, '/images/graphics/avatar.png')
v1.2.3 Förstärkt säkerheten vid filuppladdning.
Framework
Säkerhet
Förstärkt säkerheten vid filuppladdning.
file_type-validering kontrollerar nu filens faktiska MIME-typ via finfo, i stället för att lita på klientens type-fält.
Upload::save() kräver nu att uppladdningen har status UPLOAD_ERR_OK innan filen sparas.
Automatiskt genererade filnamn använder nu kryptografiskt säkra slumpvärden.
Filändelser för automatiskt genererade uppladdningar baseras nu på detekterad MIME-typ.
Egna filnamn vid uppladdning begränsas nu till säkra tecken och basename-format för att motverka path traversal.
Fixar
Förhindrar att klientstyrda filändelser används vid genererade uppladdningsnamn.
Förhindrar path traversal via egna filnamn vid uppladdning.
Förbättrad hantering av ogiltigt eller saknat tmp_name.
Förbättrad filstorleksvalidering genom tydligare kontroll av size-fältet.
Förbättrad MIME-validering för uppladdade filer.
Krav
Lagt till explicit Composer-krav på ext-fileinfo för MIME-detektering.
Lagt till explicit Composer-krav på ext-gd för bildhantering.
Kvalitet
Alla tester passerar i CI.
PHPStan passerar.
Infection passerar med full mutationstäckning:
5128 mutanter genererade
5128 mutanter dödade
Mutation Code Coverage: 100%
Covered Code MSI: 100%
Noteringar
Denna release skärper valideringen av filuppladdningar. Applikationer som använder riktiga PHP-uppladdningar via $_FILES bör fungera som tidigare, men med säkrare validering.
Tester eller integrationer som använder mockade filuppladdningar kan behöva säkerställa att tmp_name pekar på en riktig läsbar fil, eftersom file_type nu kontrollerar faktisk MIME-typ från filinnehållet.
Förstärkt säkerheten vid filuppladdning.
file_type-validering kontrollerar nu filens faktiska MIME-typ via finfo, i stället för att lita på klientens type-fält.
Upload::save() kräver nu att uppladdningen har status UPLOAD_ERR_OK innan filen sparas.
Automatiskt genererade filnamn använder nu kryptografiskt säkra slumpvärden.
Filändelser för automatiskt genererade uppladdningar baseras nu på detekterad MIME-typ.
Egna filnamn vid uppladdning begränsas nu till säkra tecken och basename-format för att motverka path traversal.
Fixar
Förhindrar att klientstyrda filändelser används vid genererade uppladdningsnamn.
Förhindrar path traversal via egna filnamn vid uppladdning.
Förbättrad hantering av ogiltigt eller saknat tmp_name.
Förbättrad filstorleksvalidering genom tydligare kontroll av size-fältet.
Förbättrad MIME-validering för uppladdade filer.
Krav
Lagt till explicit Composer-krav på ext-fileinfo för MIME-detektering.
Lagt till explicit Composer-krav på ext-gd för bildhantering.
Kvalitet
Alla tester passerar i CI.
PHPStan passerar.
Infection passerar med full mutationstäckning:
5128 mutanter genererade
5128 mutanter dödade
Mutation Code Coverage: 100%
Covered Code MSI: 100%
Noteringar
Denna release skärper valideringen av filuppladdningar. Applikationer som använder riktiga PHP-uppladdningar via $_FILES bör fungera som tidigare, men med säkrare validering.
Tester eller integrationer som använder mockade filuppladdningar kan behöva säkerställa att tmp_name pekar på en riktig läsbar fil, eftersom file_type nu kontrollerar faktisk MIME-typ från filinnehållet.
v1.2.2 Förbättrad sessionscookie-säkerhet
Framework
Den här releasen lägger till stöd för konfigurerbart sessionscookie-namn via SESSION_COOKIE_NAME.
Nytt
Ny miljövariabel: SESSION_COOKIE_NAME
Stöd för säkra cookie-prefix, t.ex. __Host- och __Secure-
Validering av sessionscookie-namn i EnvValidator
Säkerhetsregler för cookie-prefix:
__Host- kräver SESSION_COOKIE_SECURE=true
__Secure- kräver SESSION_COOKIE_SECURE=true
SameSite=None kräver Secure=true
SESSION_COOKIE_SECURE=auto tillåts endast utanför production
Rekommenderad production-konfiguration
dotenv SESSION_COOKIE_NAME=__Host-din_app_session SESSION_COOKIE_SECURE=true SESSION_COOKIE_HTTPONLY=true SESSION_COOKIE_SAMESITE=Lax
Rekommenderad development-konfiguration
dotenv SESSION_COOKIE_NAME=radix_session SESSION_COOKIE_SECURE=auto SESSION_COOKIE_HTTPONLY=true SESSION_COOKIE_SAMESITE=Lax
Kommentar
Detta gör det möjligt för applikationer som använder Radix att sätta egna, app-specifika sessionscookie-namn och samtidigt använda moderna cookie-prefix för bättre skydd mot
cookie-relaterade attacker.
Nytt
Ny miljövariabel: SESSION_COOKIE_NAME
Stöd för säkra cookie-prefix, t.ex. __Host- och __Secure-
Validering av sessionscookie-namn i EnvValidator
Säkerhetsregler för cookie-prefix:
__Host- kräver SESSION_COOKIE_SECURE=true
__Secure- kräver SESSION_COOKIE_SECURE=true
SameSite=None kräver Secure=true
SESSION_COOKIE_SECURE=auto tillåts endast utanför production
Rekommenderad production-konfiguration
dotenv SESSION_COOKIE_NAME=__Host-din_app_session SESSION_COOKIE_SECURE=true SESSION_COOKIE_HTTPONLY=true SESSION_COOKIE_SAMESITE=Lax
Rekommenderad development-konfiguration
dotenv SESSION_COOKIE_NAME=radix_session SESSION_COOKIE_SECURE=auto SESSION_COOKIE_HTTPONLY=true SESSION_COOKIE_SAMESITE=Lax
Kommentar
Detta gör det möjligt för applikationer som använder Radix att sätta egna, app-specifika sessionscookie-namn och samtidigt använda moderna cookie-prefix för bättre skydd mot
cookie-relaterade attacker.
v1.2.1 Underhåll
Framework
Uppdaterat GitHub Actions workflows för Node.js 24 kompatibilitet.
Uppdaterat actions/checkout från v4 to v5.
Uppdaterat actions/upload-artifact från v4 till v5.
Uppdaterat actions/checkout från v4 to v5.
Uppdaterat actions/upload-artifact från v4 till v5.
v1.2.0 Förbättrad säkerhet
Framework
Den här releasen fokuserar på förbättrad säkerhet, stabilare miljökonfiguration och hårdare testtäckning.
Nytt och förbättrat
Återställt och förbättrat stöd för .env-styrning i GeoLocator.
GeoLocator kan nu läsa:
GEOLOCATOR_BASE_URL
GEOLOCATOR_TIMEOUT
Lagt till timeout-stöd för HTTP-anrop i GeoLocator.
Förbättrad hantering av ogiltiga eller tomma miljövärden.
Konstruktorargument i GeoLocator prioriteras före .env-värden.
Förbättrad felhantering vid ogiltiga API-svar från geolocation-tjänsten.
Förbättrad JSON-hantering i felmeddelanden från GeoLocator.
Säkerhet
Förbättringar kring security headers.
Hårdare skydd och testning runt säkerhetsrelaterade standardvärden.
Förbättrad hantering av sessionssäkerhet via miljövariabler, inklusive cookie-inställningar som HttpOnly, SameSite och Secure.
Tester och kvalitet
GeoLocator-testerna använder nu fake/spy istället för riktiga externa HTTP-anrop.
Mutationstester har stärkts för GeoLocator.
Fler tester för edge cases kring .env, timeout och API-fel.
PHPStan-anpassningar för striktare typkontroll.
Stabilare testsvit utan beroende av externa geolocation-anrop.
För utvecklare
GeoLocator är fortsatt bakåtkompatibel för normal användning:
getLocation() fungerar som tidigare.
getLocation(null) använder fortsatt $_SERVER['REMOTE_ADDR'].
get($key) fungerar som tidigare.
Applikationer kan konfigurera geolocation via .env utan att behöva ändra kod.
Nytt och förbättrat
Återställt och förbättrat stöd för .env-styrning i GeoLocator.
GeoLocator kan nu läsa:
GEOLOCATOR_BASE_URL
GEOLOCATOR_TIMEOUT
Lagt till timeout-stöd för HTTP-anrop i GeoLocator.
Förbättrad hantering av ogiltiga eller tomma miljövärden.
Konstruktorargument i GeoLocator prioriteras före .env-värden.
Förbättrad felhantering vid ogiltiga API-svar från geolocation-tjänsten.
Förbättrad JSON-hantering i felmeddelanden från GeoLocator.
Säkerhet
Förbättringar kring security headers.
Hårdare skydd och testning runt säkerhetsrelaterade standardvärden.
Förbättrad hantering av sessionssäkerhet via miljövariabler, inklusive cookie-inställningar som HttpOnly, SameSite och Secure.
Tester och kvalitet
GeoLocator-testerna använder nu fake/spy istället för riktiga externa HTTP-anrop.
Mutationstester har stärkts för GeoLocator.
Fler tester för edge cases kring .env, timeout och API-fel.
PHPStan-anpassningar för striktare typkontroll.
Stabilare testsvit utan beroende av externa geolocation-anrop.
För utvecklare
GeoLocator är fortsatt bakåtkompatibel för normal användning:
getLocation() fungerar som tidigare.
getLocation(null) använder fortsatt $_SERVER['REMOTE_ADDR'].
get($key) fungerar som tidigare.
Applikationer kan konfigurera geolocation via .env utan att behöva ändra kod.
v1.1.9 Säkerhetsuppdatering
Framework
Den här releasen härdar PHP-session cookies och gör cookie-säkerheten konfigurerbar via .env.
Nytt
Session cookies sätts nu med säkrare defaults.
Stöd för konfigurerbar Secure, HttpOnly och SameSite.
SameSite=None kräver SESSION_COOKIE_SECURE=true.
EnvValidator validerar nya session-cookie-inställningar.
Förbättrad hantering vid session destroy/delete.
Lägg till i befintliga projekt
SESSION_COOKIE_SECURE=auto SESSION_COOKIE_HTTPONLY=true SESSION_COOKIE_SAMESITE=Lax
För production rekommenderas
SESSION_COOKIE_SECURE=true SESSION_COOKIE_HTTPONLY=true SESSION_COOKIE_SAMESITE=Lax
CSP-rekommendation
Komplettera applikationens CSP med:
base-uri: self object-src: none
I PHP-konfigurationen motsvarar det:
'base-uri' => ["'self'"] 'object-src' => ["'none'"]
För API-profiler kan en striktare variant användas:
'base-uri' => ["'none'"] 'object-src' => ["'none'"]
Bakåtkompatibilitet
Session-hanteringen har säkra defaults om miljövariabler saknas, men applikationer som kör EnvValidator måste lägga till de nya SESSION_COOKIE_* variablerna i sin .env.
Teststatus
PHPUnit: grönt
PHPStan: grönt
Infection: 5019/5019 mutanter dödade
Mutation Code Coverage: 100%
Covered Code MSI: 100%
Nytt
Session cookies sätts nu med säkrare defaults.
Stöd för konfigurerbar Secure, HttpOnly och SameSite.
SameSite=None kräver SESSION_COOKIE_SECURE=true.
EnvValidator validerar nya session-cookie-inställningar.
Förbättrad hantering vid session destroy/delete.
Lägg till i befintliga projekt
SESSION_COOKIE_SECURE=auto SESSION_COOKIE_HTTPONLY=true SESSION_COOKIE_SAMESITE=Lax
För production rekommenderas
SESSION_COOKIE_SECURE=true SESSION_COOKIE_HTTPONLY=true SESSION_COOKIE_SAMESITE=Lax
CSP-rekommendation
Komplettera applikationens CSP med:
base-uri: self object-src: none
I PHP-konfigurationen motsvarar det:
'base-uri' => ["'self'"] 'object-src' => ["'none'"]
För API-profiler kan en striktare variant användas:
'base-uri' => ["'none'"] 'object-src' => ["'none'"]
Bakåtkompatibilitet
Session-hanteringen har säkra defaults om miljövariabler saknas, men applikationer som kör EnvValidator måste lägga till de nya SESSION_COOKIE_* variablerna i sin .env.
Teststatus
PHPUnit: grönt
PHPStan: grönt
Infection: 5019/5019 mutanter dödade
Mutation Code Coverage: 100%
Covered Code MSI: 100%
Saknar du en detalj här? Se GitHub‑releaser för komplett historik.