Eloquent: منابع API
معرفی
هنگام ساخت یک API، ممکن است به یک لایه تبدیل نیاز داشته باشید که بین مدلهای Eloquent شما و پاسخهای JSON که در واقع به کاربران برنامه شما بازگردانده میشوند، قرار گیرد. کلاسهای منابع لاراول به شما این امکان را میدهد که مدلها و مجموعههای مدلهای خود را بهطور واضح و آسان به JSON تبدیل کنید.
تولید منابع
برای تولید یک کلاس منبع، می توانید از
make:resource
دستور Artisan استفاده کنید.
app/Http/Resources
به طور پیش فرض، منابع در فهرست برنامه شما
قرار می گیرند .
منابع
Illuminate\Http\Resources\Json\JsonResource
کلاس را گسترش می دهند:
php artisan make:resource User
مجموعه منابع
علاوه بر تولید منابعی که مدلهای فردی را تغییر میدهند، ممکن است منابعی تولید کنید که مسئول تغییر مجموعهای از مدلها هستند. این اجازه می دهد تا پاسخ شما شامل پیوندها و سایر اطلاعات متا باشد که به کل مجموعه ای از یک منبع معین مربوط می شود.
برای ایجاد مجموعه منابع،
--collection
هنگام ایجاد منبع باید از پرچم استفاده کنید.
یا گنجاندن کلمه
Collection
در نام منبع به لاراول نشان می دهد که باید یک منبع مجموعه ایجاد کند.
منابع مجموعه
Illuminate\Http\Resources\Json\ResourceCollection
کلاس را گسترش می دهند:
php artisan make:resource Users --collection php artisan make:resource UserCollection
نمای کلی مفهوم
این یک نمای کلی در سطح بالا از منابع و مجموعه های منابع است. شما بسیار تشویق می شوید که بخش های دیگر این مستندات را بخوانید تا درک عمیق تری از سفارشی سازی و قدرت ارائه شده توسط منابع به شما داشته باشید.
قبل از بررسی تمام گزینه های موجود در هنگام نوشتن منابع، اجازه دهید ابتدا
نگاهی سطح بالا به نحوه استفاده از منابع در لاراول بیندازیم.
یک کلاس منبع نشان دهنده یک مدل واحد است که باید به یک ساختار JSON تبدیل
شود.
به عنوان مثال، در اینجا یک
User
کلاس منبع ساده وجود دارد:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class User extends JsonResource{ /** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ]; }}
هر کلاس منبع
toArray
متدی را تعریف می کند که آرایه ای از ویژگی هایی را که باید هنگام ارسال
پاسخ به JSON تبدیل شوند، برمی گرداند.
توجه داشته باشید که ما می توانیم مستقیماً از
$this
متغیر به ویژگی های مدل دسترسی داشته باشیم.
این به این دلیل است که یک کلاس منبع برای دسترسی راحت، به طور خودکار ویژگی
و روش دسترسی به مدل اصلی را پروکسی می کند.
هنگامی که منبع تعریف شد، ممکن است از یک مسیر یا کنترل کننده بازگردانده
شود:
use App\Http\Resources\User as UserResource;use App\User; Route::get('/user', function () { return new UserResource(User::find(1));});
مجموعه منابع
اگر مجموعهای از منابع یا یک پاسخ صفحهبندی شده را برمیگردانید،
میتوانید
collection
هنگام ایجاد نمونه منبع در مسیر یا کنترلر خود از این روش استفاده کنید:
use App\Http\Resources\User as UserResource;use App\User; Route::get('/user', function () { return UserResource::collection(User::all());});
توجه داشته باشید که این اجازه نمی دهد هیچ گونه متا داده ای که ممکن است نیاز به بازگرداندن با مجموعه داشته باشد، اضافه شود. اگر میخواهید پاسخ مجموعه منابع را سفارشی کنید، میتوانید یک منبع اختصاصی برای نمایش مجموعه ایجاد کنید:
php artisan make:resource UserCollection
هنگامی که کلاس مجموعه منابع تولید شد، می توانید به راحتی هر متا داده ای را که باید در پاسخ گنجانده شود تعریف کنید:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\ResourceCollection; class UserCollection extends ResourceCollection{ /** * Transform the resource collection into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return [ 'data' => $this->collection, 'links' => [ 'self' => 'link-value', ], ]; }}
پس از تعریف مجموعه منابع شما، ممکن است از یک مسیر یا کنترلر برگردانده شود:
use App\Http\Resources\UserCollection;use App\User; Route::get('/users', function () { return new UserCollection(User::all());});
حفظ کلیدهای مجموعه
هنگام برگرداندن مجموعه منابع از مسیر، لاراول کلیدهای مجموعه را به گونه ای
تنظیم مجدد می کند که به ترتیب عددی ساده باشند.
با این حال، می توانید یک
preserveKeys
ویژگی به کلاس منبع خود اضافه کنید که نشان می دهد آیا کلیدهای مجموعه باید
حفظ شوند یا خیر:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class User extends JsonResource{ /** * Indicates if the resource's collection keys should be preserved. * * @var bool */ public $preserveKeys = true;}
وقتی
preserveKeys
ویژگی روی تنظیم شود
true
، کلیدهای مجموعه حفظ خواهند شد:
use App\Http\Resources\User as UserResource;use App\User; Route::get('/user', function () { return UserResource::collection(User::all()->keyBy->id);});
سفارشی کردن کلاس منبع زیربنایی
به طور معمول،
$this->collection
ویژگی یک مجموعه منبع به طور خودکار با نتیجه نگاشت هر آیتم از مجموعه به
کلاس منبع منفرد آن پر می شود.
کلاس منبع مفرد به عنوان نام کلاس مجموعه بدون
Collection
رشته انتهایی فرض می شود.
به عنوان مثال،
UserCollection
تلاش خواهد کرد تا نمونه های کاربر داده شده را در
User
منبع نگاشت کند.
برای سفارشی کردن این رفتار، ممکن است
$collects
ویژگی مجموعه منابع خود را لغو کنید:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\ResourceCollection; class UserCollection extends ResourceCollection{ /** * The resource that this resource collects. * * @var string */ public $collects = 'App\Http\Resources\Member';}
منابع نوشتاری
اگر نمای کلی مفهوم را نخوانده اید ، بسیار تشویق می شوید که قبل از ادامه این مستندات این کار را انجام دهید.
در اصل منابع ساده هستند.
آنها فقط باید یک مدل داده شده را به یک آرایه تبدیل کنند.
بنابراین، هر منبع حاوی
toArray
روشی است که ویژگیهای مدل شما را به یک آرایه مناسب API ترجمه میکند که
میتواند به کاربران شما بازگردانده شود:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class User extends JsonResource{ /** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ]; }}
هنگامی که یک منبع تعریف شد، ممکن است مستقیماً از یک مسیر یا کنترل کننده بازگردانده شود:
use App\Http\Resources\User as UserResource;use App\User; Route::get('/user', function () { return new UserResource(User::find(1));});
روابط
اگر میخواهید منابع مرتبط را در پاسخ خود بگنجانید، میتوانید آنها را به
آرایهای که توسط متدتان برگردانده شده است اضافه کنید
toArray
.
Post
در این مثال، از روش منبع
collection
برای اضافه کردن پستهای وبلاگ کاربر به پاسخ منبع
استفاده میکنیم :
/** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */public function toArray($request){ return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'posts' => PostResource::collection($this->posts), 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ];}
اگر میخواهید روابط را فقط زمانی وارد کنید که قبلاً بارگذاری شدهاند، اسناد مربوط به روابط شرطی را بررسی کنید .
مجموعه منابع
در حالی که منابع یک مدل واحد را به یک آرایه ترجمه می کنند، مجموعه های
منابع مجموعه ای از مدل ها را به یک آرایه ترجمه می کنند.
لزومی ندارد که یک کلاس مجموعه منابع برای هر یک از انواع مدل خود تعریف
کنید زیرا همه منابع روشی را
collection
برای تولید یک مجموعه منابع "ad-hoc" در جریان ارائه می کنند:
use App\Http\Resources\User as UserResource;use App\User; Route::get('/user', function () { return UserResource::collection(User::all());});
با این حال، اگر شما نیاز به سفارشی سازی متا داده های بازگشتی با مجموعه دارید، لازم است مجموعه منابع را تعریف کنید:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\ResourceCollection; class UserCollection extends ResourceCollection{ /** * Transform the resource collection into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return [ 'data' => $this->collection, 'links' => [ 'self' => 'link-value', ], ]; }}
مانند منابع منفرد، مجموعههای منابع ممکن است مستقیماً از مسیرها یا کنترلکنندهها برگردانده شوند:
use App\Http\Resources\UserCollection;use App\User; Route::get('/users', function () { return new UserCollection(User::all());});
بسته بندی داده ها
data
به طور پیش فرض، زمانی که پاسخ منبع به JSON تبدیل می شود،
بیرونی ترین منبع شما در یک کلید پیچیده می شود .
بنابراین، برای مثال، یک پاسخ مجموعه منابع معمولی مانند زیر است:
{ "data": [ { "id": 1, "name": "Eladio Schroeder Sr.", "email": "therese28@example.com", }, { "id": 2, "name": "Liliana Mayert", "email": "evandervort@example.com", } ]}
اگر می خواهید از یک کلید سفارشی به جای استفاده کنید
data
، می توانید یک
$wrap
ویژگی را در کلاس منبع تعریف کنید:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class User extends JsonResource{ /** * The "data" wrapper that should be applied. * * @var string */ public static $wrap = 'user';}
اگر میخواهید بستهبندی بیرونیترین منبع را غیرفعال کنید، میتوانید
withoutWrapping
از روش کلاس منبع پایه استفاده کنید.
به طور معمول، شما باید این روش را از
ارائه دهنده خدمات
AppServiceProvider
خود یا ارائه دهنده دیگری
که در هر درخواست برای برنامه شما بارگذاری می شود، فراخوانی کنید:
<?php namespace App\Providers; use Illuminate\Http\Resources\Json\JsonResource;use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider{ /** * Register any application services. * * @return void */ public function register() { // } /** * Bootstrap any application services. * * @return void */ public function boot() { JsonResource::withoutWrapping(); }}
این روش تنها بر بیرونی ترین پاسخ تأثیر می گذارد و کلیدهایی را که به صورت دستی به مجموعه منابع خود اضافه می کنید
withoutWrapping
حذف نمی کند .data
بسته بندی منابع تو در تو
شما آزادی کامل دارید تا تعیین کنید که چگونه روابط منابع شما پیچیده می
شود.
data
اگر میخواهید همه مجموعههای منابع ، بدون توجه به تودرتو،
در یک کلید پیچیده شوند ، باید برای هر منبع یک کلاس مجموعه منابع تعریف
کنید و مجموعه را در یک
data
کلید برگردانید.
ممکن است از خود بپرسید که آیا این باعث می شود که خارجی ترین منبع شما در
دو کلید پیچیده شود
data
.
نگران نباشید، لاراول هرگز اجازه نخواهد داد منابع شما به طور تصادفی دوبار
بسته شوند، بنابراین لازم نیست نگران سطح تودرتو مجموعه منابعی باشید که در حال تغییر آن هستید:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\ResourceCollection; class CommentsCollection extends ResourceCollection{ /** * Transform the resource collection into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return ['data' => $this->collection]; }}
بسته بندی و صفحه بندی داده ها
هنگام برگرداندن مجموعه های صفحه بندی شده در یک پاسخ منبع، لاراول داده های
منبع شما را در یک کلید قرار می دهد،
data
حتی اگر
withoutWrapping
متد فراخوانی شده باشد.
این به این دلیل است که پاسخ های صفحه بندی شده همیشه حاوی
meta
و
links
کلیدهایی با اطلاعات مربوط به وضعیت صفحه بندی کننده هستند:
{ "data": [ { "id": 1, "name": "Eladio Schroeder Sr.", "email": "therese28@example.com", }, { "id": 2, "name": "Liliana Mayert", "email": "evandervort@example.com", } ], "links":{ "first": "http://example.com/pagination?page=1", "last": "http://example.com/pagination?page=1", "prev": null, "next": null }, "meta":{ "current_page": 1, "from": 1, "last_page": 1, "path": "http://example.com/pagination", "per_page": 15, "to": 10, "total": 10 }}
صفحه بندی
شما همیشه می توانید یک نمونه صفحه بندی را به
collection
روش یک منبع یا به مجموعه منابع سفارشی ارسال کنید:
use App\Http\Resources\UserCollection;use App\User; Route::get('/users', function () { return new UserCollection(User::paginate());});
پاسخ های صفحه بندی شده همیشه حاوی
meta
و
links
کلیدهایی با اطلاعاتی در مورد وضعیت صفحه بندی کننده هستند:
{ "data": [ { "id": 1, "name": "Eladio Schroeder Sr.", "email": "therese28@example.com", }, { "id": 2, "name": "Liliana Mayert", "email": "evandervort@example.com", } ], "links":{ "first": "http://example.com/pagination?page=1", "last": "http://example.com/pagination?page=1", "prev": null, "next": null }, "meta":{ "current_page": 1, "from": 1, "last_page": 1, "path": "http://example.com/pagination", "per_page": 15, "to": 10, "total": 10 }}
صفات مشروط
گاهی اوقات ممکن است بخواهید فقط در صورتی که یک شرط مشخص شده باشد، یک
ویژگی را در پاسخ منبع بگنجانید.
به عنوان مثال، ممکن است بخواهید فقط در صورتی یک مقدار را وارد کنید که
کاربر فعلی یک "مدیر" باشد.
لاراول انواع مختلفی از روش های کمکی را برای کمک به شما در این شرایط ارائه
می دهد.
این
when
روش ممکن است برای اضافه کردن یک ویژگی به صورت مشروط به یک پاسخ منبع
استفاده شود:
/** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */public function toArray($request){ return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'secret' => $this->when(Auth::user()->isAdmin(), 'secret-value'), 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ];}
در این مثال،
secret
کلید تنها در صورتی در پاسخ منبع نهایی بازگردانده میشود که روش کاربر
احراز هویت شده
isAdmin
برگردد
true
.
اگر روش برگردد
false
،
secret
کلید قبل از اینکه به مشتری بازگردانده شود به طور کامل از پاسخ منبع حذف می
شود.
این
when
روش به شما این امکان را می دهد که منابع خود را بدون توسل به عبارات شرطی
در هنگام ساختن آرایه به وضوح تعریف کنید.
این
when
روش همچنین یک Close را به عنوان آرگومان دوم خود می پذیرد و به شما امکان
می دهد مقدار حاصل را فقط در صورتی محاسبه کنید که شرط داده شده باشد
true
:
'secret' => $this->when(Auth::user()->isAdmin(), function () { return 'secret-value';}),
ادغام ویژگی های شرطی
گاهی اوقات ممکن است چندین ویژگی داشته باشید که فقط باید بر اساس شرایط
یکسان در پاسخ منبع گنجانده شوند.
در این مورد، میتوانید از
mergeWhen
روشی برای گنجاندن ویژگیها در پاسخ استفاده کنید، تنها زمانی که شرط داده
شده
true
:
/** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */public function toArray($request){ return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, $this->mergeWhen(Auth::user()->isAdmin(), [ 'first-secret' => 'value', 'second-secret' => 'value', ]), 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ];}
مجدداً، اگر شرط داده شده باشد
false
، این ویژگی ها قبل از ارسال به مشتری، به طور کامل از پاسخ منبع حذف می
شوند.
این
mergeWhen
روش نباید در آرایه هایی که رشته ها و کلیدهای عددی را ترکیب می کنند استفاده شود. علاوه بر این، نباید در آرایه هایی با کلیدهای عددی که به ترتیب ترتیب داده نشده اند استفاده شود.
روابط مشروط
علاوه بر بارگذاری مشروط ویژگیها، میتوانید بهصورت مشروط روابطی را در پاسخهای منابع خود بر اساس اینکه آیا رابطه قبلاً در مدل بارگذاری شده است، اضافه کنید. این به کنترلر شما اجازه می دهد تصمیم بگیرد که کدام روابط باید در مدل بارگذاری شوند و منبع شما به راحتی می تواند آنها را فقط زمانی که واقعاً بارگذاری شده اند شامل شود.
در نهایت، این امر جلوگیری از مشکلات پرس و جو "N+1" در منابع شما را آسان
تر می کند.
این
whenLoaded
روش ممکن است برای بارگذاری مشروط یک رابطه استفاده شود.
برای جلوگیری از بارگذاری بی مورد روابط، این روش نام رابطه را به جای خود
رابطه می پذیرد:
/** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */public function toArray($request){ return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'posts' => PostResource::collection($this->whenLoaded('posts')), 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ];}
در این مثال، اگر رابطه بارگذاری نشده باشد،
posts
کلید قبل از ارسال به مشتری، به طور کامل از پاسخ منبع حذف می شود.
اطلاعات محوری شرطی
علاوه بر گنجاندن مشروط اطلاعات رابطه در پاسخ های منابع خود، می توانید به
صورت مشروط داده هایی را از جداول میانی روابط چند به چند با استفاده از این
whenPivotLoaded
روش درج کنید.
این
whenPivotLoaded
متد نام جدول محوری را به عنوان اولین آرگومان خود می پذیرد.
آرگومان دوم باید یک Closure باشد که اگر اطلاعات محوری در مدل موجود باشد،
مقداری را که باید برگردانده شود، تعریف میکند:
/** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */public function toArray($request){ return [ 'id' => $this->id, 'name' => $this->name, 'expires_at' => $this->whenPivotLoaded('role_user', function () { return $this->pivot->expires_at; }), ];}
اگر جدول میانی شما از ابزاری غیر از اکسسوری استفاده می کند
pivot
، می توانید از
whenPivotLoadedAs
روش زیر استفاده کنید:
/** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */public function toArray($request){ return [ 'id' => $this->id, 'name' => $this->name, 'expires_at' => $this->whenPivotLoadedAs('subscription', 'role_user', function () { return $this->subscription->expires_at; }), ];}
افزودن متا دیتا
برخی از استانداردهای JSON API نیاز به افزودن متا داده به پاسخ های منابع و
مجموعه منابع شما دارند.
این اغلب شامل مواردی مانند
links
منبع یا منابع مرتبط یا متا داده در مورد خود منبع است.
اگر نیاز به بازگرداندن متا داده های اضافی در مورد یک منبع دارید، آن را در
toArray
روش خود قرار دهید.
به عنوان مثال، ممکن است
link
هنگام تبدیل یک مجموعه منابع، اطلاعاتی را اضافه کنید:
/** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */public function toArray($request){ return [ 'data' => $this->collection, 'links' => [ 'self' => 'link-value', ], ];}
هنگام بازگرداندن متا داده های اضافی از منابع خود، هرگز نباید نگران نادیده
گرفتن تصادفی کلیدها
links
یا
meta
کلیدهایی باشید که به طور خودکار توسط لاراول هنگام بازگرداندن پاسخ های
صفحه بندی شده اضافه می شوند.
هر اضافی
links
که تعریف می کنید با پیوندهای ارائه شده توسط صفحه نویس ادغام می شود.
داده های متا سطح بالا
گاهی اوقات ممکن است بخواهید فقط داده های متا خاصی را با یک پاسخ منبع وارد
کنید در صورتی که منبع بیرونی ترین منبعی باشد که برگردانده می شود.
به طور معمول، این شامل اطلاعات متا در مورد پاسخ به عنوان یک کل است.
برای تعریف این متا داده، یک
with
متد به کلاس منبع خود اضافه کنید.
این روش باید آرایهای از متا داده را برگرداند تا تنها زمانی که منبع
بیرونیترین منبعی است که ارائه میشود، با پاسخ منبع اضافه شود:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\ResourceCollection; class UserCollection extends ResourceCollection{ /** * Transform the resource collection into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return parent::toArray($request); } /** * Get additional data that should be returned with the resource array. * * @param \Illuminate\Http\Request $request * @return array */ public function with($request) { return [ 'meta' => [ 'key' => 'value', ], ]; }}
افزودن متا داده هنگام ساخت منابع
همچنین میتوانید هنگام ساختن نمونههای منبع در مسیر یا کنترلر خود،
دادههای سطح بالا را اضافه کنید.
روشی
additional
که در همه منابع موجود است، آرایه ای از داده ها را می پذیرد که باید به
پاسخ منبع اضافه شود:
return (new UserCollection(User::all()->load('roles'))) ->additional(['meta' => [ 'key' => 'value', ]]);
پاسخ های منابع
همانطور که قبلاً خواندید، ممکن است منابع مستقیماً از مسیرها و کنترلرها بازگردانده شوند:
use App\Http\Resources\User as UserResource;use App\User; Route::get('/user', function () { return new UserResource(User::find(1));});
با این حال، گاهی اوقات ممکن است لازم باشد پاسخ HTTP خروجی را قبل از ارسال
به مشتری سفارشی کنید.
دو راه برای انجام این کار وجود دارد.
ابتدا، می توانید
response
روش را به منبع زنجیره بزنید.
این روش نمونه ای را برمی گرداند
Illuminate\Http\JsonResponse
و به شما امکان کنترل کامل سرصفحه های پاسخ را می دهد:
use App\Http\Resources\User as UserResource;use App\User; Route::get('/user', function () { return (new UserResource(User::find(1))) ->response() ->header('X-Value', 'True');});
از طرف دیگر، می توانید یک
withResponse
روش را در خود منبع تعریف کنید.
این متد زمانی فراخوانی می شود که منبع به عنوان بیرونی ترین منبع در یک
پاسخ بازگردانده شود:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class User extends JsonResource{ /** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return [ 'id' => $this->id, ]; } /** * Customize the outgoing response for the resource. * * @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Response $response * @return void */ public function withResponse($request, $response) { $response->header('X-Value', 'True'); }}