16 β Eloquent API Resources va JSON¶
β¬ οΈ Oldingi: 15 β Middleware Β· π README Β· Keyingi: 17 β RESTful API va Sanctum β‘οΈ
Bu bobda: modelni JSON sifatida toza, nazorat ostida qaytarishni o'rganamiz. Avval Eloquent'ning "tekin" usuli (
toJson/toArray) nega xavfli ekanini ko'ramiz, keyin API Resource (make:resource) bilan javobning aniq shaklini boshqaramiz: qaysi maydon chiqadi, uni qayta nomlash, sanani formatlash. So'ng Resource Collection orqali ro'yxat qaytarish,paginate()bilan JSON'ga avtomatik keladiganmeta/links, shartli maydonlar (when,whenLoaded), Resource ichida nested relation, javobnidataichiga "o'rash" (wrapping) va kollektsiya metodlari (map/filter/pluck) bilan API javobini standartlashtirishni ko'rib chiqamiz.
Muammo¶
15-bobgacha biz natijani odamga β brauzerga HTML qilib ko'rsatdik (Blade). Lekin endi mobil ilova yoki React frontend bizning serverdan ma'lumotni JSON ko'rinishida so'raydi. "Postlar ro'yxatini ber", "ID 7 foydalanuvchini ber" β javob HTML emas, mashina o'qiydigan JSON bo'lishi kerak.
Laravel'da bu juda oson ko'rinadi. Controller'dan modelni shunchaki qaytarsangiz, Laravel uni avtomatik JSON qiladi:
Brauzerda ochsangiz:
{
"id": 7,
"name": "Ali Valiyev",
"email": "ali@example.com",
"email_verified_at": "2026-05-01T10:00:00.000000Z",
"is_admin": 1,
"created_at": "2026-04-01T09:00:00.000000Z",
"updated_at": "2026-06-01T12:00:00.000000Z"
}
Ishladi-ku? Lekin yaxshilab qarang. is_admin β ichki bayroq, uni tashqi dunyoga ko'rsatish kerakmidi? email_verified_at, updated_at β mobil ilovaga nima keragi bor? Eng yomoni: ertaga jadvalga salary (maosh) yoki secret_token ustun qo'shsangiz, ular ham avtomatik JSON'ga tushib, butun internetga ochilib qoladi. Siz hatto sezmaysiz ham.
Demak, muammo aniq: modelni "yalang'och" qaytarish β bu butun jadvalni nazoratsiz ochib qo'yish. Bizga shunday qatlam kerakki, u "API javobida aynan qaysi maydon, qaysi nom bilan, qanday formatda chiqadi"ni bitta joyda, aniq belgilab bersin. Mana shu qatlam β API Resource.
Birinchi urinish: $hidden va toArray¶
Eng tez yechim β modelda $hidden ishlatish (8-bobda ko'rgan edingiz):
class User extends Authenticatable
{
protected $hidden = ['password', 'remember_token', 'is_admin'];
}
Endi password, remember_token, is_admin JSON'ga chiqmaydi. toArray() ham, toJson() ham, avtomatik qaytarish ham β hammasi shu ro'yxatni hurmat qiladi.
π $hidden β "qora ro'yxat" (nimani yashirish). Aksincha $visible β "oq ro'yxat" (faqat shularni ko'rsatish). Ikkalasi ham faqat parol kabi maxfiy ustunlardan saqlaydi.
Lekin $hidden ikki muhim narsani qila olmaydi:
- Maydonni qayta nomlash β
nameniismqilib chiqarish. - Javob shaklini boshqarish β bir API'da
emailkerak, boshqasida kerak emas. Model bitta, talab har xil.
$hidden modelga "yopishtirilgan" β u har joyda bir xil ishlaydi. Bizga esa har bir API endpoint uchun alohida shakl kerak. Mana shu yerda API Resource yutadi: u modelni o'zgartirmaydi, balki uning yonida turib "javobni qanday yasashni" hal qiladi.
π‘ Qoida: kichik loyihada $hidden yetadi. Jiddiy API yozayotgan bo'lsangiz β to'g'ridan-to'g'ri Resource'dan boshlang. Pastda nega ekanini ko'rasiz.
API Resource yaratish¶
Resource β bu modelni JSON'ga aylantiruvchi "tarjimon" klass. Artisan bilan yaratamiz:
Bu app/Http/Resources/UserResource.php faylini yaratadi. Ichi shunaqa ko'rinadi (men maydonlarni o'zbekcha javob uchun moslab to'ldirdim):
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
/**
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'ism' => $this->name,
'email' => $this->email,
'qoshilgan' => $this->created_at->toDateString(),
];
}
}
Diqqat qiling: toArray() ichida $this->id, $this->name deb yozdik β go'yo $this modelning o'zi. Aslida Resource modelni "o'rab" oladi va unga yo'naltirib turadi, shuning uchun model ustunlariga to'g'ridan-to'g'ri murojaat qila olasiz. Bu yerda butun nazorat sizda:
'ism' => $this->nameβnameustunini JSON'daismdeb chiqaramiz (qayta nomlash).password,is_adminβ ro'yxatda umuman yo'q, demak JSON'ga chiqmaydi. "Yashirish" ham kerak emas β kiritmasangiz bo'ldi.$this->created_at->toDateString()β sanani2026-04-01T09:00:00Zo'rniga toza2026-04-01qilib formatlash.
π Resource β oq ro'yxat mantig'ida ishlaydi: faqat siz yozgan maydon chiqadi. Bu $hiddendan xavfsizroq, chunki jadvalga yangi maxfiy ustun qo'shilsa ham, u toArray()da yo'q β avtomatik ochilib qolmaydi.
Resource'dan foydalanish β bitta model¶
Controller'da modelni Resource'ga "o'raymiz":
use App\Http\Resources\UserResource;
Route::get('/users/{user}', function (User $user) {
return new UserResource($user);
});
Javob:
{
"data": {
"id": 7,
"ism": "Ali Valiyev",
"email": "ali@example.com",
"qoshilgan": "2026-04-01"
}
}
Endi javob aniq nazorat ostida. is_admin yo'q, password yo'q, name o'rniga ism, sana toza. Va e'tibor bering β javob "data" kalitining ichida. Bu Laravel'ning ataylab qilgan ishi (wrapping), bob oxirida buni boshqarishni ham ko'ramiz.
π‘ Nega Resource ichida ham Request $request keladi? Chunki ba'zan javobni so'rovga qarab o'zgartirish kerak bo'ladi β masalan, faqat admin so'rasa qo'shimcha maydon qaytarish. $request orqali joriy so'rovga (va auth() foydalanuvchisiga) yeta olasiz. Buni "shartli maydonlar" bo'limida ishlatamiz.
Ro'yxat qaytarish: Resource Collection¶
Bitta model uchun new UserResource($user) yozdik. Endi ro'yxat kerak: barcha foydalanuvchilar. Eng oddiy yo'l β Resource klassining collection() metodi:
use App\Http\Resources\UserResource;
Route::get('/users', function () {
return UserResource::collection(User::all());
});
collection() β kollektsiyadagi har bir modelni alohida UserResource orqali o'tkazadi va natijani massivga yig'adi. Javob:
{
"data": [
{ "id": 1, "ism": "Ali", "email": "ali@...", "qoshilgan": "2026-01-10" },
{ "id": 2, "ism": "Vali", "email": "vali@...", "qoshilgan": "2026-02-15" }
]
}
Bitta Resource yozdingiz β ham bitta model, ham ro'yxat uchun ishlaydi. Aksariyat hollarda sizga shuncha kerak.
Alohida Collection klassi (--collection)¶
Ba'zan butun ro'yxat darajasida qo'shimcha ma'lumot qo'shmoqchi bo'lasiz β masalan "jami nechta", "qaysi versiya". Buning uchun alohida Collection klassi yaratamiz:
Bu app/Http/Resources/UserCollection.php ni yaratadi:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
{
/**
* @return array<int|string, mixed>
*/
public function toArray(Request $request): array
{
return [
'data' => $this->collection,
'meta' => [
'jami_soni' => $this->collection->count(),
'manba' => 'kutubxona API',
],
];
}
}
Foydalanish:
Javob data yonida meta ham oladi:
{
"data": [ { "id": 1, "ism": "Ali", ... } ],
"meta": { "jami_soni": 2, "manba": "kutubxona API" }
}
π $this->collection β Collection ichida modellar to'plamiga ishora qiladi. Laravel uni avtomatik har bir element uchun mos Resource'ga (UserResource) o'rab beradi, agar nom konvensiyasiga (User**Collection** -> User**Resource**) mos kelsa. Aniq belgilamoqchi bo'lsangiz, Collection klassida public $collects = UserResource::class; yozasiz.
π‘ Ko'pchilik loyihalarda alohida Collection klassi kerak emas β UserResource::collection(...) yetadi. Alohida klass faqat ro'yxat darajasida maxsus meta qo'shganda yoki murakkab yig'ish kerak bo'lganda asqotadi.
Pagination β sahifalash JSON'da¶
Real API hech qachon 10 000 ta yozuvni bir javobda qaytarmaydi. Sahifalab beramiz: bir sahifaga 15 ta, qolganini ?page=2 orqali. Buning sehri shundaki β Resource bilan paginatsiya avtomatik birlashadi.
all() o'rniga paginate() ishlatamiz, xolos:
Va Laravel javobga links (sahifalar orasidagi havolalar) va meta (joriy sahifa, jami soni) bloklarini o'zi qo'shadi:
{
"data": [
{ "id": 1, "ism": "Ali", "email": "ali@...", "qoshilgan": "2026-01-10" }
],
"links": {
"first": "http://localhost/api/users?page=1",
"last": "http://localhost/api/users?page=8",
"prev": null,
"next": "http://localhost/api/users?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 8,
"per_page": 15,
"to": 15,
"total": 117
}
}
Frontend dasturchi xursand: u meta.total dan jami nechta yozuv borligini, links.next dan keyingi sahifa manzilini to'g'ridan-to'g'ri oladi. Siz esa hech narsa qo'lda yozmadingiz β paginate() va Resource o'zi hal qildi.
π Muhim tuzoq: Resource bilan paginatsiya ishlashi uchun paginate() natijasini UserResource::collection(...) ichiga uzating. Agar siz simplePaginate() ishlatsangiz, metada total/last_page bo'lmaydi (u keyingi/oldingi havolalarni bilibgina, jami sonni hisoblamaydi β shu sabab tezroq).
π‘ paginate() β Eloquent va Query Builder ikkalasida ham bor. Sahifa o'lchamini foydalanuvchi tanlasin desangiz: User::paginate($request->integer('per_page', 15)). Lekin yuqori chegara qo'ying (mas. 100), aks holda kimdir ?per_page=999999 bilan serverni cho'ktiradi.
Shartli maydonlar: when()¶
Hamma maydon har doim chiqishi shart emas. Masalan, foydalanuvchining email manzilini faqat admin ko'rsin, oddiy mehmon ko'rmasin. when() aynan shuning uchun:
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'ism' => $this->name,
'email' => $this->when($request->user()?->is_admin, $this->email),
];
}
when($shart, $qiymat) β agar $shart rost bo'lsa, maydon JSON'ga qo'shiladi; aks holda u butunlay yo'qoladi (null emas, umuman bo'lmaydi). Admin ko'rsa email bor, oddiy foydalanuvchi ko'rsa hatto kaliti ham yo'q.
π Farqni his qiling: 'email' => $shart ? $this->email : null yozsangiz, kalit har doim chiqadi, faqat qiymati null bo'ladi. when() esa kalitning o'zini olib tashlaydi. API'da bu toza-roq: "yo'q ma'lumot" va "null ma'lumot" β boshqa-boshqa narsa.
π‘ Og'ir qiymat (masalan ko'p hisob-kitob talab qiladigan narsa) bo'lsa, ikkinchi argumentni closure qiling β u faqat shart rost bo'lgandagina ishga tushadi:
Relation faqat yuklangan bo'lsa: whenLoaded()¶
Endi eng muhim β eng ko'p xato qilinadigan joy. Post Resource'iga muallif (user) ma'lumotini ham qo'shmoqchisiz:
// β Sodda, lekin xavfli yo'l:
return [
'id' => $this->id,
'sarlavha' => $this->title,
'muallif' => new UserResource($this->user), // har safar relation'ga murojaat
];
Bu "ishlaydi", lekin yashirin tuzoq bor. Agar siz controller'da with('user') qilmagan bo'lsangiz, $this->user har bir post uchun bazaga alohida so'rov yuboradi. 50 ta post β 50 ta qo'shimcha so'rov. Bu 10-bobda ko'rgan N+1 muammosi, faqat endi u Resource ichida yashiringan.
Yechim β whenLoaded(). U relation'ni faqat oldindan yuklangan bo'lsa qo'shadi, aks holda umuman tegmaydi:
// β
To'g'ri yo'l:
return [
'id' => $this->id,
'sarlavha' => $this->title,
'muallif' => new UserResource($this->whenLoaded('user')),
];
Endi controller'da relation'ni yuklasangiz β muallif JSON'da chiqadi; yuklamasangiz β muallif kaliti umuman bo'lmaydi va bazaga ortiqcha so'rov ham ketmaydi:
// muallif bilan:
return PostResource::collection(Post::with('user')->paginate(15));
// muallifsiz (yengilroq javob):
return PostResource::collection(Post::paginate(15));
Bitta Resource β ikki xil javob, va N+1 dan himoyalangan. Resource "men relation'ni o'zim yuklab olmayman, agar berilgan bo'lsa qo'shaman" deydi. Bu β to'g'ri mas'uliyat taqsimoti: nimani yuklashni controller hal qiladi, qanday ko'rsatishni Resource.
π Munosabat soni uchun whenCounted() ham bor. Controller'da Post::withCount('comments') qilsangiz, Resource'da:
comments_count yuklangan bo'lsa chiqadi, yo'q bo'lsa kaliti ham bo'lmaydi.
Nested Resource β Resource ichida Resource¶
Yuqorida new UserResource($this->whenLoaded('user')) yozdik β bu nested (ichma-ich) Resource. Post Resource'i muallifni UserResource orqali, muallif Resource'i esa o'z navbatida boshqa narsalarni o'rashi mumkin. Har bir model o'z Resource'iga ega bo'ladi va ular bir-birini chaqiradi.
Ko'plab relation (hasMany) uchun collection'dan foydalanamiz:
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'sarlavha' => $this->title,
'muallif' => new UserResource($this->whenLoaded('user')),
'izohlar' => CommentResource::collection($this->whenLoaded('comments')),
];
}
Controller'da ikkala relation'ni ham yuklaymiz:
Javob β chiroyli ichma-ich tuzilma:
{
"data": {
"id": 1,
"sarlavha": "Laravel bilan API",
"muallif": { "id": 7, "ism": "Ali", "email": "ali@..." },
"izohlar": [
{ "id": 10, "matn": "Zo'r maqola!" },
{ "id": 11, "matn": "Rahmat" }
]
}
}
π‘ Diqqat: whenLoaded('comments') ni CommentResource::collection(...) ichiga uzatdik. Bu β to'g'ri qolip. Relation yuklanmagan bo'lsa, whenLoaded bo'sh "yo'q" qiymatini qaytaradi va izohlar kaliti umuman chiqmaydi; yuklangan bo'lsa, har bir izoh CommentResource orqali o'tadi.
Wrapping β data o'rashini boshqarish¶
Sezgan bo'lsangiz, har bir javob "data" kalitining ichida keldi. Bu Laravel'ning standart "o'rash" (wrapping) xatti-harakati. U yaxshi narsa: javob doim bir xil tuzilishda bo'ladi, frontend doim response.data ni o'qiydi.
Wrapper nomini o'zgartirmoqchi bo'lsangiz, AppServiceProviderning boot() metodida:
use Illuminate\Http\Resources\Json\JsonResource;
public function boot(): void
{
JsonResource::wrap('natija'); // "data" o'rniga "natija"
}
O'rashni butunlay olib tashlash uchun (kamdan-kam kerak bo'ladi):
π Muhim nozik nuqta: o'rashni olib tashlasangiz ham, paginatsiya uchun meta/links ishlashi uchun data qatlami baribir kerak bo'ladi β shuning uchun paginatsiya qilingan javoblarda data saqlanib qoladi. Amalda standart data o'rashini o'z holicha qoldirish eng xavfsiz yo'l: butun loyihada bitta, bashorat qilinadigan shakl.
π‘ Maslahat: yangi API boshlaganda wrapping'ni o'zgartirmang. Standart data shakli butun Laravel ekotizimida kutiladi (mobil SDK, hujjatlar, misollar hammasi shunga moslangan). O'zgartirish β keyinchalik chalkashlik manbai.
Kollektsiya metodlari bilan javobni shakllash¶
Resource ichida siz oddiy modeldan tashqari butun kollektsiya ustida ham ishlashingiz mumkin β Laravel kollektsiyalari map, filter, pluck, sum kabi kuchli metodlarga ega (8-bobda ko'rdik). Bu API javobini moslashda asqotadi.
Masalan, Collection klassida faqat faol foydalanuvchilarni qoldirib, ularning ismlaridan alohida ro'yxat yasaymiz:
public function toArray(Request $request): array
{
return [
'foydalanuvchilar' => $this->collection,
'faollar_ismi' => $this->collection
->where('holat', 'faol') // filter: faqat faollar
->pluck('name') // pluck: faqat ism ustuni
->values(), // kalitlarni 0,1,2 ga tiklash
'umumiy_soni' => $this->collection->count(),
];
}
Yoki har bir modeldan qisqartirilgan ko'rinish yasash uchun map:
'qisqacha' => $this->collection->map(fn ($user) => [
'id' => $user->id,
'ism' => $user->name,
])->values(),
π where, pluck, map β bular SQL emas, bular xotiradagi kollektsiya ustida ishlaydi. Demak ular allaqachon bazadan olingan yozuvlar ustida bajariladi. Katta ro'yxatni filtrlash kerak bo'lsa, buni bazada (->where(...) Eloquent so'rovida) qiling, kollektsiyada emas β aks holda 100 000 qatorni xotiraga olib, keyin filtrlab o'tirasiz.
π‘ values() ni unutmang: where/filter'dan keyin kalitlar (0, 1, 2...) "teshikli" qolishi mumkin (0, 3, 7...), va JSON'da bu massiv emas, obyekt sifatida chiqib qoladi. values() kalitlarni qayta tartiblab, toza massiv beradi.
Hammasini birlashtirib: standart API javobi¶
Endi o'rganganlarimizni bitta to'liq misolga yig'amiz. Blog API'sida postlar ro'yxati endpoint'i β paginatsiya, nested muallif, shartli maydon, N+1 himoyasi bilan.
PostResource:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource
{
/**
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'sarlavha' => $this->title,
'qisqa_matn' => str($this->body)->limit(120)->value(),
'chop_etilgan' => (bool) $this->is_published,
'sana' => $this->created_at->toDateString(),
'muallif' => new UserResource($this->whenLoaded('user')),
'izohlar_soni' => $this->whenCounted('comments'),
'tahrir_url' => $this->when(
$request->user()?->id === $this->user_id,
fn () => route('posts.edit', $this->id),
),
];
}
}
Controller (slim struktura, Laravel 11+):
<?php
namespace App\Http\Controllers;
use App\Http\Resources\PostResource;
use App\Models\Post;
class PostController extends Controller
{
public function index()
{
$postlar = Post::query()
->with('user') // N+1 dan saqlaydi (nested muallif uchun)
->withCount('comments') // izohlar_soni uchun
->latest()
->paginate(15);
return PostResource::collection($postlar);
}
}
Marshrut (routes/api.php β bu fayl php artisan install:api dan keyin paydo bo'ladi, 17-bobda batafsil):
Natija β toza, bashorat qilinadigan, xavfsiz JSON:
{
"data": [
{
"id": 1,
"sarlavha": "Laravel API'lari",
"qisqa_matn": "Bu maqolada API Resource...",
"chop_etilgan": true,
"sana": "2026-06-10",
"muallif": { "id": 7, "ism": "Ali", "email": "ali@..." },
"izohlar_soni": 4
}
],
"links": { "first": "...", "last": "...", "prev": null, "next": "...?page=2" },
"meta": { "current_page": 1, "per_page": 15, "total": 117, "last_page": 8 }
}
Diqqat qiling: tahrir_url faqat postning egasi so'rasagina chiqadi (when), muallif faqat with('user') qilingani uchun chiqdi (whenLoaded), izohlar_soni withCount tufayli keldi, va butun javob sahifalangan. Bitta endpoint β barcha tushunchalar birga ishlaydi.
β
To'g'ri: controller nimani yuklashni hal qiladi (with, withCount, paginate), Resource qanday ko'rsatishni hal qiladi.
β Xato: Resource ichida Post::with(...) yoki yangi so'rov yozish. Resource β faqat shakl beruvchi, u ma'lumot olib kelmasligi kerak.
Qachon Resource, qachon yo'q?¶
- Resource ishlating: ommaviy API, mobil ilova backend'i, frontend (React/Vue) bilan ishlaydigan loyiha β qisqasi, JSON tashqariga chiqadigan har qanday joyda.
- Resource shart emas: ichki, bir martalik, faqat o'zingiz ishlatadigan tezkor JSON; yoki butunlay HTML qaytaradigan an'anaviy Blade sayt.
π‘ Oltin qoida: agar JSON sizning serveringizdan boshqa birovga ketsa (mijoz, mobil, frontend) β Resource'siz qoldirmang. Bir kun maxfiy ustun qo'shganingizda u sizni qutqaradi.
16-bob mashqlari¶
Quyidagi mashqlarni o'z loyihangizda (blog yoki do'kon) bajaring. Yechimlarini o'zingiz yozing β har biri oldingisidan bir qadam murakkabroq.
- Marshrutdan modelni
return $user;qilib JSON ko'rinishida qaytaring va javobda qaysi maydonlar "ochiq" turganini ro'yxatlang; qaysi biri tashqariga chiqmasligi kerakligini belgilang. Usermodeliga$hiddenqo'shib,passwordvaremember_tokenni JSON'dan yashiring; keyinis_adminni ham qo'shing va o'zgarishni tekshiring.php artisan make:resource UserResourcebilan Resource yarating;toArrayda faqatid,name(niismdeb),emailni qaytaring.- Marshrutda
new UserResource($user)ishlatib, javobdatakalitining ichida kelishini tasdiqlang. created_atni->toDateString()bilan toza sanaga aylantiribqoshilganmaydon sifatida chiqaring; format farqini avvalgi xom JSON bilan solishtiring.UserResource::collection(User::all())bilan barcha foydalanuvchilar ro'yxatini qaytaring; har bir element bir xil shaklda kelishini tekshiring.php artisan make:resource UserCollection --collectionbilan alohida Collection klassi yarating va ungametaichidajami_soniqo'shing.User::all()o'rnigaUser::paginate(10)ishlatib, javobga avtomatik kelganlinksvametabloklarini ko'ring;meta.totalvameta.last_pageqiymatlarini izohlang.- Sahifa o'lchamini so'rovdan oling:
User::paginate($request->integer('per_page', 15)); keyin yuqori chegara (mas. 100) qo'yib,?per_page=99999so'rovini xavfsiz qiling. - Resource'da
emailmaydoniniwhen($request->user()?->is_admin, $this->email)bilan shartli qiling; admin va oddiy foydalanuvchi javoblarini solishtiring. when($shart, $qiymat)va$shart ? $qiymat : nullfarqini ko'rsatadigan ikki maydon yozing; JSON'da kalitning butunlay yo'qolishi vanullbo'lib qolishi farqini tushuntiring.- Og'ir hisob-kitobli maydonni
when(..., fn () => ...)closure bilan yozing va u faqat shart rost bo'lgandagina ishga tushishiga ishonch hosil qiling. PostResourcedamuallifninew UserResource($this->whenLoaded('user'))bilan qo'shing; controller'dawith('user')qilgan va qilmagan holatlar javobini solishtiring.- Controller'da
Post::all()qilib siklda muallifga murojaat qilib N+1 yarating; keyinwith('user')qo'shib so'rovlar soni kamayganini tekshiring (10-bobdagi usul bilan). withCount('comments')va Resource'dawhenCounted('comments')bilanizohlar_sonimaydonini qo'shing.CommentResourceyarating vaPostResourcedaizohlarniCommentResource::collection($this->whenLoaded('comments'))bilan nested qiling.- Bitta postni
Post::with(['user', 'comments'])->findOrFail($id)bilan oling va nested muallif + izohlar bo'lgan to'liq JSON'ni hosil qiling. AppServiceProvider::boot()daJsonResource::wrap('natija')qilib wrapper nomini o'zgartiring; keyinwithoutWrapping()ni sinab ko'ring va paginatsiyadadatabaribir saqlanishini kuzating.- Collection klassida
$this->collection->where('holat', 'faol')->pluck('name')->values()bilan faqat faollar ismidan alohida massiv yasang;values()ni olib tashlasangiz JSON'da nima o'zgarishini tekshiring. - Yakuniy mashq:
paginate, nestedwhenLoaded('user'),whenCounted('comments')va egasi uchun shartlitahrir_url(when) bo'lgan to'liqPostResource+ controller yozing; controller'dawith('user')->withCount('comments')borligiga va Resource ichida hech qanday yangi so'rov yo'qligiga ishonch hosil qiling.