9 β Eloquent munosabatlari¶
β¬ οΈ Oldingi: 08 β Eloquent ORM β asoslar Β· π README Β· Keyingi: 10 β Query Builder va ilg'or Eloquent β‘οΈ
Bu bobda: ma'lumotni bir necha jadvalga bo'lib saqlaganimizdan keyin Eloquent ularni qanday "bog'lashini" o'rganamiz: bitta user koplab post yozadi (
hasMany), har post bitta userga tegishli (belongsTo), bitta postda koplab tag bo'ladi va bir tag koplab postda uchraydi (belongsToMany+ pivot jadval). Munosabatni o'qish ($user->posts), undan yangi yozuv yaratish ($user->posts()->create()), N:M niattach/detach/syncbilan boshqarish, pivotdagi qo'shimcha ma'lumot (withPivot), polimorf munosabatlar (morphMany/morphTo) vahasManyThroughni ko'rib chiqamiz. Oxirida N+1 muammosiga ham qisqa ishora qilamiz β uni 10-bobda hal qilamiz.
Muammo¶
8-bobda bitta Post modeli bilan ishladik: yaratdik, o'qidik, yangiladik, o'chirdik. Lekin real ilova hech qachon bitta jadvaldan iborat bo'lmaydi. Blog yozmoqchimiz deylik:
- har postni qaysidir user yozgan;
- har postda koplab comment (izoh) bo'ladi;
- har postga bir nechta tag (yorliq:
php,laravel,devops) yopishtiriladi va bitta tag koplab postda uchraydi.
Sof SQL bilsangiz, bu sizga tanish: jadvallarni foreign key (FK β boshqa jadvalning idsiga ishora qiluvchi ustun) orqali bog'laysiz, keyin JOIN bilan qaytadan yig'asiz. Lekin har safar qo'lda JOIN yozish zerikarli:
Eloquent buni butunlay yashiradi. Modelga bir marta "post userga tegishli" deb aytib qo'yasiz β keyin shunchaki:
$post = Post::find(1);
echo $post->user->name; // muallifning ismi
$user = User::find(5);
foreach ($user->posts as $post) { // shu userning hamma postlari
echo $post->title;
}
JOIN yo'q, user_id yo'q, qo'lda WHERE yo'q. Siz ob'ektlar tilida gapirasiz: "postning useri", "userning postlari". Eloquent orqa tarafda kerakli SQL'ni o'zi tuzadi. Mana shu β munosabatlar (relationships). Bu bobning vazifasi β modelga bu bog'lanishlarni qanday "aytib qo'yishni" o'rgatish.
π Munosabat β bu jadvaldagi ustun emas. Bu modeldagi metod. Migratsiyada faqat FK ustunini (user_id) yaratasiz; munosabat metodi esa Eloquent'ga shu ustunni qanday ishlatishni tushuntiradi. Ikkalasi birga ishlaydi.
Bir userda koplab post β hasMany va belongsTo¶
Eng ko'p uchraydigan munosabat β bir-koplab (one-to-many). Bitta user koplab post yozadi, lekin har bir post aniq bitta userga tegishli. Avval jadvallarni tayyorlaymiz. 7-bobdan eslang β migratsiyada FK ustunini shunday qo'shamiz:
// database/migrations/..._create_posts_table.php
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->text('body');
$table->boolean('published')->default(false);
$table->timestamps();
});
}
foreignId('user_id')->constrained() β bu user_id ustunini yaratadi va uni users jadvalining idsiga bog'laydi. cascadeOnDelete() β user o'chsa, uning postlari ham o'chadi.
π‘ constrained() jadval nomini ustun nomidan taxmin qiladi: user_id -> users jadvali. Konvensiyaga amal qilsangiz, hech narsa yozish shart emas. Boshqa jadvalga ishora qilsa, aniq belgilaysiz: ->constrained('authors').
Endi modellarga munosabatni yozamiz. User modelida:
// app/Models/User.php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
O'qilishi: "userda koplab post bor". Metod nomini ko'plikda (posts) yozamiz β chunki natija ko'p bo'ladi.
Endi teskari tomon β Post modelida:
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Post extends Model
{
protected $fillable = ['user_id', 'title', 'body', 'published'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
O'qilishi: "post bitta userga tegishli". Bu yerda metod nomi birlikda (user) β chunki natija bitta.
π Inverse relation (teskari munosabat). hasMany va belongsTo β bitta bog'lanishning ikki tomoni. hasMany FKni ushlamaydigan modelda (User), belongsTo esa FKni ushlaydigan modelda (Post, chunki user_id aynan posts jadvalida) yoziladi. Oddiy qoida: FK qaysi jadvalda bo'lsa, o'sha model belongsTo yozadi.
Foreign key konvensiyasi¶
Eloquent FK nomini o'zi taxmin qiladi: belongsTo(User::class) uchun u user_id ustunini qidiradi (model nomi kichik harfda + _id). Agar ustun boshqacha nomlangan bo'lsa (masalan author_id), uni aniq ko'rsatasiz:
β
Konvensiyaga amal qiling (user_id) β hech narsa yozish shart emas.
β Ustunni userId yoki usr deb nomlasangiz, har joyda qo'lda ko'rsatishga to'g'ri keladi.
Munosabatni o'qish¶
Endi sehr boshlanadi. Munosabatga ikki xil murojaat bor va ular farqi muhim:
$user = User::find(1);
// 1) Xususiyat sifatida (qavssiz) β tayyor natija qaytaradi:
$posts = $user->posts; // Collection (Post obyektlari to'plami)
echo $posts->count(); // nechta post bor
// 2) Metod sifatida (qavs bilan) β query builder qaytaradi:
$published = $user->posts() // bu yerda hali so'rov tugamagan
->where('published', true) // shart qo'shamiz
->latest() // saralash
->get(); // endi bazaga boramiz
$user->posts (qavssiz) β Eloquent so'rovni darrov bajaradi va Collection qaytaradi. $user->posts() (qavs bilan) β so'rovni davom ettirishga imkon beradi: where, orderBy, count zanjirlaysiz va oxirida get() yoki first() bilan yakunlaysiz.
π‘ Esda tutish oson: qavssiz = ma'lumot, qavs bilan = davom ettiriladigan so'rov. Faqat hamma postlar kerak bo'lsa β $user->posts. Filtrlash kerak bo'lsa β $user->posts()->where(...)->get().
Teskari tomon ham xuddi shunday ishlaydi:
$post = Post::find(1);
echo $post->user->name; // postning muallifi ismi
echo $post->user->email; // bitta so'rov bilan butun user keladi
Munosabat orqali yaratish β ->create() va ->save()¶
Eng kuchli imkoniyatlardan biri β munosabat orqali yangi yozuv yaratish. Postga user_id ni qo'lda yozmaysiz; Eloquent uni o'zi to'ldiradi:
$user = User::find(1);
// create() β massivdan yangi post yaratadi va bazaga yozadi:
$post = $user->posts()->create([
'title' => 'Birinchi postim',
'body' => 'Salom, dunyo!',
]);
// user_id => 1 AVTOMATIK qo'yiladi, qo'lda yozish shart emas
$user->posts()->create([...]) user_idni avtomatik 1 qilib qo'yadi β chunki siz allaqachon "userning postlari" kontekstidasiz. Bu sizni xatodan saqlaydi: noto'g'ri user_id yozib qo'yolmaysiz.
π create() ishlashi uchun siz massivda uzatgan ustunlar (title, body) Post modelida $fillable ichida bo'lishi shart β buni 8-bobda ko'rgan edik. Aks holda MassAssignmentException chiqadi. user_idni esa munosabatning o'zi qo'yadi β u mass-assignment himoyasini chetlab o'tadi, shu sababli uni $fillablega qo'shish shart emas (qo'shsangiz ham zarari yo'q).
save() esa allaqachon mavjud obyektni bog'laydi:
$post = new Post(['title' => 'Yangi', 'body' => '...']);
$user->posts()->save($post); // user_id ni qo'yib, bazaga saqlaydi
Bir nechta yozuvni birdan:
$user->posts()->createMany([
['title' => 'Post A', 'body' => '...'],
['title' => 'Post B', 'body' => '...'],
]);
β
$user->posts()->create([...]) β toza, FK avtomatik.
β Post::create(['user_id' => 1, ...]) β ishlaydi, lekin user_idni qo'lda yozasiz, xato qilish ehtimoli bor.
Bitta postda koplab izoh β yana bir hasMany¶
hasMany faqat user-post uchun emas. Post va comment ham aynan shunday: bitta post -> koplab comment. Migratsiya:
// ..._create_comments_table.php
public function up(): void
{
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->string('author');
$table->text('body');
$table->timestamps();
});
}
Post modeliga comment munosabatini qo'shamiz:
use Illuminate\Database\Eloquent\Relations\HasMany;
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
Comment modelida teskari tomon:
// app/Models/Comment.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Comment extends Model
{
protected $fillable = ['post_id', 'author', 'body'];
public function post(): BelongsTo
{
return $this->belongsTo(Post::class);
}
}
Endi izohni post orqali qo'shamiz:
$post = Post::find(1);
$post->comments()->create([
'author' => 'Oqil',
'body' => 'Ajoyib maqola!',
]);
echo $post->comments->count(); // nechta izoh bor
Bir-birga munosabat β hasOne¶
Goho munosabat bir-birga (one-to-one) bo'ladi: bitta userda aniq bitta profil. hasManydan farqi β hasOne Collection emas, bitta model (yoki null) qaytaradi. Migratsiya FK ni profiles jadvaliga qo'yadi:
// ..._create_profiles_table.php
Schema::create('profiles', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('bio')->nullable();
$table->string('website')->nullable();
$table->timestamps();
});
// User modelida:
use Illuminate\Database\Eloquent\Relations\HasOne;
public function profile(): HasOne
{
return $this->hasOne(Profile::class);
}
// Profile modelida (teskari):
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
$user = User::find(1);
echo $user->profile->bio; // bitta Profile (yoki null)
$user->profile()->create(['bio' => 'Laravel dasturchisi']);
π Farqni eslang: hasOne β bitta obyekt; hasMany β Collection. FK ikkalasida ham "narigi" jadvalda (profiles.user_id, posts.user_id). Faqat nechtaligi farq qiladi.
Koplab-koplab β belongsToMany va pivot jadval¶
Eng qiziq munosabat β koplab-koplab (many-to-many). Bitta postda koplab tag bor (php, laravel), va bitta tag koplab postda uchraydi. Bu yerda FKni qayerga qo'yamiz? postsgami? Yo'q β bitta postda ko'p tag bo'ladi, bitta ustunga sig'maydi. tagsgami? U ham bo'lmaydi.
Yechim β uchinchi jadval, "pivot jadval" (ko'prik jadval): u faqat ikkita FKdan iborat va "qaysi post qaysi tagga bog'langan"ini saqlaydi. Konvensiya bo'yicha nomi β ikki model nomining birlik shakli, alifbo tartibida, _ bilan: post_tag.
Migratsiyalar (uchta jadval: tags, va pivot post_tag):
// ..._create_tags_table.php
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->timestamps();
});
// ..._create_post_tag_table.php
Schema::create('post_tag', function (Blueprint $table) {
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->foreignId('tag_id')->constrained()->cascadeOnDelete();
$table->primary(['post_id', 'tag_id']); // takror juftlikni taqiqlaydi
});
Endi ikkala modelda ham belongsToMany yozamiz:
// Post modelida:
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class);
}
// Tag modelida:
public function posts(): BelongsToMany
{
return $this->belongsToMany(Post::class);
}
π belongsToMany ikkala tomonda ham bir xil β chunki munosabat simmetrik. Eloquent pivot jadval nomini (post_tag) va ustunlarni (post_id, tag_id) konvensiyadan o'zi topadi. Boshqa nom ishlatsangiz aniq ko'rsatasiz: belongsToMany(Tag::class, 'tagging', 'post_id', 'tag_id').
attach, detach, sync β bog'lanishni boshqarish¶
Many-to-many'da create() o'rniga maxsus uchta metod ishlatamiz. Ular pivot jadvaldagi qatorlarni boshqaradi:
$post = Post::find(1);
// attach β bog'lash (pivotga qator qo'shadi):
$post->tags()->attach(7); // id=7 tagni bog'lash
$post->tags()->attach([7, 8, 9]); // bir nechtasini birdan
// detach β bog'ni uzish (pivotdan qatorni o'chiradi, tagning o'zi qolaveradi):
$post->tags()->detach(7); // faqat 7-tagni uzish
$post->tags()->detach(); // hamma bog'larni uzish
// sync β RO'YXATNI to'liq moslashtirish (qolganlarini uzadi):
$post->tags()->sync([8, 9]); // endi FAQAT 8 va 9 qoladi
sync β eng ko'p ishlatiladigani: forma checkbox'laridan kelgan ro'yxatni to'liq moslaydi. Ro'yxatda yo'q taglar uziladi, yangilari bog'lanadi. Mavjudlarini uzmasdan faqat qo'shish kerak bo'lsa:
π‘ attach va sync farqini eslang: attach β "qo'sh" (mavjudlariga tegmaydi, takror qo'shishi mumkin), sync β "shu ro'yxat bo'lsin" (qolgan hammasini uzadi). Forma uchun deyarli har doim sync.
O'qish β hasMany kabi:
foreach ($post->tags as $tag) {
echo $tag->name; // php, laravel, ...
}
// Teskari tomon ham ishlaydi:
$tag = Tag::where('name', 'laravel')->first();
echo $tag->posts->count(); // bu tag nechta postda
Pivotdagi qo'shimcha ma'lumot β withPivot¶
Goho pivot jadvalga qo'shimcha ustun kerak bo'ladi: tagni kim qo'shgani, qachon qo'shilgani. Migratsiyaga ustun qo'shamiz:
Schema::create('post_tag', function (Blueprint $table) {
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->foreignId('tag_id')->constrained()->cascadeOnDelete();
$table->string('added_by')->nullable(); // qo'shimcha ustun
$table->timestamps(); // created_at / updated_at
$table->primary(['post_id', 'tag_id']);
});
Munosabatda bu ustunlarni withPivot bilan "ochamiz", withTimestamps esa vaqt ustunlarini:
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class)
->withPivot('added_by')
->withTimestamps();
}
Endi pivot ma'lumotini pivot xususiyati orqali o'qiymiz:
foreach ($post->tags as $tag) {
echo $tag->name;
echo $tag->pivot->added_by; // kim qo'shgan
echo $tag->pivot->created_at; // qachon
}
Pivot ma'lumotini yozish β attachning ikkinchi argumenti orqali:
$post->tags()->attach(7, ['added_by' => 'Oqil']);
// sync bilan ham:
$post->tags()->sync([
8 => ['added_by' => 'Ali'],
9 => ['added_by' => 'Vali'],
]);
π pivot so'zini boshqacha nomlamoqchi bo'lsangiz (o'qilishi chiroyli bo'lsin uchun), ->as('tagging') ishlatasiz β keyin $tag->tagging->added_by bo'ladi.
Uzoq munosabat β hasManyThrough¶
Goho ikki model uchinchisi orqali bog'lanadi. Misol: Country (davlat) -> User (o'sha davlatdagi userlar) -> Post (ularning postlari). Davlatning hamma postlarini bitta munosabatda olishni xohlaymiz, garchi posts jadvalida country_id umuman yo'q.
Buning ishlashi uchun users jadvalida country_id FK ustuni bo'lishi kerak (posts jadvalida esa user_id, allaqachon bor):
// ..._create_users_table.php ichida (yoki alohida migratsiyada):
$table->foreignId('country_id')->constrained()->cascadeOnDelete();
// Country modelida:
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
public function posts(): HasManyThrough
{
// "Country'ning postlari, User orqali"
return $this->hasManyThrough(Post::class, User::class);
}
$country = Country::find(1);
foreach ($country->posts as $post) { // shu davlatdagi userlarning hamma postlari
echo $post->title;
}
Eloquent zanjirni o'zi quradi: countries.id -> users.country_id -> users.id -> posts.user_id. Bu murakkab JOIN'ni qo'lda yozmaslik uchun juda qulay.
π‘ hasManyThrough kamroq uchraydi, lekin "oralig'idagi modeldan o'tib, narigisiga yetish" kerak bo'lganda eslab qoling β qo'lda ikkita JOIN yozishdan saqlaydi.
Polimorf munosabat β morphMany va morphTo¶
Endi qiziq holat. Comment (izoh) faqat postga emas, videoga ham, rasmga ham yozilishi mumkin. Har biriga alohida post_comments, video_comments jadvali yaratish β ko'p takror. Yechim β polimorf munosabat (polymorphic): bitta comments jadvali hamma uchun ishlaydi.
Sir β ikkita maxsus ustunda: commentable_id (qaysi yozuvning idsi) va commentable_type (qaysi model: App\Models\Post yoki App\Models\Video).
π Diqqat: bu bo'limda comments jadvalini va Comment modelini polimorf ko'rinishga qayta quramiz β yuqorida (bir-koplab izoh bo'limida) ular post_id + author ustunlari bilan tuzilgan edi. Polimorf yondashuvda o'sha post_id va author o'rniga commentable_id + commentable_type keladi, Comment modelidagi belongsTo(Post::class) esa pastdagi morphTo() bilan almashadi. Ya'ni quyidagi ikkala variant bir xil jadvalning ikki xil ko'rinishi β ketma-ket ikkalasini birga ishlatmang, polimorf kerak bo'lsa shu variantni tanlang.
Migratsiya buni bitta qatorda yaratadi:
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->morphs('commentable'); // commentable_id + commentable_type
$table->text('body');
$table->timestamps();
});
Comment modelini ham polimorf ko'rinishga moslaymiz: eski belongsTo(Post::class) o'rniga morphTo (teskari, "men kimga tegishliman"), $fillable esa endi faqat body:
// app/Models/Comment.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class Comment extends Model
{
protected $fillable = ['body'];
public function commentable(): MorphTo
{
return $this->morphTo();
}
}
Post va Video modellarida morphMany:
// Post modelida:
use Illuminate\Database\Eloquent\Relations\MorphMany;
public function comments(): MorphMany
{
return $this->morphMany(Comment::class, 'commentable');
}
// Video modelida xuddi shu:
public function comments(): MorphMany
{
return $this->morphMany(Comment::class, 'commentable');
}
Ishlatish β oddiy hasMany kabi, lekin orqada commentable_type to'ldiriladi:
$post = Post::find(1);
$post->comments()->create(['body' => 'Postga izoh']);
$video = Video::find(1);
$video->comments()->create(['body' => 'Videoga izoh']);
// Teskari: izoh kimga yozilganini bilish (Post yoki Video qaytaradi):
$comment = Comment::find(1);
$owner = $comment->commentable; // Post obyekti yoki Video obyekti
echo get_class($owner); // App\Models\Post
π Bitta comments jadvali β istalgancha model uchun. Yangi Photo model qo'shsangiz, faqat unga morphMany yozasiz; jadvalga tegmaysiz. Mana shuning uchun "polimorf" β bitta munosabat ko'p shaklga kiradi.
N+1 muammosiga ishora¶
Munosabatlar shunchalik qulayki, ko'pincha bilmagan holda unumdorlik tuzog'iga tushasiz. 10 ta postni ko'rsatib, har biriga muallif ismini qo'shmoqchimiz:
$posts = Post::all(); // 1 ta so'rov: hamma post
foreach ($posts as $post) {
echo $post->user->name; // HAR aylanishda YANA bitta so'rov!
}
Bu yerda 1 (postlar uchun) + 10 (har postning useri uchun) = 11 so'rov ketadi. Postlar 100 ta bo'lsa β 101 so'rov. Bu N+1 muammosi: bittadan boshqasi N marta takrorlanadi.
Yechim β eager loading (oldindan yuklash): with() bilan munosabatni bitta qo'shimcha so'rovda oldindan olib qo'yamiz:
$posts = Post::with('user')->get(); // 2 ta so'rov: postlar + ularning userlari
foreach ($posts as $post) {
echo $post->user->name; // endi bazaga bormaydi, tayyor turibdi
}
100 ta post bo'lsa ham β atigi 2 so'rov. Bu β Eloquent'da unumdorlikning eng muhim odati.
π‘ Hozircha shuni eslang: foreach ichida munosabatga murojaat qilsangiz, with() ishlating. To'liq mexanikasi β with, load, loadMissing, withCount, has, whereHas β keyingi 10-bobda batafsil. Hozir faqat "N+1 borligini" his qilib qo'ying.
Munosabat turlari β qisqacha jadval¶
| Munosabat | Qayerda | FK qayerda | Natija |
|---|---|---|---|
hasOne |
"egasi" modelda | narigi jadvalda | bitta model / null |
hasMany |
"egasi" modelda | narigi jadvalda | Collection |
belongsTo |
FK ushlagan modelda | shu modelning jadvalida | bitta model / null |
belongsToMany |
ikkala tomonda | pivot jadvalda | Collection |
hasManyThrough |
"egasi" modelda | oraliq modelda | Collection |
morphMany |
"egasi" modelda | ..._id + ..._type |
Collection |
morphTo |
polimorf modelda | shu modelda | har xil model |
π Eng muhim qoidani takrorlaymiz: FK qaysi jadvalda bo'lsa, o'sha model belongsTo yozadi. Qolgan hammasi shu mantiqdan kelib chiqadi.
9-bob mashqlari¶
Quyidagi mashqlarni blog nomli yangi Laravel loyihasida (yoki 8-bobdagi loyihada davom ettirib) bajaring. Har mashqda model, migratsiya yoki Tinker (php artisan tinker) kerak bo'ladi. Yechimlarni yozmaymiz β o'zingiz qilib o'rganasiz.
UservaPostmodellarini yarating (php artisan make:model Post -m).postsmigratsiyasigaforeignId('user_id')->constrained()qo'shing va migratsiyani ishlating.Usermodeligaposts()hasManymunosabatini,Postmodeligauser()belongsTomunosabatini yozing. Har ikkalasiga to'g'ri qaytarish tipini (HasMany,BelongsTo) qo'ying.- Tinker'da bitta user yarating, keyin
$user->postsni chaqiring. Natija nima β bo'sh Collection'mi? Uningcount()ini chop eting. $user->posts()->create([...])orqali shu userga 3 ta post yarating. Bazadauser_idto'g'ri to'lganini Tinker'da$user->postsorqali tekshiring.Post::find(1)->user->nameni chop eting. Endi teskari yo'nalish (postdan userga) ishlayotganini ko'ring.$user->posts(qavssiz) va$user->posts()->where('published', true)->get()(qavs bilan) farqini sinab ko'ring: birinchisi hamma postni, ikkinchisi faqat e'lon qilinganlarini qaytarishini tasdiqlang.Commentmodeli vacommentsmigratsiyasini yarating (post_idFK bilan).Postgacomments()hasMany,Commentgapost()belongsToqo'shing.$post->comments()->create([...])bilan bitta postga 2 ta izoh qo'shing va$post->comments->count()ni tekshiring.Profilemodeli va migratsiyasini yarating,Usergaprofile()hasOnemunosabatini qo'shing.$user->profilebitta obyekt qaytarishini (Collection emas) tasdiqlang.$user->profile()->create([...])bilan profil yarating, keyin$user->profile->bioni o'qing.Tagmodeli,tagsmigratsiyasi vapost_tagpivot migratsiyasini (post_id+tag_id, primary kalit ikkalasiga) yarating.PostvaTagmodellarigabelongsToManymunosabatini qo'shing (ikkala tomonda). 3 ta tag yarating.$post->tags()->attach([1, 2])bilan postga ikkita tag bog'lang, keyin$post->tagsorqali tekshiring.$post->tags()->detach(1)bilan bitta tagni uzing.post_tagjadvalida nima o'zgardi β Tinker yokiphp artisan dborqali ko'ring.$post->tags()->sync([2, 3])ni ishlating. Avval bog'langan taglardan qaysilari qoldi, qaysilari uzildi βsyncningattachdan farqini tushuntirib bering (izoh sifatida yozib qo'ying).post_tagjadvaligaadded_byustunini qo'shing (yangi migratsiya yokitags()munosabatigawithPivot('added_by')).$post->tags()->attach(2, ['added_by' => 'Oqil'])qiling.- 16-mashqdan keyin
foreach ($post->tags as $tag) { echo $tag->pivot->added_by; }orqali pivot ma'lumotini o'qing. Videomodeli yarating va polimorfcommentsmigratsiyasini ($table->morphs('commentable')) tuzing.PostvaVideogamorphMany,Commentgacommentable()morphToqo'shing.- Bitta postga va bitta videoga
comments()->create([...])bilan izoh qo'shing.Comment::first()->commentableqaysi model (Post yoki Video) qaytarishiniget_class()bilan tekshiring. - N+1 ni o'z ko'zingiz bilan ko'ring:
DB::enableQueryLog()yoqib, avvalPost::all()+foreachichida$post->user->name, keyinPost::with('user')->get()bilan bir xil sikl uchunDB::getQueryLog()dagi so'rovlar sonini solishtiring.