كيفية بناء WHERE معقد في Laravel Eloquent: 4 طرق مع أمثلة
\n\nتخيل: أنت تبني متجرًا إلكترونيًا باستخدام Laravel. تحتاج إلى العثور على جميع المنتجات التي تتراوح أسعارها بين 1000 و 5000 ريال، متوفرة في المخزون، ولكن ليست من قسم "التخفيضات"، و تم إنشاؤها بعد 1 يناير 2024. كيف تفعل ذلك باستعلام واحد دون التأثير على الأداء؟
\n\nهذا السؤال هو من أكثر الأسئلة شيوعًا على Stack Overflow (آلاف المشاهدات!). وليس من دون سبب: القدرة على بناء شروط WHERE معقدة في Laravel Eloquent تفرّق بين المبتدئ والمطور المحترف.
\n\nفي هذه المقالة، سأعرض لكم 4 طرق مجربة لإنشاء شروط WHERE متعددة. ستتعلم متى تستخدم المصفوفات، ومتى تستخدم closures، وكيفية تجميع الشروط، وكيفية تجنب هجمات SQL injection. هيا بنا!
\n\n\n\n
1. الطريقة الأساسية: مصفوفة الشروط (لـ AND البسيط)
\n\nأبسط حالة هي عندما تكون جميع الشروط متصلة عبر AND. يتيح لك Laravel تمرير مصفوفة عادية إلى where():
<?php\n\n// نريد العثور على المستخدمين النشطين من السعودية، الذين تم إنشاؤهم في 2024\n$users = User::where([\n ['status', '=', 'active'],\n ['country', '=', 'Saudi Arabia'],\n ['created_at', '>=', '2024-01-01'],\n])->get();\n\n// SQL: SELECT * FROM users WHERE status = 'active' AND country = 'Saudi Arabia' AND created_at >= '2024-01-01'\n\nمتى تستخدم: عندما يكون لديك 2-5 شروط بسيطة مع عامل = أو >. الكود يصبح مقروءًا، لكنه ليس مرنًا.
العيب: إذا كنت بحاجة إلى خلط AND و OR، فإن المصفوفة لا تفي بالغرض.
2. سلسلة دوال where() (للشروط الديناميكية)
\n\nهذه هي الطريقة الأكثر شيوعًا بين المطورين. يمكنك ببساطة استدعاء where() عدة مرات متتالية:
<?php\n\n$products = Product::where('price', '>', 1000)\n ->where('price', '<', 5000)\n ->where('in_stock', true)\n ->where('category_id', '!=', 5)\n ->get();\n\n// SQL: ... WHERE price > 1000 AND price < 5000 AND in_stock = 1 AND category_id <> 5\n\nخدعة: يمكنك دمجها مع شروط أخرى:
\n\n<?php\n\n// شرط "أو" داخل السلسلة\n$orders = Order::where('status', 'paid')\n ->orWhere('status', 'shipped')\n ->where('total', '>', 100) // انتبه: هذا الشرط يُطبق على orWhere السابق!\n ->get();\n\n// SQL: ... WHERE status = 'paid' OR (status = 'shipped' AND total > 100)\n\n⚠️ مهم! في المثال الأخير، حيث total > 100 يُطبق فقط على status = 'shipped'. إذا كنت تريد أن يكون كلا الحالتين مع total > 100، اقرأ النقطة التالية.
3. تجميع الشروط عبر closures (AND + OR معًا)
\n\nهنا نصل إلى أقوى أداة. عندما تحتاج إلى إنشاء مجموعة من الشروط بين قوسين، استخدم closure داخل where():
<?php\n\n// المهمة: العثور على الطلبات بحالة "مدفوع" أو "تم الشحن"،\n// ولكن يجب أن يكون total > 100 في كلتا الحالتين\n$orders = Order::where(function($query) {\n $query->where('status', 'paid')\n ->orWhere('status', 'shipped');\n })\n ->where('total', '>', 100)\n ->get();\n\n// SQL: ... WHERE (status = 'paid' OR status = 'shipped') AND total > 100\n\nالآن تم تجميع الشروط بشكل صحيح! يمكنك تداخل closures داخل بعضها البعض بقدر ما تريد:
\n\n<?php\n\n// فلتر معقد للتحليلات\n$data = Sale::where('date', '>=', '2024-01-01')\n ->where(function($q) {\n $q->where('amount', '>', 10000)\n ->orWhere('is_vip', true);\n })\n ->where(function($q) {\n $q->where('region', 'Riyadh')\n ->orWhere('region', 'Jeddah');\n })\n ->get();\n\n// SQL: ... WHERE date >= '2024-01-01' AND (amount > 10000 OR is_vip = 1) AND (region = 'Riyadh' OR region = 'Jeddah')\n\n4. whereHas: الشروط على العلاقات (المتقدم)
\n\nأحيانًا تحتاج إلى تصفية بناءً على بيانات من جدول مرتبط. هنا يأتي دور whereHas:
<?php\n\n// العثور على المستخدمين الذين لديهم طلبات بقيمة إجمالية تزيد عن 5000\n$users = User::whereHas('orders', function($query) {\n $query->where('total', '>', 5000);\n})->get();\n\n// SQL: SELECT * FROM users WHERE EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id AND total > 5000)\n\nمثال متقدم: ابحث عن المنتجات التي لها تعليقات من مستخدمين نشطين:
\n\n<?php\n\n$products = Product::whereHas('reviews', function($query) {\n $query->whereHas('user', function($q) {\n $q->where('status', 'active');\n });\n})->get();\n\nنصائح إضافية للأداء والأمان
\n\n- \n
- استخدم whereIn بدلاً من orWhere المتكرر: بدلاً من
orWhere('status', 'a')->orWhere('status', 'b')، استخدمwhereIn('status', ['a', 'b']). \n - تجنب N+1: عند استخدام whereHas، فكر في استخدام
with()لتحميل العلاقات مسبقًا. \n - الحماية من SQL injection: استخدم دائمًا parameter binding (كما في الأمثلة أعلاه). لا تقم بتوصيل المدخلات مباشرة في الاستعلام. \n
الخلاصة
\n\nالآن لديك 4 أدوات قوية لبناء شروط WHERE معقدة في Laravel Eloquent:
\n\n- \n
- المصفوفات للشروط البسيطة AND. \n
- سلسلة الدوال للشروط الديناميكية. \n
- closures لتجميع AND و OR معًا. \n
- whereHas للتصفية عبر العلاقات. \n
اختر الأداة المناسبة بناءً على احتياجك. تذكر: الكود الواضح والمقروء أفضل من الكود "الذكي" الذي يصعب فهمه. ابدأ بتطبيق هذه التقنيات في مشروعك اليوم!