X

Transactions de base de données dans Laravel : 5 exemples Open Source


Les transactions de base de données sont essentielles si vous souhaitez effectuer quelques opérations d’insertion/mise à jour/suppression de base de données et garantir l’intégrité des données. Jetons un coup d’œil à 5 ​​exemples différents de projets open source Laravel.


1. themsaid/ergodnc : créer Office avec des balises

Le code du Contrôleur :

class OfficeController extends Controller

{

public function create(): JsonResource

{

$attributes = (new OfficeValidator())->validate(

$office = new Office(),

request()->all()

);

 

$attributes['approval_status'] = Office::APPROVAL_PENDING;

$attributes['user_id'] = auth()->id();

 

$office = DB::transaction(function () use ($office, $attributes) {

$office->fill(

Arr::except($attributes, ['tags'])

)->save();

 

if (isset($attributes['tags'])) {

$office->tags()->attach($attributes['tags']);

}

 

return $office;

});

 

// ...

}

}

Comme vous pouvez le voir, le Office un nouvel enregistrement modèle est créé, puis, avec la relation plusieurs-à-plusieurs ->attach() DB Transaction garantit que si l’attachement de la balise échoue, le nouvel enregistrement Office est également annulé.

Voir le code original sur GitHub.


2. JuanDMeGon/Laravel-from-Scratch : plusieurs à plusieurs avec blocages

Le code du Contrôleur :

class OrderController extends Controller

{

public function store(Request $request)

{

return DB::transaction(function() use($request) {

$user = $request->user();

 

$order = $user->orders()->create([

'status' => 'pending',

]);

 

$cart = $this->cartService->getFromCookie();

 

$cartProductsWithQuantity = $cart

->products

->mapWithKeys(function ($product) {

$quantity = $product->pivot->quantity;

 

if ($product->stock < $quantity) {

throw ValidationException::withMessages([

'cart' => "There is not enough stock for the quantity you required of {$product->title}",

]);

}

 

$product->decrement('stock', $quantity);

$element[$product->id] = ['quantity' => $quantity];

 

return $element;

});

 

$order->products()->attach($cartProductsWithQuantity->toArray());

 

return redirect()->route('orders.payments.create', ['order' => $order->id]);

}, 5);

}

}

Discutons de la transaction qui se passe ici et pourquoi.

  • Nous créons le Order
  • Puis on décrémente le stock de $product
  • Enfin, nous attachons des produits à la $order

Chose intéressante ici : saviez-vous que vous pouvez ajouter un paramètre numérique à la DB::transaction() méthode?

Voir au dessus:

DB::transaction(function() use($request) {

// ... whatever is inside

}, 5);

Qu’est ce que ça 5 faire?

Citation des documents originaux de Laravel :

Le transaction La méthode accepte un deuxième argument facultatif qui définit le nombre de fois qu’une transaction doit être réessayée lorsqu’un blocage se produit. Une fois ces tentatives épuisées, une exception sera levée.

Voir le code original sur GitHub.


3. amitavroy/doctor-app

Le code de la classe Service :

class PatientService

{

public function createPatient($patientData): Patient

{

$settingService = app()->make(SettingService::class);

 

try {

DB::beginTransaction();

$patientNumber = $settingService->getNextPatientNumber();

 

$patient = Patient::create([

'patient_id' => now()->format('Ym') . $patientNumber,

'name' => $patientData['name'],

'phone_number' => $patientData['phone_number'],

'year_of_birth' => now()->subYears($patientData['age'])->format('Y'),

'weight' => $patientData['weight'],

]);

 

$settingService->incrementLastPatientNumber();

DB::commit();

 

return $patient;

} catch (Exception $exception) {

logger()->error($exception->getMessage());

}

}

}

Celui-ci est intéressant : il utilise beginTransaction() et commit() manuellement, et encapsule également la transaction dans un try .. catch déclaration, en plus.

Voir le code original sur GitHub.


4. pixelfed/pixelfed : supprimez tout en toute sécurité

Le code de la classe Job :

class DeleteRemoteProfilePipeline implements ShouldQueue

{

// ...

 

public function handle()

{

$profile = $this->profile;

 

DB::transaction(function() use ($profile) {

$profile->avatar->forceDelete();

 

$id = $profile->id;

 

MediaTag::whereProfileId($id)->delete();

StatusHashtag::whereProfileId($id)->delete();

DirectMessage::whereFromId($id)->delete();

FollowRequest::whereFollowingId($id)

->orWhere('follower_id', $id)

->forceDelete();

Follower::whereProfileId($id)

->orWhere('following_id', $id)

->forceDelete();

Like::whereProfileId($id)->forceDelete();

});

}

}

C’est assez simple. Il y a tellement de choses liées au profil, il y a donc de grandes chances d’échec si certains de ces enregistrements fonctionnent mal pendant le processus de suppression. Donc DB Transaction est une évidence ici.

Il se passe plus de choses dans ce Job, alors consultez le code original sur GitHub.


5. akaunting / akaunting

Le code d’une méthode de classe PHP Action personnalisée :

class Reconciliations extends BulkAction

{

public function reconcile($request)

{

$reconciliations = $this->getSelectedRecords($request);

 

foreach ($reconciliations as $reconciliation) {

\DB::transaction(function () use ($reconciliation) {

$reconciliation->reconciled = 1;

$reconciliation->save();

 

Transaction::where('account_id', $reconciliation->account_id)

->isNotReconciled()

->whereBetween('paid_at', [$reconciliation->started_at, $reconciliation->ended_at])->each(function ($item) {

$item->reconciled = 1;

$item->save();

});

});

}

}

 

}

La réconciliation est un terme financier pour “fusionner des enregistrements transactionnels” ou quelque chose comme ça.

Nous devons donc marquer le rapprochement comme enregistré, mais également marquer les transactions individuelles comme rapprochées.

Certains d’entre vous demanderaient pourquoi il y a un ->each() fonction pour chaque transaction, au lieu d’une simple mise à jour groupée ? Je suppose qu’il y a des observateurs ou d’autres événements qui sont automatiquement déclenchés sur le individuel mise à jour de l’enregistrement, qui ne serait pas exécutée automatiquement autrement.

Voir le code original sur GitHub.


Vous voulez plus d’exemples de code ?

Donc, ce ne sont que 5 exemples. Nous avons collecté des centaines d’exemples de code de projets open source Laravel.

Vous pouvez consulter quelques exemples de transactions DB supplémentaires ou parcourir toute la liste des exemples de code par sujet/balise.