Ce qui se passe
Laravel 13.39.0 ajoute une commande Artisan session:garbage-collect, un
moyen de désactiver la clé primaire d'un modèle, la durée des jobs sur
l'événement JobAttempted, et plusieurs correctifs d'infrastructure.
Sortir la purge de sessions du chemin des requêtes
Par défaut, Laravel nettoie les sessions expirées sur une requête tirée au
hasard, selon le réglage lottery de config/session.php. C'est donc un
visiteur qui paie le nettoyage.
use Illuminate\Support\Facades\Schedule;
Schedule::command('session:garbage-collect')->hourly();La commande se fie à votre valeur session.lifetime pour décider ce qui est
expiré. Pour que les requêtes arrêtent de s'en charger, passez la loterie à
[0, 100]. Contribution d'Andrew Brown, PR
#62104 et
#62150.
Le correctif à prendre en premier
config:cache, route:cache et event:cache écrivent maintenant dans un
fichier temporaire, puis le renomment. Avant, une requête qui démarrait pendant
l'exécution de la commande pouvait lire un fichier de cache vide. Et avec
opcache.validate_timestamps=0, OPcache conservait ce fichier vide : toutes les
requêtes échouaient jusqu'au redémarrage de PHP-FPM. PR
#62117.
Si votre production tourne sous OPcache avec les timestamps désactivés, c'est la raison de prendre cette version.
Les autres ajouts utiles
- Clé primaire désactivable. L'attribut
#[Table]acceptekey: false. Jusqu'ici, une clénullretombait sur la propriété$primaryKey, qui vautidpar défaut, et il fallait donc conserver la propriété :
#[Table(name: 'activity_log', key: false)]
class Activity extends Model {} Un correctif de suivi marque aussi ces modèles comme non incrémentaux, si bien
que create() ne lève plus d'erreur après l'insertion. PR
#62113 (Caleb White) et
#62205.
Durée des jobs échoués. L'événement
JobAttemptedporte une propriétédurationen millisecondes. Avant, seulJobProcesseden avait une : un job échoué ou relâché pour nouvelle tentative n'avait aucun temps mesuré. La filesyncfournit aussi cette durée, donc undispatchSync()est mesuré sur les deux événements. PR #62118 (Jack Bayliss) et #62155.Tailles sur
Rule::array(). Les méthodesmin(),max(),between()etexactly()rejoignent celles deRule::string():
// avant
'photos' => [Rule::required(), Rule::array(), 'min:1'],
// après
'photos' => [Rule::required(), Rule::array()->min(1)->max(10)], Elles fonctionnent aussi avec des clés autorisées : Rule::array(['a', 'b'])->min(1)
produit array:a,b|min:1. PR
#62179.
Côté tests. Un attribut
#[WithoutMigrationEvents]empêche les requêtes de migration d'atteindreDB::listen()etexpectsDatabaseQueryCount()quandLazilyRefreshDatabasemigre pendant le test (#62201) ; le faux deMailgère enfinMail::html()etMail::plain(), qui envoyaient de vrais courriels en test (#62162) ;RefreshDatabaseannule tous les niveaux de transaction après chaque test, donc un test qui en laisse une ouverte ne fait plus échouer les suivants (#62194) ; etassertSeeText('0'), qui passait sans rien vérifier, est corrigé (#62126).Relations.
BelongsToManyreçoitforceCreate()etforceCreateQuietly(): l'appel partait auparavant au query builder, donc le modèle était créé mais jamais attaché.restoreOrCreate()etcreateOrRestore()passent désormais par la relation, y comprisHasManyThroughetHasOneThrough(#62136, #62146, #62204).
Source : Laravel News, 28 octobre 2026. Source en anglais.