تحدثنا في مقال سابق عن علاقة Many To Many ، وكيفية إستخدام pivot table، في هذه المقالة سيتم الحديث عن مجموعة من الإعتبارات والخصائص التي يجب إتباعها عند إنشاء أو التعامل مع pivot table.
لفرض أن لدينا الجداول التالية (books, authors) بحيث أن المؤلف له أكثر من كتاب، والكتاب له أكثر من مؤلف.
جدول المؤلفين
Schema::create('authors', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
جدول books
Schema::create('books', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->timestamps();
});
للربط بين جدولين (books, authors) نحتاج إلى جدول وسيط وهو author_book
Schema::create('author_book', function (Blueprint $table) {
$table->foreignId('author_id')->constrained();
$table->foreignId('book_id')->constrained();
});
تسمية pivot table والحقول
لماذا الاسم author_book
في عملية التسيمة يوجد مجموعة من القواعد:-
- يجب أن يتكون الاسم من شقين ويفصل بينهما underscore.
- الشق الأول من الاسم يجب أن يكون الحرف الأول منه يسبق الحرف الأول من الشق الثاني حسب ترتيب الأحرف الأبجدية للغة الإنجليزية aplanatic order.
- يجب أن يكون الشيقين بصيغة المفرد وليس الجمع.
محتويات جدول pivot table.
يجب على الأقل أن يحتوي جدول pivot table على حقلين وهما إسم الجدول لكن بصيغة الفرد ونضيف إليها id، مثلا إذا كان إسم الجدول الذي أريد ربطه هو posts يجب أن يكون إسم الحقل في pivot table باسم post_id، لذلك في مثالنا قمنا بسميته ب author_id والجدول الثاني book_id.
بناء العلاقة بين Models في علاقة Many To Many.
نستطيع وضع العلاقة في أي model وكذلك في الـ two model :
الخيار الأول:
App/Models/Author
class Author extends Model
{
use HasFactory;
public function Books(){
return $this->belongsToMany('App\Book');
}
}
الخيار الثاني
App/Models/Book
class Book extends Model
{
use HasFactory;
public function Authors(){
return $this->belongsToMany('App\Models\Author');
}
}
كما تم ذكره نستطيع أيضا أن نضع العلاقه في الـ two model وهذا يعتمد على طريقة وكيفية إستخدامنا للعلاقة.
تغيير إسم pivot table
على سبيل المثال أن إسم pivot table هو authors_books فيجب أن يتم إخبار الـ دوال العلاقات بذلك، من خلال إضافة parameter أخر وهو الإسم الجديد، وإلا لن تتعرف الدوال على إسم الجدول
public function Authors(){
return $this->belongsToMany('App\Models\Author' ,'authors_books');
}
public function Books(){
return $this->belongsToMany('App\Models\Book','authors_books');
}
ماذا لو أردنا تغيير أسماء الحقول.
على سبيل المثال لو أردنا تغيير أسماء الحقول من author_id إلى authors_id ومن books_id إلى books_id فيجب أن يتم كذلك إخبار العلاقات بذلك، من خلال إضافة parameters أخرى تحتوي على الأسماء الجديده
public function Books(){
return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id');
}
public function Authors(){
return $this->belongsToMany('App\Models\Author' ,'authors_books','authors_id','books_id');
}
إضافة Timestamps لجدول pivot table
إذا أردنا إضافة timestamps يجب أن يتم إخبار العلاقة بذلك
Schema::create('author_book', function (Blueprint $table) {
$table->foreignId('author_id')->constrained();
$table->foreignId('book_id')->constrained();
$table->timestamp();
});
في العلاقة يجب إضافة withTimeStamps
public function Books(){
return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
->withTimestamps();
}
طباعة حقل الحقول الإضافية لجدول pivot table في ملف blade
للوصول إلى timestamp في ملفات blade، يجب إستخدام pivot keyword
{{ $author->pivot->created_at }}
إضافة حقول أخرى لجدول pivot table.
مثلا لو أردنا إضافة حقل is_free إلى جدول pivot فإننا بحاجة لتعريف هذا الحقل في العلاقة
Schema::create('author_book', function (Blueprint $table) {
$table->foreignId('author_id')->constrained();
$table->foreignId('book_id')->constrained();
$table->timestamp();
$table->boolean('is_paid')->default(false);
});
يتم تعريف الحقول الإضافية من خلال إستخدام withPivot حيث تأخذ مصفوفة من الحقول
public function Books(){
return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
->withTimestamps()
->withPivot(['is_free']);
}
كما نلاحظ ان withPivot أخذ مصفوفة من الحقول
إدخال البيانات للحقول الإضافية في جدول pivot table.
ولإدخال البيانات لحقل is_free
$author->Books ()->attach($book,['is_free'=>false]);
تغيير الـ pivot keyword في ملفات العرض blade
ربما لأي سبب لا ترغب بالوصول إلى is_free من خلال إستخدام pivot keyword
{{ $author->pivot->is_free }}
نستطيع تغيير كلمة pivot من خلال العلاقة حيث يمكن إعطاء alias name لها من خلال إستخدام as
public function Books(){
return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
->withTimestamps()
->withPivot(['is_free'])
->as('authorBoook');
}
هنا تم إعطاء alias name وهو authorBook ولطباعة is_free في ملف blade نستخدم authorBook عوضا عن pivot
{{ $author->authorBook->is_free }}
تحديد العلاقة لحقل معين في جدول pivot table.
ماذا لو أردنا تحديد العلاقة فقط إذا كان is_free = 1، بمعنى أن يتم جلب الحقول الي is_free = 1
يتم ذلك من خلال إستخدام wherePivot
public function free_book(){
return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
->withTimestamps()
->withPivot(['is_free'])
->wherePivot('is_free',1);
}
كذلك نستطيع إستخدام wherePivotIn و wherePivotNotIn
public function free_book(){
return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
->withTimestamps()
->withPivot(['is_free'])
->wherePivotIn('priority',[1,2]);
}
إنشاء model للـ pivot table
كما نلاحظ أنه لم يتم إنشاء model للـ pivot table، فغالباً لن نحتاج إليه، لكن ماذا لو أردنا إنشاء model له للقيام ببعض العمليات الحسابية.
في الموديل عوضا عن أن يرث Model فإنه يجب أن يرث Pivot
class AuthorBook extends Pivot
{
use HasFactory;
}
وفي العلاقة يجب تعريف هذا الموديل من خلال إستخدام using
public function free_book(){
return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
->withTimestamps()
->withPivot(['is_free'])
->using(AuthorBook::class);
}
Mohammad
لدي مشكلة call to a member function attach on null