Laravel بر اساس الگوی ساختاری MVC طراحی شده و کنترلر یکی از سه جزء این الگو است که مسئول اجرای منطق ها و سیاست های نرم افزار، ارتباط با دیتابیس(model) و نشان دادن نتایج(view) و اطلاعات مورد نظر به کاربر است. درواقع می توانیم درون روت ها، جای تعریف کردن تمام منطق برنامه با closure، از کنترلر استفاده کنیم و functionality هایی که از یک گروه اند را درون یک کنترلر قرار دهیم.
برای ساختن یک کنترلر باید دستور artisan زیر را اجرا کنیم:
php artisan make:controller UserController
داخل کنترلر برای انجام دادن هر کار یک تابع public تعریف می کنیم:
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\View\View;
class UserController extends Controller
{
public function index(): View
{
return view('users', [
'users' => User::get()
]);
}
}
سپس با استفاده از روت ها، درخواست مربوطه را به این کنترلر ارسال می کنیم:
use App\Http\Controllers\UserController;
Route::get('/users', [UserController::class, 'index']);
Resource Contollers
اگر هر مدل eloquent را به عنوان یک منبع یا resource در نظر بگیریم یک سری اعمال تکراری وجود دارد که معمولا روی این منابع انجام می دهیم؛ مثل ساختن، بروزرسانی یا پاک کردن.
با زدن دستور زیر لاراول یک کنترلر برای ما ایجاد می کند که هفت متد معروف درون آن وجود دارد:
php artisan make:controller PostController --resource
این هفت متد معروف برای انجام هفت action پرکاربرد بر روی منابع است. این هفت متد و کاربردشان پایین تر آمده است.
public function index()
{
//
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show(string $id)
{
//
}
public function edit(string $id)
{
//
}
public function update(Request $request, string $id)
{
//
}
public function destroy(string $id)
{
//
}
index: نشان دادن محتوای جدول به صورت لیست
Create: نمایش فرم برای ایجاد یک رکورد جدید
Store: دریافت فرم submit شده و ایجاد یک رکورد جدید
Show: نشان دادن اطلاعات یک رکورد مشخص
Edit: نمایش فرم ویرایش اطلاعات یک رکورد
Update: دریافت فرم submit شده و بروزرسانی یک رکورد
Destroy: پاک کردن یک رکورد مشخص
هرکدام از این متد ها از یک فعل یا متد http استفاده می کند که بسته به آن فعل، متد Route را مشخص می کنیم. متد های Route هم نام با افعال http اند. دقت کنید که انتخاب نام های بالا اختیاری است، این نام ها فقط یک سری naming convention برای برنامه نویسان لاراول است که البته استفاده از آنها به خوانا بودن کد ما کمک زیادی می کند.
به صورت زیر برای resource یک روت تعریف می کنیم:
use App\Http\Controllers\PostController;
Route::resource('posts', PostController::class);
همچنین می توانیم چند resource را همزمان تعریف کنیم:
Route::resources([
'users' => UserController::class,
'posts' => PostController::class,
]);
همین یک خط کد برای تک تک متد های resource controller، روت تولید می کند.
اگر بخواهیم خودمان یک روت به صورت دستی به کنترلر اضافه کنیم، باید آن ها را قبل از متد resource تعریف کنیم در غیر این صورت ممکن است روت های resource، بر روتی که تعریف کردیم تقدم پیدا کنند:
use App\Http\Controller\PostController;
Route::get('/posts/topFive', [PostController::class, 'topFive']);
Route::resource('posts', PostController::class);
لاراول بر اساس نامی که برای کنترلر گذاشتیم، مدل را پیدا می کند مثلا برای PostController مدل Post را در نظر می گیرد اما خودمان هم می توانیم زمان ساخت کنترلر، مدل منبع را مشخص کنیم:
php artisan make:controller PostController --model=Post --resource
API resource
از آنجایی که در نوشتن API ها به روت هایی که یک فرم html را برمی گردانند نیازی نداریم دستوری دیگری برای تعریف آن ها وجود دارد:
use App\Http\Controllers\PostController;
Route::apiResource('posts', PostController::class);
همچنین می توانیم از دستور artisan زیر برای ساختن api resource ها استفاده کنیم:
php artisan make:controller PostController --api
Nested Resources
منابع قابلیت nest شدن هم دارند، به عنوان مثال منبعی به نام post می تواند چندین کامنت داشته باشد که به post مربوط می شوند.
use App\Http\Controllers\PostCommentController;
Route::resource('posts.comments', PostCommentController::class);
کد بالا یک منبع nest شده را نشان می دهد که از URI زیر قابل دسترسی است:
/posts/{post}/comments/{comment}
Singleton Resource Controllers
اگر با الگو های طراحی کار کرده باشید حتما کلمه singleton را شنیده اید. هر وقت بخواهیم از منبع مورد نظر ما فقط و فقط یک نمونه درون برنامه وجود داشته باشد. می توانیم از کنترلر های سینگلتون استفاده کنیم.
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;
Route::singleton('profile', ProfileController::class);
در حالت عادی برای منابع سینگلتون فقط سه روت تعریف می شود درواقع روت های مربوط به ساختن و پاک کردن را برای منابع سینگلتون تعریف نمی کنیم. همچنین از آنجایی که فقط یک مثال از آنها وجود دارد متغیر identifier دریافت نمی کنند.
منابع سینگلتون می توانند با کنترلر های عادی nest بشوند.
Route::singleton('posts.thumbnail', ThumbnailController::class);
در کد بالا منبع posts تمام روت های یک کنترلر عادی را دارد، ولی منبع thumbnail یک منبع سینگلتون است که فقط سه روت دارد.
برای اینکه منبع سینگلتون ما قابلیت ساختن و پاک کردن هم داشته باشد، باید متد ()creatable را به آخر روت زنجیر کنیم.
Route::singleton(...)->creatable();
در این صورت شش متد برای کنترلر ایجاد می شود. دقت کنید که همچنان متد index تعریف نشده، چون منبع سینگلتون فقط یک رکورد دارد و متد index برای نشان دادن لیست رکورد ها است پس در اینجا کاربردی ندارد.
برای اضافه کرد متد delete به تنهایی، باید متد ()destroyable را زنجیر کرد.
Route::singleton(...)->destroyable();
می توان منبع سینگلتون را برای API هم تعریف کرد.
Route::apiSingleton('profile', ProfileController::class);
نیازی به گفتن نیست که متد های ()creatable و ()destroyable را می توان روی سینگلتون های API هم استفاده کرد.
در طول مقاله از Route زیاد نام بردیم، برای آشنایی بیشتر با آن می توانید به مقاله "Routing در لاراول" مراجعه کنید.
در ادامه برای اطلاعات بیشتر درباره Controller ها توصیه می کنم به داکیومنت لاراول مراجعه کنید.