تم الحديث في مقال سابق عن إستخدام Api Resource في لارافيل عند عرض البيانات بإستخدام API، وكيف إنها تقوم بترتيب البيانات أثناء العرض من خلال تحويلها إلى JSON.
في أحد المنتديات تم طرح سؤال كيفية التعامل مع مصفوفة كقيمة للـ key، حيث يتم عرض الـ user_cart وجلب جميع المنتجات التابعة لها من خلال إستخدام علاقة hasMany.
للتوضيح أكثر فإنه كان يريد إنشاء API Resource للبيانات التالية
[ { "id": 44, "payament_method": 1, "recivedType": 1, "reciveLocation": 1, "status": 0, "created_at": "2021-06-14T17:23:20.000000Z", "user_cart_items": [ { "id": 3, "price": 2.5, "qty": 2, "product_id": 2, "user_cart_id": 44, "product": { "id": 2, "name_ar": "Blaze Holcomb" } }, { "id": 4, "price": 10, "qty": 2, "product_id": 1, "user_cart_id": 44, "product": { "id": 1, "name_ar": "Marah Cole" } } ] } ]
حيث قام بإنشاء ملف UserOrderResource وقام بإرجاع المصفوفة التالية
//UserOrderResource public function toArray($request) { return [ 'id' => $this->id, 'paymentMethod' => $this->payament_method, 'receivedType' => $this->recivedType, 'receivedLocation' => $this->reciveLocation, 'created_at' => $this->created_at, 'status' => $this->status, 'user_cart_items' => [ 'product_name'=>$this->user_cart_items->product->name_ar, 'price'=>$this->user_cart_items->price, 'qty'=>$this->user_cart_items->qty, ], ]; }
وفي eloquent قام بإستخدام الجملة التالية
public function myOrders($user_id){ return UserOrderResource::collection( UserCart::select('id','payament_method','recivedType','reciveLocation','status','created_at') ->with((['user_cart_items' => function ($q) { $q->select('id', 'price', 'qty', 'product_id','user_cart_id') ->with('product:id,name_ar'); }])) ->where('user_id',$user_id) ->get()); }
إلا إنه كان يظهر لدية الخطأ التالي
Exception: Property [product] does not exist on this collection instance.
من خلال تحليل السؤال والأكوود، تبين أن الشخص يريد أن يتم إرجاع سلة المشريات وجميع المنتجات الي تتبع لهذه السلة، والمشكله في apiResource أن قيمة user_cart_items تحتوي على أكثر من عنصر ( مصفوفة ).
إنشاء ملف مثلا بإسم UserCartItemResource ويقوم بتعريف خصائص المنتج به
// UserCartItemResource public function toArray($request) { return [ 'product_name'=>$this->product->name_ar, 'price'=>$this->price, 'qty'=>$this->qty, ]; }
ومن ثم يقوم بتمرير هذا الكلاس كقيمة للـ user_cart_items مع إستخدام دالة whenLoaded حيث تستخدم لجلب العلاقة، وتأخذ فقط إسم العلاقة
// UserOrderResource public function toArray($request) { return [ 'id' => $this->id, 'paymentMethod' => $this->payament_method, 'receivedType' => $this->recivedType, 'receivedLocation' => $this->reciveLocation, 'created_at' => $this->created_at, 'status' => $this->status, 'user_cart_items' => UserCartItemResource::collection($this->whenLoaded('user_cart_items')), ]; }
إستخدام الدالة map حيث يجب عمل map على user_cart_items ومن ثم بناء مصفوفة بالمنتجات
public function toArray($request) { return [ 'id' => $this->id, 'paymentMethod' => $this->payament_method, 'receivedType' => $this->recivedType, 'receivedLocation' => $this->reciveLocation, 'created_at' => $this->created_at, 'status' => $this->status, 'user_cart_items' => $this->user_cart_items->map(function ($item) { return [ 'product_name'=>$item->product->name, 'price'=>$item->price, 'qty'=>$item->qty, ]; })->all() ]; }
وفي كلا الحالتين سوف نحصل على النتيجة التالية
{ "data": [ { "id": 44, "paymentMethod": 1, "receivedType": 1, "receivedLocation": 1, "created_at": "2021-06-14T17:23:20.000000Z", "status": 0, "user_cart_items": [ { "product_name": "Blaze Holcomb", "price": 2.5, "qty": 2 }, { "product_name": "Marah Cole", "price": 10, "qty": 2 } ] } ] }
جزاك الله خيراً
شكراً لك, على هذا المحتوى الجيد , الى الامام يا اخي
جزاكم الله خيراً أخي الكريم وبارك الله فيكم
لو حابب اعمل pagination للداتا وتكون نفس شكل الرسبونس ازاي.؟
خالد حسن
شكرا جزيلا على ال9 دروس العظيمة