تخطَّ إلى المحتوى

المتحكمات في Laravel: Controllers

الدرس 3 من 11 · Laravel

في الدرس السابق كتبت الكود داخل المسارات مباشرة. هذا جميل لمسار أو اثنين، لكن تخيّل تطبيقاً فيه خمسون صفحة، وكل صفحة فيها منطق طويل: سيتحول routes/web.php إلى ملف ضخم مزدحم. المتحكمات (Controllers) تحل هذه المشكلة بتنظيم الكود في كلاسات مرتبة. وهي حرف C في نمط MVC الذي تعرفت عليه في الدرس الأول.

المتحكم كلاس فيه مجموعة دوال (تسمى Actions)، كل دالة مسؤولة عن صفحة أو عملية واحدة. وعادة نجمع العمليات المتعلقة بنفس الشيء في متحكم واحد: كل ما يخص المقالات في PostController، وكل ما يخص المستخدمين في UserController.

تذكّر تشبيه المطعم: المتحكم هو النادل. يستقبل طلبك (Request)، ويذهب للمطبخ (Model) ليجلب الطعام، ثم يقدمه لك في طبق جميل (View). وكل نادل مسؤول عن مجموعة طاولات محددة.

لا تكتب الملف بيدك، بل اطلبه من Artisan:

نافذة طرفيّة
php artisan make:controller PostController

سينشئ الملف app/Http/Controllers/PostController.php:

app/Http/Controllers/PostController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PostController extends Controller
{
//
}
  • namespace: مكان الكلاس في المشروع، مثل عنوان البيت.
  • extends Controller: يرث من المتحكم الأساسي في Laravel.
  • اسم المتحكم بصيغة PascalCase وينتهي بكلمة Controller، وهذا عُرف يلتزم به كل مطوري Laravel.

نضيف دالة تعرض قائمة المقالات:

class PostController extends Controller
{
public function index()
{
return 'هنا ستظهر كل المقالات';
}
}

ثم نربطها بمسار في routes/web.php:

routes/web.php
<?php
use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');

بدلاً من الدالة المجهولة، نعطي المسار مصفوفة فيها اسم الكلاس واسم الدالة. اقرأها: «عندما يطلب الزائر /posts، نفّذ الدالة index في PostController». ولا تنسَ سطر use في الأعلى ليعرف الملف مكان الكلاس.

استقبال معاملات الرابط

Section titled “استقبال معاملات الرابط”

معامل المسار يصل إلى دالة المتحكم تماماً كما كان يصل للدالة المجهولة:

routes/web.php
Route::get('/posts/{id}', [PostController::class, 'show'])->name('posts.show');
public function show(int $id)
{
return "المقال رقم $id";
}

اسم المتغير في الدالة يطابق اسم المعامل في المسار {id}.

لقراءة بيانات نموذج أو رابط، أضف معاملاً من نوع Request، وسيمرره Laravel تلقائياً:

use Illuminate\Http\Request;
public function store(Request $request)
{
$title = $request->input('title');
// ...
}

$request->input('title') تقرأ الحقل title سواء أُرسل بـ GET أو POST. هذا أنظف وأأمن من التعامل مع $_POST مباشرة كما كنت تفعل في PHP العادية. وهذه الميزة التي «يمرر فيها Laravel ما تحتاجه تلقائياً» تسمى حقن الاعتماديات (Dependency Injection)، وستراها كثيراً.

في التطبيق الحقيقي، المتحكم لا يُرجع نصاً، بل يجهّز البيانات ويرسلها إلى View:

public function index()
{
$posts = ['أول مقال', 'مقال ثانٍ'];
return view('posts.index', ['posts' => $posts]);
}

الدالة view('posts.index') تعرض الملف resources/views/posts/index.blade.php، والمصفوفة الثانية فيها البيانات التي ستصل للصفحة. ويمكن كتابة نفس الشيء باختصار بالدالة compact:

return view('posts.show', compact('post'));
// تساوي: ['post' => $post]

ستتعلم كتابة ملفات الـ View في الدرس القادم، وجلب البيانات الحقيقية من قاعدة البيانات في الدرس الذي بعده.

متحكمات الموارد (Resource Controllers)

Section titled “متحكمات الموارد (Resource Controllers)”

أغلب أجزاء التطبيقات تحتاج نفس العمليات: عرض القائمة، وعرض عنصر واحد، والإنشاء، والتعديل، والحذف. هذه تسمى عمليات CRUD (Create, Read, Update, Delete). Laravel ينشئ لك متحكماً جاهزاً بها كلها:

نافذة طرفيّة
php artisan make:controller CourseController --resource

سيأتي المتحكم بسبع دوال فارغة جاهزة:

الدالة وظيفتها
index عرض كل العناصر
create عرض نموذج إضافة عنصر
store حفظ العنصر الجديد
show عرض عنصر واحد
edit عرض نموذج التعديل
update حفظ التعديل
destroy حذف العنصر

وتربطها كلها بسطر واحد في المسارات:

Route::resource('courses', CourseController::class);

هذا السطر ينشئ سبعة مسارات بأسمائها، مثل courses.index و courses.store. شغّل php artisan route:list لتراها.

  1. أنشئ PostController بأمر artisan.
  2. أضف الدالة index تُرجع «كل المقالات»، والدالة show(int $id) تُرجع «المقال رقم …».
  3. اربطهما بالمسارين /posts و /posts/{id} مع أسماء posts.index و posts.show.
  4. شغّل php artisan route:list --path=posts وتأكد أن المسارين يظهران مع اسم المتحكم.
  5. تحدٍّ: أنشئ CourseController بـ --resource، واربطه بـ Route::resource، ثم عدّ المسارات الجديدة.
  • نسيان سطر use للمتحكم في routes/web.php: يظهر خطأ أن الكلاس غير موجود Target class [PostController] does not exist.
  • اختلاف اسم الدالة بين المسار والمتحكم: 'index' في المسار و function list() في المتحكم لا يعملان معاً.
  • وضع كل المنطق في المتحكم: متحكم بمئات الأسطر علامة على أن الكود يحتاج تقسيماً.

سؤال

كيف تربط المسار /posts بالدالة index في PostController؟

سؤال

أي دالة في متحكم الموارد مسؤولة عن حفظ عنصر جديد بعد إرسال النموذج؟

  • المتحكم كلاس ينظّم منطق الصفحات بدل تكديسه في المسارات.
  • تنشئه بـ php artisan make:controller وتربطه بـ [PostController::class, 'index'].
  • معاملات الرابط تصل للدالة باسمها، و Request $request لقراءة بيانات الطلب.
  • المتحكم يرسل البيانات للصفحة بـ view('name', [...]).
  • --resource و Route::resource يجهّزان العمليات السبع لـ CRUD دفعة واحدة.