سحر Laravel الذي تعرفه، يتم تطبيقه الآن على الصلات.
عمليات الانضمام مفيدة جدًا بعدة طرق. إذا كنت هنا، فمن المرجح أنك تعرف عنها وتستخدمها. Eloquent قوي جدًا، لكنه يفتقر إلى القليل من "طريقة Laravel" عند استخدام الصلات. تعمل هذه الحزمة على جعل عمليات الانضمام الخاصة بك بطريقة Laravel أكثر، مع سهولة القراءة مع تعليمات برمجية أقل مع إخفاء تفاصيل التنفيذ من الأماكن التي لا تحتاج إلى كشفها.
بعض الأشياء التي نعتبرها مفقودة عند استخدام الصلات والتي تعتبر ميزات Eloquent قوية جدًا:
يمكنك قراءة شرح أكثر تفصيلاً حول المشكلات التي تحلها هذه الحزمة في منشور المدونة هذا.
يمكنك تثبيت الحزمة عبر الملحن:
composer require kirschbaum-development/eloquent-power-joins
بالنسبة لإصدارات Laravel < 10، استخدم الإصدار 3.*. بالنسبة لإصدارات Laravel < 8، استخدم الإصدار 2.*:
composer require kirschbaum-development/eloquent-power-joins:3. *
توفر هذه الحزمة بعض الميزات.
لنفترض أن لديك نموذج User
له علاقة hasMany
بنموذج Post
. إذا كنت تريد الانضمام إلى الجداول، فعادةً ما تكتب شيئًا مثل:
User:: select ( ' users.* ' )-> join ( ' posts ' , ' posts.user_id ' , ' = ' , ' users.id ' );
توفر لك هذه الحزمة طريقة joinRelationship()
جديدة، والتي تقوم بنفس الشيء تمامًا.
User:: joinRelationship ( ' posts ' );
كلا الخيارين ينتجان نفس النتائج. فيما يتعلق بالكود، لم تقم بحفظ الكثير، ولكنك تستخدم الآن العلاقة بين نموذجي User
Post
للانضمام إلى الجداول. هذا يعني أنك الآن تخفي كيفية عمل هذه العلاقة خلف الكواليس (تفاصيل التنفيذ). لا تحتاج أيضًا إلى تغيير الرمز إذا تغير نوع العلاقة. لديك الآن كود أكثر قابلية للقراءة وأقل إرهاقًا.
لكن الأمر يصبح أفضل عندما تحتاج إلى الانضمام إلى علاقات متداخلة . لنفترض أن لديك أيضًا علاقة hasMany
بين نموذجي Post
و Comment
وتحتاج إلى الانضمام إلى هذه الجداول، يمكنك ببساطة كتابة:
User:: joinRelationship ( ' posts.comments ' );
أفضل بكثير، ألا توافقون على ذلك؟! يمكنك أيضًا الانضمام إلى العلاقات left
أو right
حسب الحاجة.
User:: leftJoinRelationship ( ' posts.comments ' );
User:: rightJoinRelationship ( ' posts.comments ' );
لنتخيل أن لديك نموذج Image
عبارة عن علاقة متعددة الأشكال ( Post -> morphMany -> Image
). إلى جانب الانضمام العادي، ستحتاج أيضًا إلى تطبيق شرط where imageable_type = Post::class
، وإلا فقد تحصل على نتائج فوضوية.
اتضح أنه إذا انضممت إلى علاقة متعددة الأشكال، فإن Eloquent Power Joins يطبق هذا الشرط تلقائيًا عليك. تحتاج ببساطة إلى الاتصال بنفس الطريقة.
Post:: joinRelationship ( ' images ' );
يمكنك أيضًا الانضمام إلى علاقات MorphTo.
Image:: joinRelationship ( ' imageable ' , morphable: Post::class);
ملاحظة: الاستعلام عن التحويل إلى العلاقات يدعم فقط نوعًا واحدًا قابلاً للتحويل في كل مرة.
تطبيق الشروط وعمليات الاسترجاعات على الصلات
لنفترض الآن أنك تريد تطبيق شرط على عملية الانضمام التي تجريها. تحتاج ببساطة إلى تمرير رد اتصال كمعلمة ثانية لأسلوب joinRelationship
.
User:: joinRelationship ( ' posts ' , fn ( $ join ) => $ join -> where ( ' posts.approved ' , true ))-> toSql ();
يمكنك أيضًا تحديد نوع الانضمام الذي تريد إجراؤه في رد الاتصال:
User:: joinRelationship ( ' posts ' , fn ( $ join ) => $ join -> left ());
بالنسبة للمكالمات المتداخلة ، تحتاج ببساطة إلى تمرير مصفوفة تشير إلى أسماء العلاقات.
User:: joinRelationship ( ' posts.comments ' , [
' posts ' => fn ( $ join ) => $ join -> where ( ' posts.published ' , true ),
' comments ' => fn ( $ join ) => $ join -> where ( ' comments.approved ' , true ),
]);
بالنسبة للعديد من الاستدعاءات، تحتاج إلى تمرير مصفوفة بالعلاقة، ثم مصفوفة بأسماء الجداول.
User:: joinRelationship ( ' groups ' , [
' groups ' => [
' groups ' => function ( $ join ) {
// ...
},
// group_members is the intermediary table here
' group_members ' => fn ( $ join ) => $ join -> where ( ' group_members.active ' , true ),
]
]);
نحن نعتبر هذه واحدة من أكثر الميزات المفيدة لهذه الحزمة. لنفترض أن لديك نطاقًا published
في نموذج Post
الخاص بك:
public function scopePublished ( $ query )
{
$ query -> where ( ' published ' , true );
}
عند الانضمام إلى العلاقات، يمكنك استخدام النطاقات المحددة في النموذج الذي يتم ضمه. كم هو رائع هذا؟
User:: joinRelationship ( ' posts ' , function ( $ join ) {
// the $join instance here can access any of the scopes defined in Post
$ join -> published ();
});
عند استخدام نطاقات نموذجية داخل عبارة ربط، لا يمكنك كتابة تلميح لمعلمة $query
في نطاقك. وتذكر أيضًا أنك داخل صلة، لذا يقتصر استخدامك على الشروط التي تدعمها الصلات فقط.
في بعض الأحيان، ستحتاج إلى استخدام الأسماء المستعارة للجدول في الصلات الخاصة بك لأنك تنضم إلى نفس الجدول أكثر من مرة. أحد الخيارات لتحقيق ذلك هو استخدام طريقة joinRelationshipUsingAlias
.
Post:: joinRelationshipUsingAlias ( ' category.parent ' )-> get ();
في حال كنت بحاجة إلى تحديد اسم الاسم المستعار الذي سيتم استخدامه، يمكنك القيام بذلك بطريقتين مختلفتين:
Post:: joinRelationshipUsingAlias ( ' category ' , ' category_alias ' )-> get ();
as
داخل رد اتصال الانضمام. Post:: joinRelationship ( ' category.parent ' , [
' category ' => fn ( $ join ) => $ join -> as ( ' category_alias ' ),
' parent ' => fn ( $ join ) => $ join -> as ( ' category_parent ' ),
])-> get ()
بالنسبة إلى ينتمي إلى العديد أو لديه العديد من خلال الاستدعاءات، فأنت بحاجة إلى تمرير مصفوفة مع العلاقة، ثم مصفوفة مع أسماء الجداول.
Group:: joinRelationship ( ' posts.user ' , [
' posts ' => [
' posts ' => fn ( $ join ) => $ join -> as ( ' posts_alias ' ),
' post_groups ' => fn ( $ join ) => $ join -> as ( ' post_groups_alias ' ),
],
])-> toSql ();
عند إجراء عمليات الصلات، قد يكون استخدام select * from ...
أمرًا خطيرًا حيث قد تتعارض الحقول التي تحمل الاسم نفسه بين الجدول الأصلي والجداول المرتبطة. بالتفكير في ذلك، إذا قمت باستدعاء طريقة joinRelationship
دون تحديد أي أعمدة محددة مسبقًا، فسوف يقوم Eloquent Power Joins بتضمين ذلك تلقائيًا لك. على سبيل المثال، ألقِ نظرة على الأمثلة التالية:
User:: joinRelationship ( ' posts ' )-> toSql ();
// select users.* from users inner join posts on posts.user_id = users.id
وإذا قمت بتحديد عبارة التحديد:
User:: select ( ' users.id ' )-> joinRelationship ( ' posts ' )-> toSql ();
// select users.id from users inner join posts on posts.user_id = users.id
عند الانضمام إلى أي نماذج تستخدم سمة SoftDeletes
، سيتم أيضًا تطبيق الشرط التالي تلقائيًا على جميع الصلات الخاصة بك:
and " users " . " deleted_at " is null
في حالة رغبتك في تضمين النماذج المحذوفة، يمكنك استدعاء الأسلوب ->withTrashed()
في رد اتصال الانضمام.
UserProfile:: joinRelationship ( ' users ' , fn ( $ join ) => $ join -> withTrashed ());
يمكنك أيضًا الاتصال بنموذج onlyTrashed
أيضًا:
UserProfile:: joinRelationship ( ' users ' , ( $ join ) => $ join -> onlyTrashed ());
إذا كانت لديك شروط إضافية في تعريفات علاقتك، فسيتم تطبيقها عليك تلقائيًا.
class User extends Model
{
public function publishedPosts ()
{
return $ this -> hasMany (Post::class)-> published ();
}
}
إذا اتصلت بـ User::joinRelationship('publishedPosts')->get()
، فسيتم أيضًا تطبيق النطاق المنشور الإضافي على جملة الانضمام. سينتج SQL أكثر أو أقل مثل هذا:
select users. * from users inner join posts on posts . user_id = posts . id and posts . published = 1
إذا كان النموذج الخاص بك يحتوي على نطاقات عامة مطبقة عليه، فيمكنك تمكين النطاقات العامة عن طريق استدعاء الأسلوب withGlobalScopes
في عبارة الربط الخاصة بك، مثل هذا:
UserProfile:: joinRelationship ( ' users ' , fn ( $ join ) => $ join -> withGlobalScopes ());
هناك، على الرغم من ذلك، مسكتك هنا. لا يمكن لنطاقك العام أن يلمح إلى فئة EloquentBuilder
في المعلمة الأولى للطريقة apply
، وإلا فسوف تحصل على أخطاء.
يعد الاستعلام عن وجود العلاقة ميزة قوية جدًا ومريحة في Eloquent. ومع ذلك، فهو يستخدم بناء الجملة where exists
والذي ليس دائمًا هو الأفضل وقد لا يكون الخيار الأكثر أداءً، اعتمادًا على عدد السجلات لديك أو بنية الجداول الخاصة بك.
تنفذ هذه الحزم نفس الوظيفة، ولكن بدلاً من استخدام بناء الجملة where exists
، فإنها تستخدم الصلات . أدناه، يمكنك رؤية الطرق التي تنفذها هذه الحزمة وأيضًا ما يعادلها من Laravel.
يرجى ملاحظة أنه على الرغم من تشابه الطرق، إلا أنك لن تحصل دائمًا على نفس النتائج عند استخدام الصلات، اعتمادًا على سياق الاستعلام الخاص بك. يجب أن تكون على دراية بالاختلافات بين الاستعلام عن البيانات where exists
مقابل joins
.
طرق لارافيل الأصلية
User:: has ( ' posts ' );
User:: has ( ' posts.comments ' );
User:: has ( ' posts ' , ' > ' , 3 );
User:: whereHas ( ' posts ' , fn ( $ query ) => $ query -> where ( ' posts.published ' , true ));
User::whereHas( ' posts.comments ' , [ ' posts ' => fn ( $ query ) => $ query -> where ( ' posts.published ' , true ));
User:: doesntHave ( ' posts ' );
حزمة مكافئة، ولكن باستخدام الصلات
User:: powerJoinHas ( ' posts ' );
User:: powerJoinHas ( ' posts.comments ' );
User:: powerJoinHas ( ' posts.comments ' , ' > ' , 3 );
User:: powerJoinWhereHas ( ' posts ' , function ( $ join ) {
$ join -> where ( ' posts.published ' , true );
});
User:: powerJoinDoesntHave ( ' posts ' );
عند استخدام الأسلوب powerJoinWhereHas
مع العلاقات التي تتضمن أكثر من جدول واحد (واحد إلى كثير، كثير إلى كثير، وما إلى ذلك)، استخدم بناء جملة المصفوفة لتمرير رد الاتصال:
User:: powerJoinWhereHas ( ' commentsThroughPosts ' , [
' comments ' => fn ( $ query ) => $ query -> where ( ' body ' , ' a ' )
])-> get ());
يمكنك أيضًا فرز نتائج الاستعلام باستخدام عمود من جدول آخر باستخدام طريقة orderByPowerJoins
.
User:: orderByPowerJoins ( ' profile.city ' );
إذا كنت بحاجة إلى تمرير بعض القيم الأولية للترتيب حسب الوظيفة، فيمكنك القيام بذلك على النحو التالي:
User:: orderByPowerJoins ([ ' profile ' , DB :: raw ( ' concat(city, ", ", state) ' ]);
سيقوم هذا الاستعلام بفرز النتائج بناءً على عمود city
في جدول user_profiles
. يمكنك أيضًا فرز نتائجك حسب المجموعات ( COUNT
أو SUM
أو AVG
أو MIN
أو MAX
).
على سبيل المثال، لفرز المستخدمين ذوي أكبر عدد من المشاركات، يمكنك القيام بذلك:
$ users = User:: orderByPowerJoinsCount ( ' posts.id ' , ' desc ' )-> get ();
أو للحصول على قائمة المنشورات التي تحتوي التعليقات فيها على أعلى متوسط من الأصوات.
$ posts = Post:: orderByPowerJoinsAvg ( ' comments.votes ' , ' desc ' )-> get ();
لديك أيضًا طرق لـ SUM
و MIN
و MAX
:
Post:: orderByPowerJoinsSum ( ' comments.votes ' );
Post:: orderByPowerJoinsMin ( ' comments.votes ' );
Post:: orderByPowerJoinsMax ( ' comments.votes ' );
في حالة رغبتك في استخدام الصلات اليسرى في الفرز، يمكنك أيضًا:
Post:: orderByLeftPowerJoinsCount ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsAvg ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsSum ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsMin ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsMax ( ' comments.votes ' );
يرجى الاطلاع على المساهمة للحصول على التفاصيل.
إذا اكتشفت أي مشكلات متعلقة بالأمان، فيرجى إرسال بريد إلكتروني إلى العنوان [email protected] بدلاً من استخدام أداة تعقب المشكلات.
يتم تطوير هذه الحزمة برعاية مجموعة Kirschbaum Development Group، وهي شركة تعتمد على المطورين وتركز على حل المشكلات وبناء الفريق والمجتمع. تعلم المزيد عنا أو انضم إلينا!
رخصة معهد ماساتشوستس للتكنولوجيا (MIT). يرجى الاطلاع على ملف الترخيص لمزيد من المعلومات.