pdo = $pdo; $this->companyId = $company_id; $this->userId = $user_id; } public function acquire(string $operation_type, int $ttl_minutes = 120): array { $operation_type = trim($operation_type); $ttl_minutes = max(1, min(480, $ttl_minutes)); if ($operation_type === '') { throw new Exception('operation_type is required.'); } $now = date('Y-m-d H:i:s'); $expires = date('Y-m-d H:i:s', strtotime("+{$ttl_minutes} minutes")); $this->pdo->beginTransaction(); try { $sth = $this->pdo->prepare( "SELECT * FROM md_lock_operation WHERE company_id = :cid AND operation_type = :op_type FOR UPDATE" ); $sth->execute([':cid' => $this->companyId, ':op_type' => $operation_type]); $lock = $sth->fetch(PDO::FETCH_ASSOC); if ($lock) { $this->pdo->rollBack(); return [ 'success' => 0, 'message' => 'Operation "' . $operation_type . '" is already running. Please wait.', 'expires_at' => $lock['expires_at'], 'locked_at' => $lock['locked_at'], ]; } $this->pdo->prepare( "INSERT INTO md_lock_operation (company_id, operation_type, user_id, locked_at, expires_at) VALUES (:cid, :op_type, :uid, :locked_at, :expires_at)" )->execute([ ':cid' => $this->companyId, ':op_type' => $operation_type, ':uid' => $this->userId, ':locked_at' => $now, ':expires_at' => $expires, ]); $this->pdo->commit(); return ['success' => 1, 'message' => 'Lock acquired.']; } catch (Throwable $e) { if ($this->pdo->inTransaction()) $this->pdo->rollBack(); throw $e; } } public function release(string $operation_type): void { $operation_type = trim($operation_type); if ($operation_type === '') { throw new Exception('operation_type is required.'); } $this->pdo->prepare( "DELETE FROM md_lock_operation WHERE company_id = :cid AND operation_type = :op_type" )->execute([':cid' => $this->companyId, ':op_type' => $operation_type]); } } ?>