doganddev
Accueil Blog Boutique

Laravel : increment() et decrement(), bonnes pratiques

DOG&DEV · 25/01/2025

Technique Web Hosting
Laravel : increment() et decrement(), bonnes pratiques

Laravel : increment() et decrement(), bonnes pratiques

Lorsqu’il s’agit de mettre à jour des colonnes numériques (stock, compteurs, votes, etc.), une approche naïve consiste à lire la valeur, la modifier en PHP puis sauvegarder. Cette méthode expose à des race conditions en environnement concurrent. Laravel propose increment() et decrement() pour effectuer ces mises à jour directement en base, de façon atomique.

Prérequis

  • Projet Laravel avec Eloquent
  • Colonnes numériques (integer, bigInteger, decimal) sur le modèle

1. Le piège : lire–modifier–sauvegarder

// ❌ Risqué : deux requêtes + logique en PHP
$product = Product::find($id);
$product->stock = $product->stock + 1;
$product->save();

Entre le find() et le save(), une autre requête peut modifier stock. Les deux processus lisent la même valeur, incrémentent en parallèle et écrivent : une mise à jour est perdue. Pour un compteur de vues, de likes ou un stock, le résultat est faussé.

2. La bonne approche : increment() et decrement()

// ✅ Atomique : une seule requête UPDATE
$product = Product::find($id);
$product->increment('stock');

// Ou avec un pas personnalisé
$product->increment('stock', 5);
$product->decrement('stock', 2);

L’opération est réalisée côté base (UPDATE products SET stock = stock + 1 WHERE id = ?), sans passer par une lecture préalable en PHP. Les requêtes concurrentes sont correctement sérialisées par le moteur SQL.

3. Sans charger le modèle

Inutile de récupérer l’enregistrement si vous n’avez besoin que de la mise à jour :

Product::where('id', $id)->increment('stock');
Product::where('id', $id)->decrement('stock', 3);

4. Mettre à jour d’autres colonnes en même temps

Le troisième argument permet d’ajouter des paires clé–valeur :

$product->increment('views', 1, ['last_viewed_at' => now()]);

Utile pour un compteur de vues tout en enregistrant la dernière date de consultation.

5. Récupérer la nouvelle valeur

increment() et decrement() renvoient le nombre de lignes affectées, pas la valeur finale. Pour obtenir la valeur à jour :

$product->increment('stock');
$product->refresh();
$newStock = $product->stock;

// Ou sans avoir chargé le modèle au préalable
Product::where('id', $id)->increment('stock');
$newStock = Product::find($id)->stock;

Dépannage

Symptôme Cause possible Correctif
Compteur incohérent Lecture–modification–sauvegarde manuelle Remplacer par increment() / decrement()
Erreur sur colonne non numérique Colonne string ou type inadapté Vérifier la migration et le type de la colonne
Pas de mise à jour Condition where trop restrictive Vérifier que la ligne existe et que le where correspond

Bonnes pratiques

  • Privilégier toujours increment() / decrement() pour les compteurs et stocks, dès qu’il peut y avoir concurrence.
  • Pour des calculs plus complexes (multiples colonnes, règles métier), envisager des transactions et des locks (lockForUpdate()) si nécessaire.
  • Ne pas oublier les index et le niveau d’isolation de la base si les conflits sont très fréquents.

Ressources


Cet article s’inscrit dans notre série de guides technique et développement web. Pour un serveur ou une application sur-mesure, contact.

Commentaires (0)

Laisser un commentaire