لارافيل, Api / 2024-11-23

كيفية إستخدام العلاقات في API Resource وتمريرها كمصفوفة في لارافيل

كيفية إستخدام العلاقات في API Resource وتمريرها كمصفوفة في لارافيل

2024-11-23 وقت القراءه : 4 دقائق

تم الحديث في مقال سابق عن إستخدام 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
                }
            ]
        }
    ]
}



التعليقات
خالد حسن
منذ 3 سنوات

شكرا جزيلا على ال9 دروس العظيمة

بسملة إبراهيم
منذ سنة

جزاك الله خيراً

زائر
منذ سنة

شكراً لك, على هذا المحتوى الجيد , الى الامام يا اخي

عبدالرحمن
منذ سنة

جزاكم الله خيراً أخي الكريم وبارك الله فيكم

‪Kirellos
منذ سنة

لو حابب اعمل pagination للداتا وتكون نفس شكل الرسبونس ازاي.؟

إضافة تعليق
Loading...