Logomark

LARAVEL

Un framework qui rend heureux
Voir cette catégorie
Vers le bas
Laravel 13 : quoi de neuf ?
Vendredi 20 février 2026 18:43

Avec un rythme désormais annuel, Laravel 13 est prévu pour le premier trimestre de cette année. Il est temps de faire un peu le point de ce qui va arriver. Ne vous attendez pas à une révolution, mais plutôt une simple évolution. Pas d'annonce extraordinaire, mais quelques éléments intéressants. Ce qui est visé est plutôt la stabilité et la sécurité. Pour Laravel 12, la correction des bugs sera assurée jusqu'en août 2026 et pour la sécurité jusqu'en février 2027. Donc pas d'urgence pour migrer vos applications !

Pour cet article, je me suis inspiré de celui-ci.

PHP 8.3

La version 12 se contentait de PHP 8.2. Avec la version 13, le minimum sera PHP 8.3. On va y gagner en performances.

Typage amélioré

  • Nouvelle fonction pour valider la syntaxe JSON sans charger les données (plus efficace que json_decode) : json_validate()
  • Typage plus précis pour unserialize() : peut maintenant être annoté avec array ou list.
  • Constantes typées : amélioration du support des constantes de classe typées.

Classes et méthodes

  • #[Override] attribute : permet de marquer explicitement les méthodes qui redéfinissent une méthode parente.
  • Clonage profond (__clone) : meilleur support pour le clonage profond via __clone dans les classes readonly.

Nouvelles fonctions et extensions

  • mb_str_pad() : Equivalent multioctet de str_pad().
  • ldap_exop_sync() et ldap_connect_wallet() : nouvelles fonctions LDAP.
  • posix_sysconf(), posix_pathconf() : nouvelles fonctions POSIX.
  • Nouvelle extension Random : API améliorée pour la génération de nombres aléatoires.

Améliorations de performance

  • Optimisations du JIT (Just-In-Time compiler).
  • Améliorations de l'allocation mémoire pour les chaînes.
  • Réduction de l'empreinte mémoire dans certains cas.

Laravel reverb

Laravel Reverb est le serveur WebSocket officiel de Laravel pour les applications en temps réel. Avant Reverb, les développeurs Laravel devaient utiliser des solutions tierces comme Pusher, Soketi, ou configurer manuellement un serveur WebSocket.

Fonctionnalités clés de Reverb

  • Intégration native avec l'écosystème Laravel
  • Broadcasting (diffusion) en temps réel
  • Channels (canaux) : public, privé, de présence
  • Haute performance (écrit en PHP avec extension PECL)
  • Support SSL/TLS natif

Problème avant Laravel 13

Pour scaler Reverb horizontalement (plusieurs serveurs), vous deviez utiliser Redis :

Serveur 1 ↔ Redis ↔ Serveur 2
   ↑               ↑            ↑
Clients     État partagé  Clients

Redis stockait :

  • Les connexions WebSocket actives
  • Les messages en cours
  • L'état des canaux

Solution avec Laravel 13 : driver database

Configuration simplifiée :

// config/reverb.php
'driver' => env('REVERB_DRIVER', 'database'), // 'redis' ou 'database'

'connections' => [
    'database' => [
        'table' => 'reverb_messages',
    ],
],
# .env
REVERB_DRIVER=database
REVERB_APP_ID=mon_app
REVERB_APP_KEY=app_key
REVERB_APP_SECRET=app_secret

Migration nécessaire :

php artisan reverb:install

Cela crée la table reverb_messages pour stocker l'état.

Architecture avec database driver :

  [Client 1]   ↔   [Serveur Reverb 1]   ↔   [Base de données]
  [Client 2]   ↔   [Serveur Reverb 2]   ↔   [Base de données]
       ↑                             ↑                                     ↑
WebSocket       Même DB partagée           Stocke l'état

Workflow typique :

  • Connexion WebSocket : le client se connecte à un serveur Reverb
  • Stockage DB : le serveur enregistre la connexion dans la DB
  • Broadcast événement :   
 event(new ChatMessage($message));
  • Distribution : tous les serveurs lisent la DB et envoient aux clients concernés

Avantages du driver database

Pour les petites/moyennes applications :

  • Moins de dépendances : pas besoin de Redis
  • Setup simplifié : une seule base de données
  • Coût réduit : évite un service Redis externalisé
  • Maintenance unique : tout dans votre DB principale

Scénarios idéaux :

  • Applications avec < 10,000 connexions concurrentes
  • Chat interne d'entreprise
  • Outils collaboratifs
  • Tableaux de bord en temps réel
  • Notifications live

Le renouvellement intelligent du cache

Le problème traditionnel

Avant Laravel 13, pour prolonger la durée de vie d'une entrée cache :

// Méthode classique (inefficace)
$data = Cache::get('user:123:preferences'); // 1. Lecture
if ($data) {
    Cache::put('user:123:preferences', $data, now()->addHours(2)); // 2. Ré-écriture
}

Problèmes :

  • 2 opérations (get + put)
  • Double transfert réseau si cache distant (Redis, Memcached)
  • Données resérialisées inutilement

La solution : Cache::touch()

// Nouvelle méthode en Laravel 13
Cache::touch('user:123:preferences', now()->addHours(2));

Une seule opération atomique qui :

  • Étend le TTL sans toucher aux données
  • Évite la resérialisation
  • Réduit le trafic réseau de moitié

Cas d'usage pratiques

Sessions utilisateur "toujours actives"

// Middleware pour sessions actives
class KeepSessionAlive
{
    public function handle($request, $next)
    {
        $response = $next($request);
        
        if (Auth::check()) {
            // Extend session cache sans recharger les données
            Cache::touch('session:'.Auth::id(), now()->addHour());
        }
        
        return $response;
    }
}

Rate limiting intelligent

// Garder le compteur "actif" si l'utilisateur est actif
public function trackApiRequest($userId)
{
    $key = "api_requests:{$userId}";
    
    // Incrémenter le compteur
    $count = Cache::increment($key);
    
    // Réinitialiser le TTL à chaque requête
    Cache::touch($key, now()->addMinutes(5));
    
    return $count;
}

Panier d'achat qui n'expire pas

// Quand l'utilisateur modifie son panier
public function updateCart($userId, $item)
{
    $cartKey = "cart:{$userId}";
    
    // Mettre à jour le panier
    $cart = $this->addToCart($userId, $item);
    
    // Réinitialiser le timer d'expiration (30 jours)
    Cache::touch($cartKey, now()->addDays(30));
    
    return $cart;
}

Différence avec Cache::put()

Aspect Cache::put() Cache::touch()
Données Remplace les données Garde les données intactes
Performance Lecture + Écriture Commande unique
Usage Nouvelle valeur Prolongation d'existence
Réseau
2 allers-retours 1 aller-retour
// SCÉNARIO : Utilisateur actif sur une page

// Ancienne approche (inefficace)
public function updateLastSeen($userId)
{
    $profile = Cache::get("user:{$userId}:profile");
    Cache::put("user:{$userId}:profile", $profile, now()->addHour());
    
    // Inutile : on n'a pas modifié le profil !
}

// Nouvelle approche (optimale)
public function updateLastSeen($userId)
{
    // Juste prolonger l'existence
    Cache::touch("user:{$userId}:profile", now()->addHour());
}

Améliorations du routage par sous-domaine

Le problème avant Laravel 13

// web.php ou api.php - Routage complexe
Route::domain('{account}.example.com')->group(function () {
    Route::get('/', function ($account) {
        // Gestion manuelle
        $tenant = Tenant::where('subdomain', $account)->firstOrFail();
        
        // Configuration contextuelle manuelle
        Config::set('database.connections.tenant.database', $tenant->database);
        
        return view('tenant.dashboard', compact('tenant'));
    });
});

Nouvelle approche Laravel 13

Configuration centralisée

// config/domains.php (nouveau fichier)
return [
    'admin' => [
        'domain' => 'admin.example.com',
        'paths' => [
            'routes/admin.php',
            'routes/api.php',
        ],
        'middleware' => ['web', 'auth:admin'],
    ],
    
    'tenant' => [
        'domain' => '{account}.example.com',
        'paths' => [
            'routes/tenant.php',
        ],
        'bindings' => [
            'account' => \App\Models\Tenant::class,
        ],
        'middleware' => ['web', 'tenant'],
    ],
];

Injection automatique de modèle

// routes/tenant.php
Route::get('/dashboard', function (Tenant $account) {
    // $account est automatiquement résolu via le sous-domaine
    return view('dashboard', ['tenant' => $account]);
});

Route::get('/users', [UserController::class, 'index']);
// Le Tenant est automatiquement disponible dans le contrôleur

Middleware contextuel automatique

// Pas besoin de définir manuellement
// Laravel applique automatiquement le middleware configuré
// et prépare l'environnement (DB, config, etc.)

Comment upgrader vers Laravel 13 ?

Les upgrades de Laravel sont souvent bloquées par des problèmes récurrents :

  • Packages tiers incompatibles (50% des échecs)
  • Changements breaking non détectés
  • Tests qui passent, mais bugs en production

    Voyons une stratégie qui aborde ces problèmes de manière systématique.

    Etape 1 : les packages

    composer outdated --direct

    # Affiche uniquement vos packages directs (pas les dépendances des dépendances)
    composer outdated --direct
    
    # Exemple de sortie :
    vendor/package        current  latest
    laravel/framework     v10.28.0 v10.29.0  # OK
    spatie/laravel-permission 5.5.0    6.0.0     # Attention !
    maatwebsite/excel    3.1.48   4.0.0     # Risque de breaking changes

    Pourquoi --direct ?

    • Vous contrôlez directement ces packages
    • Les dépendances indirectes seront mises à jour avec leurs parents

    composer why-not php 8.3

    # Identifie les packages qui bloquent PHP 8.3
    composer why-not php 8.3
    
    # Exemple :
    spatie/laravel-backup ^7.0 requires php ^8.1 -> your php version (8.3.0) does not satisfy that requirement.
    # En réalité, c'est l'inverse : le package n'est PAS compatible 8.3

    Actions concrètes à faire

    # 1. Créer un fichier d'audit
    echo "# Audit d'upgrade Laravel 13 - $(date)" > upgrade-audit.md
    
    # 2. Lister tous les packages avec leur compatibilité
    composer show --direct | grep -E "(laravel|spatie|maatwebsite)" >> upgrade-audit.md
    
    # 3. Vérifier GitHub pour chaque package critique
    PACKAGES=("spatie/laravel-permission" "barryvdh/laravel-debugbar" "laravel/telescope")
    
    for pkg in "${PACKAGES[@]}"; do
        echo "=== $pkg ===" >> upgrade-audit.md
        # Vérifier les releases récentes
        curl -s "https://api.github.com/repos/${pkg/\//\/}/releases/latest" | \
        jq -r '.tag_name, .created_at' >> upgrade-audit.md
    done

    Étape 2 : rector

    Qu'est-ce que Rector ?

    Un outil qui réécrit automatiquement votre code PHP pour :

    • Corriger du code déprécié
    • Appliquer les nouvelles syntaxes
    • Adapter aux breaking changes

    Installation pas à pas

    # 1. Installer Rector (en dev seulement)
    composer require rector/rector --dev
    
    # 2. Installer les règles spécifiques à Laravel
    composer require driftingly/rector-laravel --dev
    
    # 3. Initialiser la configuration
    vendor/bin/rector init
    # Crée un fichier rector.php à la racine

    Configuration optimale pour Laravel 13

    // rector.php
    <?php
    
    declare(strict_types=1);
    
    use Rector\Config\RectorConfig;
    use RectorLaravel\Set\LaravelSetList;
    use Rector\Set\ValueObject\SetList;
    
    return RectorConfig::configure()
        ->withPaths([
            __DIR__ . '/app',
            __DIR__ . '/config',
            __DIR__ . '/database',
            __DIR__ . '/routes',
            __DIR__ . '/tests',
        ])
        ->withSkip([
            // Exclure les fichiers générés
            __DIR__ . '/vendor',
            __DIR__ . '/storage',
            __DIR__ . '/bootstrap/cache',
            
            // Exclure des règles spécifiques si nécessaire
            Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector::class,
        ])
        ->withSets([
            // Règles PHP générales
            SetList::PHP_83,
            
            // Règles spécifiques Laravel
            LaravelSetList::LARAVEL_130,
            
            // Règles de code quality (optionnel)
            SetList::CODE_QUALITY,
            SetList::DEAD_CODE,
        ])
        ->withComposerBased(
            laravel: true,           // Détecte automatiquement la version Laravel
            composerJsonPath: __DIR__ . '/composer.json'
        );

    Exécution en sécurité

    # 1. Voir ce qui va changer (SANS modifier)
    vendor/bin/rector process --dry-run --ansi
    
    # Sortie exemple :
    [file] app/Http/Middleware/TrustHosts.php
        [applied] Rector\Php81\Rector\Property\ReadOnlyPropertyRector
        --- original
        +++ new
        @@ -8,7 +8,7 @@
          */
         class TrustHosts extends Middleware
         {
        -    private $subdomains;
        +    private readonly array $subdomains;
    
    # 2. Appliquer les changements
    vendor/bin/rector process
    
    # 3. Vérifier le diff
    git diff --stat
    # 15 fichiers modifiés, 45 insertions(+), 32 deletions(-)

    Étape 3 : pyramide des tests

    1. Unit Tests d'abord (rapides & isolés)

    # Lancer uniquement les tests unitaires
    php artisan test --testsuite=Unit --parallel
    
    # AVANTAGE : Détecte immédiatement :
    # - Problèmes de typage PHP 8.3
    # - Constants typées incorrectes
    # - Méthodes dépréciées dans le code business

    Exemple de test qui échoue :

    // app/Models/User.php
    class User extends Authenticatable
    {
        public const string STATUS_ACTIVE = 'active'; // PHP 8.3
        
        // ...
    }
    
    // tests/Unit/UserTest.php
    public function test_status_constant()
    {
        // Ce test échouera IMMÉDIATEMENT si problème de type
        $this->assertSame('active', User::STATUS_ACTIVE);
    }

    2. Feature Tests ensuite (Intégration)

    # Tester les endpoints HTTP, auth, DB
    php artisan test --testsuite=Feature --stop-on-failure
    
    # Ce qui est testé :
    # Routes Laravel 13
    # Middleware
    # Validation
    # Sessions
    # Cache
    # Database (avec le nouveau driver Reverb si utilisé)

    Scénario critique à tester :

    // tests/Feature/AuthTest.php
    public function test_login_with_new_password_requirements()
    {
        // Laravel 13 peut avoir de nouvelles règles de password
        $response = $this->post('/register', [
            'password' => 'short', // Peut échouer avec nouvelles règles
        ]);
        
        $response->assertSessionHasErrors('password');
    }

    3. Browser Tests en dernier (lents mais complets)

    # Dernière ligne de défense
    php artisan dusk
    
    # Teste :
    # JavaScript + Laravel
    # WebSockets (Reverb)
    # Assets compilés
    # Authentification frontend

    Checklist finale avant déploiement

    Package Audit

        Tous les packages supportent PHP 8.3
        Tous les packages supportent Laravel 13
        Alternatives identifiées pour les packages bloquants

    Code Changes

        Rector exécuté sans erreurs
        Code review des changements automatiques
        Tests manuels sur les fonctionnalités critiques

    Testing

        Unit tests: 100% pass
        Feature tests: 100% pass
        Browser tests: exécutés sur les flows critiques
        Performance test (cache, Reverb, etc.)

    Infrastructure

        PHP 8.3 installé sur les serveurs
        Extensions PHP nécessaires (pour Reverb, etc.)
        Configuration cache vérifiée (Redis/DB)
        Backup de la base de données

    Conclusion

    Même s'il n'y a rien de vraiment marquant, Laravel 13 marque une étape importante dans l'évolution du framework, renforçant sa philosophie centrale : rendre le développement web élégant, productif et accessible.

    Les trois piliers de Laravel 13

    1. L'autonomie renforcée

    • Reverb avec driver Database : plus besoin de Redis pour du temps réel à moyenne échelle
    • Écosystème intégré : réduction des dépendances externes pour les fonctionnalités courantes
    • Batteries incluses : des WebSockets au cache avancé, tout est dans la boîte

    2. La performance intelligente

    • Cache::touch() : optimisation fine des opérations de cache sans transfert inutile
    • Améliorations du routage : injection automatique et configuration déclarative
    • Optimisations PHP 8.3 : exploitation des dernières capacités du langage

    3. L'évolutivité accessible

    • Scalabilité graduelle : de la base de données unique au cluster Redis
    • Architecture modulaire : routage par domaine natif pour les applications complexes
    • Migration facilitée : des outils comme Rector qui transforment l'upgrade en processus fluide



    Par bestmomo

    Aucun commentaire