Files
zyt/server/app/common/service/pharmacy/LockedPharmacySnapshotMutation.php
T
2026-07-22 14:50:34 +08:00

93 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
namespace app\common\service\pharmacy;
use Closure;
use DomainException;
use think\facade\Db;
final class LockedPharmacySnapshotMutation
{
/**
* @param callable():array<string,mixed> $lockOrder
* @param callable(array<string,mixed>):?array<string,mixed> $lockClaim
* @param callable(array<string,mixed>,?array<string,mixed>):mixed $mutation
*/
public static function run(
callable $lockOrder,
callable $lockClaim,
callable $mutation,
bool $assertMutable = true
): mixed {
$order = Closure::fromCallable($lockOrder)();
if ($order === []) {
throw new DomainException('订单不存在');
}
$claim = Closure::fromCallable($lockClaim)($order);
if ($assertMutable) {
PharmacyRemoteSnapshotPolicy::assertMutable($order, $claim);
}
$result = Closure::fromCallable($mutation)($order, $claim);
if ($result === false) {
throw new DomainException('受保护变更未完成,事务已回滚');
}
return $result;
}
/** @param callable(array<string,mixed>,?array<string,mixed>):mixed $mutation */
public static function execute(
int $orderId,
callable $mutation,
bool $assertMutable = true,
int $revision = 1
): mixed {
return Db::transaction(static fn (): mixed => self::run(
static fn (): array => (array) (Db::name('tcm_prescription_order')
->where('id', $orderId)
->whereNull('delete_time')
->lock(true)
->find() ?: []),
static fn (): ?array => Db::name('pharmacy_submission_claim')
->where('prescription_order_id', $orderId)
->where('source_revision', max($revision, 1))
->lock(true)
->find() ?: null,
$mutation,
$assertMutable
));
}
/** @param callable(array<int,array<string,mixed>>):mixed $mutation */
public static function executeForPrescription(int $prescriptionId, callable $mutation): mixed
{
return Db::transaction(static function () use ($prescriptionId, $mutation): mixed {
$orders = Db::name('tcm_prescription_order')
->where('prescription_id', $prescriptionId)
->whereNull('delete_time')
->order('id', 'asc')
->lock(true)
->select()
->toArray();
foreach ($orders as $order) {
$claim = Db::name('pharmacy_submission_claim')
->where('prescription_order_id', (int) $order['id'])
->where('source_revision', 1)
->lock(true)
->find();
PharmacyRemoteSnapshotPolicy::assertMutable($order, $claim ?: null);
}
$result = Closure::fromCallable($mutation)($orders);
if ($result === false) {
throw new DomainException('受保护变更未完成,事务已回滚');
}
return $result;
});
}
}