تعداد بازدید: 3653

Eloquent API Resources

برای انتقال اطلاعات در API از مسیر Eloquent Model به JSON Response ما لایه های انتقال اطلاعاتی نظیر Resources , ResourceCollection داریم که فیلتر هایی را روی مدل ارسال شده از سمت سرور به سمت کلاینت اعمال می کند.

API Resource

به صورت پیش فرض زمانی که اطلاعات را به سمت کلاینت می فرستید اطلاعات شما به صورت کامل ارسال می گردد. این مورد هم حجم درخواست را بالا می برد و هم گاها مشکل امنیتی دارد. به همین منظور با استفاده از Resource ها ما اطلاعات را از روی قالب مورد دلخواه خودمان ارسال می کنیم.
Resource ها به عنوان ورودی مدل را می گیرند. (به صورت محاوره ای و نادقیق ساده شده مدل می باشند) پس نام گذاری آن ها از قالب مدل پیروی می کند. مثلا به ازای مدل User ما Resrouce با نام User ایجاد می کنیم.
برای ساخت Resource از دستور زیر استفاده می کنیم:

php artisan make:resource User

پس از اجرای دستور بالا ما در مسیر app/Http/Resources فایل User.php را که همان Resrouce ماست را مشاهده می کنیم.

namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class User extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name
        ];
    }
}

لیست Resource , ResourceCollection ها در همین مسیر می باشد.

ساختار resource بسیار ساده می باشد. در سازنده خود یک مدل دریافت می کند و به عنوان خروجی با استفاده از متد toArray خروجی مورد نظر را از روی قالبی که برایش تعریف کرده ایم به ما بر می گرداند.

در این متد با استفاده از شئ $this ما به تمامی Model Attributes دسترسی داریم. با توجه به Resource که ساخته ایم و متغیر fillable موجود در متد ما می توانیم از آن ها در Resource استفاده کنیم.

مثلا ما قالب کاربر را در مثال بالا در متد toArray تعریف کردیم. به شکلی که تنها id , name این کاربر ارسال گردد. این متد Model Attribute ها را به صورت یک قالب JSON که ما آن را تعریف کرده ایم تبدیل و بر می گرداند.

Resource ها از جایی که instansiate شده باشند می آیند . مثلا controller , route .

namespace App\Http\Controllers\Api;
use App\User;
use App\Http\Controllers\Controller;
use App\Http\Resources\Book as BookResources;

class UserController extends Controller
{
    public function show(int $id)
    {
        return new UserResources(User::findOrFail($id));
    }
}

در کد بالا ما از UserResource برای ارسال قالب پاسخ JSON Response استفاده کرده ایم. در تعریف دیگر Resource ها یکی ابزاری برای ترجمه و تبدیل Model به JSON Response می باشند.

ResourceCollection

ما زمانی که در پاسخ قرار است که یک شئ را برگردانیم (به طور مثال در متد show) باید از Resource ها استفاده کنیم . اما اگر قرار باشد collection از اشیا را برگردانیم (به طور مثال متد index) باید از ResourceCollection استفاده کنیم. برای این کار می توانیم از متد ایستا در Resource به نام collection استفاده کنیم.این متد collection از Resource که ایجاد کرده ایم را برمی گرداند.

public function index()
{
    return UserResources::collection(User::all());
}

خروجی که به سمت کلاینت در صورت اجرای کد بالا ارسال می گردد یک شئ JSON می باشد که مقداری با نام data دارد و محتوی این کلید data همان داده هایی است که ما قالبشان را در متد toArray ارسال کردیم.

{
    "data" : [
        {
            "id":1,
            "name":"Abolfazl Sabagh"
        },
        {
            "id":2,
            "name":"Rostam Zall"
        }
    ]
}

شما در کنار قالبی که مشاهده می کنید می توانید meta data هم ارسال کنید . برای این کار باید از ResourceCollection ها استفاده کنید.

با استفاه از دستور زیر می توانید مثلا یک ResourceCollection برای User بسازید.

php artisan make:resource UserCollection

در زمان ساخت ResourceCollection باید از قوانین نامگذاری به درستی استفاده کنید. به طوری که نام Resource و عبارت Collection را به ازای آن بیاورید. به طور مثال به ازای Resource = User باید نام گذاری کنید UserCollection . در غیر این صورت باید --collection را به همراه دستور خود بیاورید.

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class UserCollection extends ResourceCollection
{
    public function toArray($request)
    {
        return [
            'data' => $this->collection,
            'links' => [
                'self' => 'link-value',
            ],
        ];
    }
}

ساختار ResourceCollection هم شبیه به Resource می باشد. $this->collection یعنی collection را از روی Resource ارسال کن و همچنین یک سری داده دیگر مثل links را نیز به همراه مقدار آن بفرست.

برای استفاده از ResourceCollection ما باید Resource را داشته باشیم. مثلا به ازای UserCollection باید User را داشته باشیم.

ResourceCollection ها نیز ممکن است بر حسب نوع استفاده از route یا controller برگرفته باشند.

use App\User;
use App\Http\Resources\UserCollection;

Route::get('/users', function () {
    return new UserCollection(User::all());
});

در مثال قبل ما برای User Resource یک قالب تعیین کردیم. این Resource در زمان استفاده به تنهایی UserResource و برای ساخت collection از دو روش UserResource::collection یا UserCollection استفاده می کرد.

Relationships

اگر یک Resouce بزرگ داریم که خود از Resource های دیگر استفاده می کند باید در زمان تعریف قالب در متد toArray به ازای روابط آن از Resource های معادل استفاده کنیم. به طور مثال ما Book را داریم. در کنار آن Categories , User , Author را داریم.

در ابتدا باید Resource های مرتبط را تعریف کرده باشیم. در مثال ما Categories , User , Author به ازای ‌Book می باشد. پس از آن در BookResource با توجه به نوع روابط آن ها (one to one , one to many , many to many) باید از Resource های دیگر (Categories , User , Author) در Resource اصلی (Book) استفاده کنیم.

namespace App\Http\Resources;
use App\Http\Resources\Category as CategoryResource;
use App\Http\Resources\Author as AuthorResource;
use App\Http\Resources\User as UserResource;
use Illuminate\Http\Resources\Json\JsonResource;
class Book extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'pages' => $this->pages,
            'isbn' => $this->isbn,
            'price' => $this->price,
            'published_at' => $this->published_at,
            'user' => new UserResource($this->user),
            'categories' => CategoryResource::collection($this->categories),
            'authors' => AuthorResource::collection($this->authors)
        ];
    }
}

ورودی Resource مقدار Attibute Model می باشد. همان طور که در زمان تعیین روابط در مدل ها گفته شد که به ازای هر متد ساخته شده یک attribute داریم که مقدار collection یا single model را از مدل دیگر بر می گرداند در متد toArray نیز ما از این attribute ها استفاده می کنیم.

اگر به ازای یک مدل اصلی چند مدل دیگر داشته باشیم باید از ResourceCollection آن استفاده کنیم (مثل Book , Categories) و اگر به ازای یک مدل اصلی یک مدل دیگر داشته باشیم باید از Resource استفاده کنیم (مثل Book , User)

Conditional Attributes

مفهومی conditional attributes است که در Relationship استفاده می شود. مثلا اگر مقداری به ازای Model دیگری مثل Categories داشته باشیم در لیست خروجی می آورد و در غیر این صورت اشاره ای به آن در خروجی نمی کند.

متد whenLoaded این امکان را برای ما فراهم می کند. همان مثال بالا را این بار با اجرای تکنیک Conditional Attributes اجرا می کنیم.

public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'pages' => $this->pages,
        'isbn' => $this->isbn,
        'price' => $this->price,
        'published_at' => $this->published_at,
        'user' => new UserResource($this->user),
        'categories' => CategoryResource::collection($this->whenLoaded('categories')),
        'authors' => AuthorResource::collection($this->whenLoaded('authors'))
    ];
}

شروط بسیاری می توان برای خروجی تعیین کرد مثلا اگر کاربر در سطح admin بود اطلاعات برای او بازگردد که به ازای هر شرط یک متد منحصر به فرد خودش را خواهیم داشت.

اشتراک گذاری :

مدیر وب سایت گنوتک . برنامه نویسی رو با زبان C در هفده سالگی شروع کردم . در حال حاضر به برنامه نویسی php برپایه معماری MVC , HMVC و همچنین سیستم مدیریت محتوای WordPress و فریم ورک محبوب لاراول علاقه مند هستم و دوست دارم اطلاعاتم رو با شما به اشتراک بگذارم.

۰ دیدگاه برای Eloquent API Resources

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *