Попытка получить только определенные продукты для каждого заказа в Laravel с использованием массивов

#sql #arrays #laravel #pivot-table

#sql #массивы #ларавель #сводная таблица

Вопрос:

Я пытаюсь отобразить страницу заказа для пользователей на основе двух таблиц: orders и order_product.

В таблице заказов хранятся все полезные данные для заказа, как показано в модели:

Order.php

     protected $fillable = [
        'user_id', 'billing_fname', 'billing_lname', 'billing_email', 'billing_phone','billing_address',
        'billing_county', 'billing_locality', 'billing_zipcode', 'billing_total', 'shipped'
    ];
public function user(){
        return $this->belongsTo('AppUser');
    }

    public function products(){
        return $this->belongsToMany('AppProduct')->withPivot('quantity');
    }
 

В таблице order_product отображается информация о том, сколько продуктов было куплено по этому заказу и какое количество для каждого продукта.

OrderProduct.php

 protected $table = 'order_product';

    protected $fillable = ['order_id', 'product_id', 'quantity'];
 

Теперь проблема в том, что я хочу отобразить всю эту ограниченную информацию в представлении, но я получаю все идентификаторы продуктов из всех заказов, а не только из конкретного:

myorders.blade.php

 <ul class="order-list">
    @foreach($orders as $order)
    <div class="list-group">
  <a href="#" class="list-group-item list-group-item-action flex-column align-items-start active">
    <div class="d-flex w-100 justify-content-between">
      <h5 class="mb-1">Order {{$order->id}}</h5>
      <small>
        @if(!$o->shipped)
            Not shipped.
        @else
            Shipped.
        @endif
    </small>
    </div>
    <p class="mb-1">User: {{$order->billing_fname}} {{$order->billing_lname}} | Date: {{$order->created_at}} | Total: {{$order->billing_total}}

lt;/p>
<small>Adresa: {{$order->billing_county}} {{$order->billing_address}} {{$order->billing_city}}</small>
</a>
@foreach($products as $product)
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{$product->name}}</h5>
<small class="text-muted">Cantitate: {{$product->quantity}}</small>
</div>
<p class="mb-1">Price: {{$product->price}}</p>
</a>
@endforeach
</div>
@endforeach
</ul>

В контроллере я попытался получить доступ ко всем данным в 3 разных операторах foreach следующим образом:

Контроллер заказов

 public function index()  
    {  
            
        $user_id = Auth::user()->id;
        $orders = Order::where('user_id', $user_id)->get();   //from orders table I need all the orders placed by the authenticate user 

        $items = array();
        foreach($orders as $order){
            $items[] = OrderProduct::where('order_id', $order->id)->first();     //from order_product (the pivot table) I need all the data from order_id equals the id in orders
        }

        $products = array();
        foreach($items as $item){
            $prod = Product::where('id', $item->product_id)->first();   //searching for the products in the products table with the id's from order_product
            $products[] = $prod;
        }
        return view('orders.myorders', array(
            'orders' => $orders,
            'products' => $products
        ));

        // dd($products);
        
    } 
 

То, что я получаю, — это все продукты для каждого заказа, так что вид выглядит примерно так:

Идентификатор первого заказа:

-все продукты, найденные в массиве

Идентификатор второго заказа:

-снова все продукты, найденные в массиве

-и так далее, в то время как мне нужны только конкретные продукты для этого заказа

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

Большое спасибо.

Ответ №1:

Я решил эту проблему, используя следующую логику:

 //details of a specific order
    public function index($id) {
        $orders = Order::where('_id', $id)->first();
        
        $details = OrderProduct::where('order_id', $id)->get();    //for an order with the same id we can have multiple products => array
        $product_id = OrderProduct::where('order_id', $id)->get(['product_id']);    //accessing the product from the linked table

        $items = array();
        $products = array();
        foreach($details as $detail){
            $items[] = $detail->product_id;    //an array with all the details from the specific order

            $prod = Product::findOrFail($detail->product_id);   //we add the products with the corresponding id in our products array
            $products[] = $prod;
        }

        return view('orders.myorder', array(
            'orders' => $orders,
            'details' => $details,
            'products' => $products   //returning all the details, orders for accessing the details from Orders, details for accessing all the product's id from that order (OrderProduct and products for getting access to all the products (Products)
        ));

        // dd($items);
    }
 

И файл блейда, в котором отображаются все детали:

 <div class="container">
    <h3 class="text-center">{{ __('Order no.') }} {{$orders['id']}}</h3>
<div class="container-fluid">
  <div class="row">
    <div class="col-sm-4">
    <h5 class="my-5">{{ __('User Details') }}</h5>
         <div class="form-group">
            <p><strong>{{ __('First Name') }}: </strong><em><strong>{{$orders['billing_fname']}} {{$orders['billing_lname']}}</strong></em></p>
         </div>
         <div class="form-group">
            <p><strong>{{ __('Last Name') }}: </strong><em><strong>{{$orders['billing_email']}}</strong></em></p>
         </div>
         <div class="form-group">
            <p><strong>{{ __('Phone') }}: </strong><em><strong> {{$orders['billing_phone']}}</strong></em></p>
         </div>
         <div class="form-group">
            <p><strong>{{ __('Address') }}: </strong><em><strong> {{$orders['billing_address']}}</strong></em></p>
         </div>
         <div class="form-group">
            <p><strong>{{ __('County') }}: </strong><em><strong> {{$orders['billing_county']}}</strong></em></p>
         </div>
         <div class="form-group">
            <p><strong>{{ __('City') }}: </strong><em><strong> {{$orders['billing_city']}}</strong></em></p>
         </div>
         <div class="form-group">
            <p><strong>{{ __('Zipcode') }}: </strong><em><strong> {{$orders['billing_zipcode']}}</strong></em></p>
         </div>
         <div class="form-group">
            
            <p><strong>{{ __('Total') }}: </strong><em><strong> {{$orders['billing_total']}}</strong></em></p>
         </div>
         <div class="form-group">
            <p><strong>Status: </strong><em><strong> {{ $orders['shipped'] === "1" ? __('Shipped') : __('Not shipped') }}</strong></em></p>
         </div>
    </div>
    <div class="col-sm-8">
    <h5 class="text-center mt-5">{{ __('Ordered products') }}</h5>
         <table class="table mt-3">
            <thead>
               <tr>
                  <th>{{ __('Product Name') }}</th>
                  <th>{{ __('Image') }}</th>
                  <th>{{ __('Price') }}</th>
                  <th>{{ __('Quantity') }}</th>
                  <th>{{ __('Date') }}</th>
               </tr>
            </thead>
            <tbody>
               @foreach($products as $product)
               <tr>
                  <td>
                     <a href="{{url(app()->getLocale().'/details', $product->slug)}}" style="text-decoration:none;"><p>{{ $product->name }}</p></a>
                  </td>
                  <td><a href="{{url(app()->getLocale().'/details', $product->slug)}}"><img src="../../img/{{$product['image']}}" width="100" height="100"></a></td>
                  <td>
                     <p>{{$product->price}} RON</p>
                  </td>
                    @foreach($details as $detail)
                        @if($product->id == $detail->product_id) 
                            <td><p>{{ $detail->quantity }} buc</p></td>
                        @endif
                   @endforeach 
                  <td>
                     <p>{{$orders['created_at']}}</p>
                  </td>
               </tr>
               @endforeach
            </tbody>
         </table>
         <div class="float-right m-4">
            <a class="btn btn-info m-4" href="{{ url(app()->getLocale().'/myorders') }}">{{ __('Back') }}</a>
        </div>
    </div>
  </div>
</div>
</div>
 

Это может быть слишком сложно для понимания, моя логика довольно сложная, но я надеюсь, что некоторые из вас могут найти в ней некоторую помощь.

Ответ №2:

Вы можете сделать это с меньшим количеством кодирования, с этими изменениями:

изменения в Order.php

  public function orderProducts(){
    return $this->hasMany('AppOrderProduct');
}
 

изменения в OrderProduct.php

  public function products(){
    return $this->hasOne('AppProduct')->withPivot('quantity');
}
 

изменения в OrderController.php:

  public function index()  
{  
   
    $user_id = Auth::user()->id;
    $orders = Order::where('user_id', $user_id)->get();   
    return view('orders.myorders', array('orders' => $orders));
}
 

и изменения в myorders.blade.php:

 <ul class="order-list">
@foreach($orders as $order)
<div class="list-group">
  <a href="#" class="list-group-item list-group-item-action flex-column align-items-start active">
    <div class="d-flex w-100 justify-content-between">
      <h5 class="mb-1">Order {{$order->id}}</h5>
      <small>
        @if(!$o->shipped)
            Not shipped.
        @else
            Shipped.
        @endif
    </small>
    </div>
    <p class="mb-1">User: {{$order->billing_fname}} {{$order->billing_lname}} | Date:     {{$order->created_at}} | Total: {{$order->billing_total}}

lt;/p>
<small>Adresa: {{$order->billing_county}} {{$order->billing_address}} {{$order->billing_city}}</small>
</a>
@foreach($order->orderProducts()->get() as $orderProduct)
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{$orderProduct->product->name}}</h5>
<small class="text-muted">Cantitate: {{$orderProduct->product->quantity}}</small>
</div>
<p class="mb-1">Price: {{$orderProduct->product->price}}</p>
</a>
@endforeach
</div>
@endforeach
</ul>

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

1. У него есть проблема со вторым foreach, он пытается получить доступ к свойствам не-объекта. Я попытался заменить его на $OrderProduct->products()->name, чтобы получить доступ к функции products(), но произошло следующее: вызов неопределенного метода IlluminateDatabaseEloquentRelationshasMany::withPivot() . Я думаю, что withPivot() работает только с отношениями belongsToMany