#php #laravel #eloquent
#php #ларавель #красноречивый
Вопрос:
В моем приложении пользователи могут создавать и программно удалять шлюзы, такие как Paypal. Пользователи веб-сайта могут подключиться к шлюзу и совершать платежи.
Я написал логику в транзакции, также блокирующей соответствующую запись (в website
поле), которая была удалена пользователем из-за состояния гонки. Прочитайте код для лучшего понимания.
Уже существует (мягко удалено)
Эти шлюзы должны быть проверены администратором, если пользователь отправляет разные website
description
поля и по сравнению с соответствующей записью, которая уже была проверена, установлена is_verified
и rejection_reason
null
is_verified
ценности:
true
проверенныйfalse
отклоненныйnull
рассматриваемый
Правило: Создайте, если он не существует, Восстановите, если он был удален.
Почему-то я думаю, что мой код не в порядке, и я слишком много думаю или что-то еще (как перфекционист синдром самозванца).
Миграция
Schema::create('gateways', function (Blueprint $table) { $table-gt;id(); $table-gt;foreignId('user_id') -gt;constrained() -gt;onUpdate('cascade') -gt;onDelete('cascade'); $table-gt;string('title', 50); $table-gt;text('description'); $table-gt;string('website')-gt;unique(); $table-gt;enum('wage', Gateway::getWageKeys()); $table-gt;text('rejection_reason')-gt;nullable(); $table-gt;boolean('is_verified')-gt;nullable()-gt;default(null); $table-gt;boolean('is_blocked')-gt;default(false); $table-gt;boolean('first_payment')-gt;default(false); $table-gt;dateTime('free_until')-gt;nullable(); $table-gt;softDeletes(); $table-gt;timestamps(); });
Контроллер
/** * Create a new gateway. * * @param AppHttpRequestsStoreGatewayRequest $request * @return AppHttpResourcesGatewayResource */ public function create(StoreGatewayRequest $request) { try { $gateway = DB::transaction(function () use ($request) { $gateway = $request-gt;user()-gt;gateways()-gt;onlyTrashed() -gt;where('website', $request-gt;website)-gt;lockForUpdate()-gt;first(); if (! $gateway) { return $request-gt;user()-gt;gateways()-gt;create($request-gt;validated()); } else { if ($gateway-gt;is_blocked) abort(452); $gateway-gt;fill($request-gt;validated()); if ($gateway-gt;isDirty('website') || $gateway-gt;isDirty('description')) { $gateway-gt;rejection_reason = null; $gateway-gt;is_verified = null; } $gateway-gt;deleted_at = null; $gateway-gt;save(); return $gateway; } }); } catch (QueryException $e) { if ($e-gt;errorInfo[1] === 1062) { abort(409); } else { throw $e; } } return new GatewayResource($gateway); }
Комментарии:
1. Я думаю, что вы могли бы перенести заблокированную и проверенную часть логики в красноречивые события. Все эти числа ошибок на самом деле ничего для меня не значат. Константы могли бы сделать код более читаемым. Константы состояния Http уже существуют где-то в HttpFoundation.
2. Также я не уверен в
$gateway = DB::transaction
этом . Я думаю, что простоDB::transaction
отлично работает. Лично я предпочитаю другой способ совершения транзакций (beginTransaction
,commit
,rollBack
)3. Что касается использования блокировки базы данных: действительно ли это так важно в данном случае? Может ли пользователь случайно выполнить одно и то же обновление дважды? Если он это сделает, будут ли какие-либо последствия, такие как взимание денег дважды или если база данных выдаст уникальное нарушение ограничений?
4.
$gateway-gt;deleted_at = null; $gateway-gt;save();
может быть заменен на$gateway-gt;restore()
5. @IGP Если вы прочитаете код еще раз, обновленный
$gateway
объект внутри транзакции будет возвращен, потомуreturn new GatewayResource($gateway);
что он нужен в качестве ответа на запрос.