Транзакция Laravel API DB со слишком длинным кодом. Как мне модулировать или оптимизировать этот код? (Я новичок в Laravel)

#laravel #api #laravel-passport #laravel-api

#laravel #API #laravel-паспорт #laravel-api

Вопрос:

У меня очень сложные функции в laravel API (вызываются из мобильного приложения). Пример функции приведен ниже. Если кто-то может помочь улучшить структуру кода. Я хотел бы знать лучшие практики обработки нескольких транзакций в одном API. Потому что, если я перемещаю запись каждой таблицы в отдельную функцию — как мне обрабатывать ошибки каждой из них? Пример: когда количество не задано в модели запроса $

РЕЗЮМЕ: Может кто-нибудь, пожалуйста, разбить его на более мелкие функции?…. Потому что я не знаю, как / где разбить его на более мелкие.

 
    public function placeOrder(Request $request)
    {
        $this->validate($request, [
            'addressId' => 'required'
        ]);
        $userId = Auth::user()->id;
        $itemList = array();
        $deliveryCharge = Store::first()->delivery_charge;
        // $deliveryCharge = Store::findOrFail($request->header('StoreId'))->delivery_charge;
        $total = $deliveryCharge;
        $cod = $request->cod;
        $useBalanceFirst = $request->useBalanceFirst;
        $addressId = $request->addressId;
        $list = $request->list;
        $cost = 0;
        // fetch all items using id in request
        foreach ($list as $orderItemFromRequest) {


            if (!isset($orderItemFromRequest['id']))
                return $this->error("Invalid item selected");

            $itemFromDB = Item::find($orderItemFromRequest['id']);

            if (!isset($orderItemFromRequest['quantity']))
                return $this->error("Please enter quantity for {$itemFromDB->name}");

            $qty = $orderItemFromRequest['quantity'];
            if ($qty > 0.0) {

                if ($itemFromDB == null || $itemFromDB->available == false)
                    return $this->error("Invalid item selected");

                $itemFromDB->quantity = $qty;
                $total  = ($itemFromDB->sell_rate * $itemFromDB->quantity) / $itemFromDB->rate_unit_multiple;
                $cost  = ($qty * $itemFromDB->purchase_rate) / $itemFromDB->rate_unit_multiple;
                array_push($itemList, $itemFromDB);
            }
        }
        if (count($itemList) == 0) {
            return $this->error("At least 1 item is needed to place the order");
        }
        // check user balance 
        $user = User::findOrFail($userId);
        // if balance < total -> throw error    
        if ($cod != true amp;amp;  $user->balance < $total) return $this->error("Insufficient Balance. Please recharge your wallet or use C.O.D.", 403);



        $order = new Order();
        $order->user_id = $user->id;
        $order->total = $total;
        $order->delivery_charge = $deliveryCharge;
        $order->purchase_rate = $cost;

        // because in-case user changes his/her name in future - the order should have the historical name amp; number
        $order->customer_name = $user->name;
        $order->customer_contact = $user->contact_no;
        $order->address_id = $addressId;

        if ($cod == true) {
            if ($useBalanceFirst == true) {
                if ($user->balance < $order->total)
                    $order->amount_due = $order->total - $user->balance;
                else
                    $order->amount_due = 0;
            } else {
                $order->amount_due = $order->total;
            }
        } else
            $order->amount_due = 0;

        $ordertransaction = new OrderTimeLine();
        $ordertransaction->created_by = Auth::user()->id;



        DB::transaction(function () use ($order, $itemList, $user, $ordertransaction) {
            // insert 1 entry into orders
            $order->save();
            $order->refresh();
            $newOrderItemList = array();
            // insert N entries for Items 
            foreach ($itemList as $requestItem) {
                $item   = new OrderItem();
                $item->order_id = $order->id;
                $item->item_id = $requestItem->id;
                $item->item_name = $requestItem->name;
                $item->sell_rate = $requestItem->sell_rate;
                $item->purchase_rate = $requestItem->purchase_rate;
                $item->quantity = $requestItem->quantity;
                $item->quantity_unit = $requestItem->unit;
                $item->rate_unit_multiple = $requestItem->rate_unit_multiple;

                if ($requestItem->remaining_stocks <= 0) {
                    $item->purchase_rate_qty = 0;
                } else if ($requestItem->remaining_stocks < $requestItem->quantity) {
                    $item->purchase_rate_qty = $requestItem->remaining_stocks;
                } else
                    $item->purchase_rate_qty = $requestItem->quantity;

                $item->save();
                $item->refresh();

                $requestItem->remaining_stocks = $requestItem->remaining_stocks - $requestItem->quantity;
                // update remaining QTY and cost price
                unset($requestItem->quantity);
                if ($requestItem->remaining_stocks <= $requestItem->alert_stocks) {
                    // send notification
                    NotificationController::notifyAdminAboutStocks($requestItem);
                }

                $requestItem->save();
                array_push($newOrderItemList, $item);
            }
            $order->items = $newOrderItemList;
            // deduct balance from user table
            $user->balance = $user->balance - $order->total   $order->amount_due;
            $user->save();
            $balanceAffected = 0 - $order->total   $order->amount_due;
            // enter transaction in wallet_transaction table   
            if ($balanceAffected != 0) {
                $transaction =  new WalletTransaction();
                $transaction->user_id = $user->id;
                $transaction->amount = $balanceAffected;
                $transaction->type = WALLET_ORDER_PLACED;
                $transaction->order_id = $order->id;
                $transaction->save();
            }

            $ordertransaction->status = $order->status;
            $ordertransaction->order_id = $order->id;
            $ordertransaction->save();
        });
        NotificationController::notifyAdminAboutOrder($user, $order);
        return $this->success(["balance" => $user->balance, "order" => $order]);
    }

 

Комментарии:

1. Во-первых, ваша функция не должна превышать 20 строк. и я не уверен в ваших требованиях, но вы можете преобразовать повторяющиеся операторы в уникальную функцию. у них также есть место для красноречивых отношений в вашей модели и использовать их

2. @Muhammad Я хочу сделать то же самое — уменьшить размер функций, но в этой функции нет повторяющихся операторов. Кроме того, для красноречивых отношений — могут ли они также использоваться для вставки и обновления? Я знаю об отношениях только в запросе select

3. @Muhammad для вышеупомянутой функции — не могли бы вы разбить ее на более мелкие функции? Потому что я не знаю, как разбить его на более мелкие.

4. Вы можете изменить функциональность, например, если вы сохраняете заказ, вы можете создать частную функцию SaveOrder() . transaction() и т. Д.

Ответ №1:

Вы выполняете слишком много работы в функции контроллера. Прежде всего, я предлагаю в полной мере использовать функциональность проверки Laravel. затем используйте Laravel Collection, чтобы сделать ваш код более читаемым и компактным. Я переработал вашу функцию так, как я обычно обрабатываю.

 public function placeOrder(Request $request)
{
   $data = $request->validate([
      'addressId' => 'required',
      'cod' => 'required|boolean',
      'useBalanceFirst' => 'required|boolean',
      'list' => 'required|array',
      'list.*.quantity' => 'required|numeric',
      'list.*.id' => ['required', 'numeric', Rule::exists('items')->where(function ($query) {
          $query->where('available', true);
      })],
  ]);
  $user = Auth::user();
  $orderItems = collect($data['list'])->map(function($listItem){
      $item = Item::find($listItem['id']);
      $orderItem = new OrderItem([
          'item_id' => $item->id,
          'item_name' => $item->name,
          'sell_rate' => $item->sell_rate,
          'purchase_rate' => $item->purchase_rate,
          'quantity' => $listItem['quantity'],
          'quantity_unit' => $item->quantity_unit,
          'rate_unit_multiple' => $item->rate_unit_multiple,
      ]);
      if ($item->remaining_stocks <= 0) {
          $orderItem->purchase_rate_qty = 0;
      } else if ($item->remaining_stocks < $orderItem->quantity) {
          $orderItem->purchase_rate_qty = $item->remaining_stocks;
      } else
          $orderItem->purchase_rate_qty = $orderItem->quantity;

      return $orderItem;
  });
  $total =  $orderItems->sum(function($item){
      return ($item->sell_rate * $item->quantity) / $item->rate_unit_multiple;
  });
  $cost =  $orderItems->sum(function($item){
      return ($item->quantity * $item->purchase_rate) / $item->rate_unit_multiple;
  });

$deliveryCharge = Store::first()->delivery_charge;
  $total  = $deliveryCharge;

  // if balance < total -> throw error
  if (!$data['cod'] amp;amp; $user->balance < $total)
  {
      return $this->error("Insufficient Balance. Please recharge your wallet or use C.O.D.", 403);
  }

$order = new Order([
      'user_id' => $user->id,
      'total' => $total,
      'delivery_charge' => $deliveryCharge,
      'purchase_rate' => $cost,
      // because in-case user changes his/her name in future - the order should have the historical name amp; number
      'customer_name' => $user->name,
      'customer_contact' => $user->contact_no,
      'address_id' => $data['addressId'],
  ]);
  if ($data['cod']) {
      if ($data['useBalanceFirst']) {
          if ($user->balance < $order->total)
              $order->amount_due = $order->total - $user->balance;
          else
              $order->amount_due = 0;
      } else {
          $order->amount_due = $order->total;
      }
  } else
  {
      $order->amount_due = 0;
  }
  DB::transaction(function () use ($order, $orderItems, $user) {
      // insert 1 entry into orders
      $order->save();
      $order->items->saveMany($orderItems);
      // deduct balance from user table
      $user->balance = $user->balance - $order->total   $order->amount_due;
      $user->save();

    $ordertransaction = OrderTimeLine::create([
          'created_by' => $user->id,
          'status' => $order->status,
          'order_id' => $order->id,
      ]);
  });

  return $this->success(["balance" => $user->balance, "order" => $order]);
}
 

Как вы заметили, я удалил код транзакции уведомления и кошелька пользователя, поскольку они должны обновляться асинхронно, без влияния на ваш пользовательский интерфейс. Я предлагаю вам взглянуть на события Laravel.

Комментарии:

1. Большое вам спасибо. Это то, что я искал