لایه ترنسفورمرها با league/fractal
در این سند
مقدمه
در توسعه Laravel، لایه ترنسفورمرها نقش مهمی در شکلدهی داده برای پاسخهای API ایفا میکند. پکیج league/fractal به طور گستردهای برای این منظور پذیرفته شده است و مجموعه ابزاری انعطافپذیر و قدرتمند برای تبدیل دادههای خام به یک قالب سازگار و ساختاریافته مناسب برای مصرفکنندگان API ارائه میدهد.
ترنسفورمرها کلاسهایی هستند که ساختارهای داده داخلی شما را به پاسخهای API استاندارد تبدیل میکنند و سازگاری و قالببندی مناسب را در سراسر API شما تضمین میکنند.
چرا ترنسفورمرها؟
ترنسفورمرها به جداسازی فرآیند بازیابی داده از قالببندی پاسخ API کمک میکنند. با استفاده از ترنسفورمرها، میتوانید اطمینان حاصل کنید که دادههای برگردانده شده توسط API شما به روشی استاندارد ارائه میشوند، که سازگاری را ترویج میکند و نگهداری کد شما را سادهتر میسازد.
نصب league/fractal
برای شروع کار با league/fractal، باید پکیج را با استفاده از Composer نصب کنید:
composer require league/fractal
پس از نصب، میتوانید ترنسفورمرها را برای تعریف نحوه نمایش دادههای خود در پاسخهای API ایجاد کنید.
راهنمای پیادهسازی
- ایجاد ترنسفورمرها
- استفاده از ترنسفورمرها
- استفاده از Helper فرکتال
- شامل کردن روابط
ایجاد ترنسفورمرها
ترنسفورمرها کلاسهایی هستند که مسئول تبدیل دادههای خام به یک ساختار خاص برای پاسخهای API هستند. در Laravel، ترنسفورمرها اغلب از کلاس League\Fractal\TransformerAbstract ارثبری میکنند.
ترنسفورمر پایه
<?php
namespace App\Transformers;
use App\Models\User;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
public function transform(User $user)
{
return [
'id' => (int) $user->id,
'name' => $user->name,
'email' => $user->email,
'created_at' => $user->created_at->toIso8601String(),
'updated_at' => $user->updated_at->toIso8601String(),
];
}
}
ترنسفورمر با روابط
<?php
namespace App\Transformers;
use App\Models\Post;
use League\Fractal\TransformerAbstract;
class PostTransformer extends TransformerAbstract
{
protected $availableIncludes = [
'author', 'comments'
];
public function transform(Post $post)
{
return [
'id' => (int) $post->id,
'title' => $post->title,
'content' => $post->content,
'slug' => $post->slug,
'published' => (bool) $post->published,
'created_at' => $post->created_at->toIso8601String(),
'updated_at' => $post->updated_at->toIso8601String(),
];
}
public function includeAuthor(Post $post)
{
return $this->item($post->author, new UserTransformer());
}
public function includeComments(Post $post)
{
return $this->collection($post->comments, new CommentTransformer());
}
}
استفاده از ترنسفورمرها در کنترلرها
پس از ایجاد ترنسفورمرها، میتوانید از آنها در کنترلرهای خود برای قالببندی داده قبل از ارسال آن به عنوان پاسخ API استفاده کنید.
استفاده با آیتم تکی
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Transformers\UserTransformer;
use League\Fractal\Resource\Item;
use League\Fractal\Manager;
class UserController extends Controller
{
public function show($id)
{
$user = User::findOrFail($id);
$transformer = new UserTransformer();
$resource = new Item($user, $transformer);
$fractal = new Manager();
$data = $fractal->createData($resource)->toArray();
return response()->json($data);
}
}
استفاده با مجموعهها
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Transformers\UserTransformer;
use League\Fractal\Resource\Collection;
use League\Fractal\Manager;
class UserController extends Controller
{
public function index()
{
$users = User::all();
$transformer = new UserTransformer();
$resource = new Collection($users, $transformer);
$fractal = new Manager();
$data = $fractal->createData($resource)->toArray();
return response()->json($data);
}
}
استفاده از Helper فرکتال
Laravel روش مناسبی برای استفاده از Fractal با یک تابع کمکی یا یک نما ارائه میدهد.
نصب Helper
composer require spatie/laravel-fractal
انتشار پیکربندی
php artisan vendor:publish --provider="Spatie\Fractal\FractalServiceProvider"
استفاده از Helper در کنترلرها
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Transformers\UserTransformer;
class UserController extends Controller
{
public function show($id)
{
$user = User::findOrFail($id);
return fractal()
->item($user)
->transformWith(new UserTransformer())
->toArray();
}
public function index()
{
$users = User::all();
return fractal()
->collection($users)
->transformWith(new UserTransformer())
->toArray();
}
}
شامل کردن روابط
Fractal به شما امکان میدهد منابع مرتبط را در پاسخهای API خود شامل کنید.
کنترلر با Includes
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use App\Transformers\PostTransformer;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function show(Request $request, $id)
{
$post = Post::findOrFail($id);
// دریافت includes از درخواست
$includes = $request->get('include', '');
return fractal()
->item($post)
->transformWith(new PostTransformer())
->parseIncludes($includes)
->toArray();
}
}
مثال درخواست API با Includes
GET /api/posts/1?include=author,comments
این روابط نویسنده و نظرات را در پاسخ شامل خواهد کرد.
ویژگیهای پیشرفته
صفحهبندی
Fractal پشتیبانی از نتایج صفحهبندی شده را ارائه میدهد:
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use App\Transformers\PostTransformer;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index(Request $request)
{
$paginator = Post::paginate(10);
$posts = $paginator->getCollection();
$response = fractal()
->collection($posts)
->transformWith(new PostTransformer())
->paginateWith(new \League\Fractal\Pagination\IlluminatePaginatorAdapter($paginator))
->toArray();
return response()->json($response);
}
}
سریالایزرهای سفارشی
Fractal به شما امکان میدهد ساختار پاسخهای API خود را با استفاده از سریالایزرها سفارشی کنید:
<?php
namespace App\Serializers;
use League\Fractal\Serializer\ArraySerializer;
class CustomSerializer extends ArraySerializer
{
public function collection($resourceKey, array $data)
{
return $resourceKey ? [$resourceKey => $data] : $data;
}
public function item($resourceKey, array $data)
{
return $resourceKey ? [$resourceKey => $data] : $data;
}
}
return fractal()
->item($user)
->transformWith(new UserTransformer())
->serializeWith(new CustomSerializer())
->toArray();
ویژگیهای شرطی
میتوانید ویژگیها را به صورت شرطی در ترنسفورمرهای خود شامل کنید:
<?php
namespace App\Transformers;
use App\Models\User;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
public function transform(User $user)
{
$data = [
'id' => (int) $user->id,
'name' => $user->name,
'email' => $user->email,
'created_at' => $user->created_at->toIso8601String(),
];
// فقط برای کاربران مدیر وضعیت مدیر را شامل کنید
if ($user->isAdmin()) {
$data['is_admin'] = true;
}
// فقط اگر کاربر احراز هویت شده در حال مشاهده پروفایل خود است، دادههای خصوصی را شامل کنید
if (auth()->id() === $user->id) {
$data['phone'] = $user->phone;
$data['address'] = $user->address;
}
return $data;
}
}
بهترین شیوهها
- سازگاری
- عملکرد
- نسخهبندی API
حفظ سازگاری
- از قالب یکسان برای تمام پاسخهای API استفاده کنید
- قالبهای تاریخ را سازگار نگه دارید (ISO 8601 توصیه میشود)
- از قراردادهای نامگذاری سازگار استفاده کنید (camelCase یا snake_case)
- همیشه IDها و مقادیر بولی را به انواع مناسب خود تبدیل کنید
return [
'id' => (int) $model->id,
'is_active' => (bool) $model->is_active,
'created_at' => $model->created_at->toIso8601String(),
];
بهینهسازی عملکرد
- از بارگذاری eager برای جلوگیری از مشکلات پرسوجوی N+1 استفاده کنید
- برای منابع با دسترسی مکرر، کش کردن دادههای تبدیل شده را در نظر بگیرید
- به includeهای عمیقاً تو در تو توجه کنید
$posts = Post::with(['author', 'comments'])->paginate(10);
نسخهبندی ترنسفورمرهای خود
- ترنسفورمرهای جداگانه برای نسخههای مختلف API ایجاد کنید
- از فضاهای نام برای سازماندهی ترنسفورمرها بر اساس نسخه استفاده کنید
// app/Transformers/V1/UserTransformer.php
namespace App\Transformers\V1;
// app/Transformers/V2/UserTransformer.php
namespace App\Transformers\V2;
نتیجهگیری
پیادهسازی لایه ترنسفورمرها با استفاده از league/fractal در Laravel به یک کد تمیزتر و قابل نگهداریتر کمک میکند. با جداسازی دغدغههای تبدیل داده از بقیه منطق برنامه خود، اطمینان حاصل میکنید که پاسخهای API شما سازگار و به راحتی قابل انطباق با تغییرات آینده هستند.
به یاد داشته باشید که ویژگیهای پیشرفته league/fractal را برای مدیریت سناریوهای پیچیدهتر در توسعه API خود، مانند includeها، صفحهبندی و سریالایزرهای سفارشی بررسی کنید.