الدرس الرابع: Routing في Laravel – إنشاء المسارات والتعامل مع الروابط والبيانات
بعد أن تعرّفنا في الدروس السابقة على Laravel، وقمنا بتجهيز بيئة العمل وإنشاء أول مشروع، ثم تعرّفنا على بنية المشروع والمجلدات والملفات الأساسية، حان الوقت للبدء في التعامل مع واحد من أهم أجزاء أي تطبيق ويب، وهو Routing أو نظام المسارات.
الـ Routing هو الجزء الذي يحدد ماذا يحدث عندما يقوم المستخدم بزيارة رابط معين داخل الموقع.
فعندما يكتب المستخدم مثلًا:
http://localhost:8000/
أو:
http://localhost:8000/about
فإن Laravel يحتاج إلى معرفة الكود الذي يجب تشغيله عند زيارة كل رابط.
وهنا يأتي دور Routes.
في هذا الدرس سنتعلم كيفية إنشاء أول Route في Laravel، والتعامل مع أنواع الطلبات HTTP مثل GET وPOST، وتمرير البيانات من الرابط، وإنشاء Named Routes، وربط المسارات بالـ Controllers، بالإضافة إلى التعرف على بعض الأخطاء الشائعة وأفضل الممارسات التي يجب أن تبدأ بها من الآن.
ما هو Routing في Laravel؟
يمكننا تبسيط فكرة Routing بأنها عملية ربط عنوان URL معين بكود يتم تنفيذه عندما يزور المستخدم هذا العنوان.
على سبيل المثال، إذا أردنا إنشاء صفحة باسم "من نحن"، يمكننا إنشاء Route بهذا الشكل:
Route::get('/about', function () {
return 'About Us';
});
هذا يعني:
عندما يقوم المستخدم بزيارة:
/about
باستخدام طلب GET، سيقوم Laravel بتنفيذ الكود الموجود داخل الدالة.
نظام Routing هو حلقة الوصل بين المستخدم والتطبيق.
فالمستخدم يطلب URL، وLaravel يبحث عن Route مناسب لهذا الطلب، ثم يقوم بتنفيذ الـ Closure أو Controller المرتبط بهذا Route.
وتوضح وثائق Laravel الرسمية أن ملف routes/web.php هو المكان الأساسي الذي تبدأ منه Routes الخاصة بواجهة الويب في التطبيق. كما أن Laravel يوفر طرقًا للتعامل مع أنواع HTTP المختلفة وربطها بالـ Closures أو Controllers.
أين نكتب Routes في Laravel؟
في مشروع Laravel ستجد مجلدًا باسم:
routes
وفي Laravel 13 يحتوي المشروع افتراضيًا على ملفات Routes مثل:
routes/ ├── web.php └── console.php
بالنسبة لصفحات الموقع التي يصل إليها المستخدم من خلال المتصفح، سنعمل بشكل أساسي داخل:
routes/web.php
لذلك إذا أردت إنشاء صفحة جديدة في موقعك، فمن الطبيعي أن تبدأ من هذا الملف.
افتح الملف:
routes/web.php
وقد تجد بداخله Route افتراضيًا مثل:
Route::get('/', function () {
return view('welcome');
});
هذا الـ Route مسؤول عن التعامل مع الصفحة الرئيسية للتطبيق.
عندما يدخل المستخدم إلى:
/
يقوم Laravel بتنفيذ الدالة وإرجاع View باسم:
welcome
والتي تكون موجودة عادةً داخل:
resources/views/welcome.blade.php
أول Route في Laravel
لنبدأ بمثال بسيط جدًا.
افتح:
routes/web.php
واكتب:
use Illuminate\Support\Facades\Route;
Route::get('/hello', function () {
return 'Hello Laravel';
});
الآن شغل مشروعك إذا لم يكن يعمل:
composer run dev
ثم افتح المتصفح وانتقل إلى:
http://localhost:8000/hello
ستظهر لك:
Hello Laravel
مبروك، لقد أنشأت أول Route فعلي في Laravel.
فهم مكونات Route
لننظر إلى الكود مرة أخرى:
Route::get('/hello', function () {
return 'Hello Laravel';
});
يتكون Route من عدة أجزاء.
Route
هذا هو الـ Facade الذي يوفر لنا واجهة التعامل مع نظام Routing في Laravel.
Route
get
هذا يحدد نوع HTTP Request الذي يستجيب له Route.
Route::get(...)
أي أن Route سيعمل عندما يصل طلب GET إلى العنوان المحدد.
/hello
هذا هو الـ URI أو المسار:
/hello
Closure
وهو الجزء:
function () {
return 'Hello Laravel';
}
وهو الكود الذي سيتم تنفيذه عند الوصول إلى Route.
ما هو HTTP GET في Laravel؟
من المهم جدًا أن تفهم الفرق بين HTTP Methods لأن Routing يعتمد عليها بشكل كبير.
أشهر HTTP Methods التي ستتعامل معها في Laravel هي:
- GET
- POST
- PUT
- PATCH
- DELETE
سنشرحها بالتفصيل في الدروس القادمة، لكن في الوقت الحالي يمكنك فهمها بهذا الشكل:
GET
يستخدم غالبًا للحصول على البيانات أو عرض صفحة.
مثال:
GET /articles
أي:
أريد الحصول على قائمة المقالات.
POST
يستخدم غالبًا لإرسال بيانات جديدة إلى الخادم.
مثال:
POST /articles
أي:
أريد إنشاء مقال جديد.
PUT / PATCH
تستخدم غالبًا لتحديث بيانات موجودة.
مثال:
PUT /articles/10
أي:
أريد تحديث المقال رقم 10.
DELETE
يستخدم لحذف بيانات.
مثال:
DELETE /articles/10
أي:
أريد حذف المقال رقم 10.
Laravel يوفر Methods مثل get وpost وput وpatch وdelete وغيرها للتعامل مع هذه الطلبات.
إنشاء عدة Routes
يمكنك إنشاء أكثر من Route داخل:
routes/web.php
مثلًا:
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return 'Home Page';
});
Route::get('/about', function () {
return 'About Us';
});
Route::get('/contact', function () {
return 'Contact Us';
});
الآن أصبح لدينا ثلاث صفحات:
/
و:
/about
و:
/contact
وبالتالي إذا زار المستخدم:
http://localhost:8000/about
سيظهر:
About Us
وإذا زار:
http://localhost:8000/contact
سيظهر:
Contact Us
إرجاع HTML من Route
يمكنك أيضًا إرجاع HTML مباشرة من Route:
Route::get('/welcome', function () {
return '<h1>Welcome to Laravel</h1>';
});
عند زيارة:
/welcome
سيتم عرض العنوان.
لكن في المشاريع الحقيقية لا يُفضل أن تضع صفحات HTML كاملة داخل Routes، لأن ذلك يجعل المشروع صعب التنظيم والصيانة.
الأفضل استخدام Blade Views.
ربط Route مع View
بدلًا من كتابة HTML داخل Route، يمكنك إنشاء View.
اذهب إلى:
resources/views
وأنشئ ملفًا باسم:
about.blade.php
واكتب داخله:
<!DOCTYPE html>
<html lang="ar">
<head>
<meta charset="UTF-8">
<title>من نحن</title>
</head>
<body>
<h1>من نحن</h1>
<p>مرحبًا بك في موقعنا.</p>
</body>
</html>
ثم في:
routes/web.php
اكتب:
Route::get('/about', function () {
return view('about');
});
الآن عندما يزور المستخدم:
/about
سيعرض Laravel ملف:
resources/views/about.blade.php
وهذه الطريقة أفضل بكثير من وضع HTML داخل Route.
استخدام Route::view
عندما يكون Route هدفه فقط عرض View بدون الحاجة إلى منطق إضافي، يمكنك استخدام:
Route::view('/about', 'about');
بدلًا من:
Route::get('/about', function () {
return view('about');
});
النتيجة واحدة تقريبًا، لكن Route::view() تجعل الكود أكثر اختصارًا عندما لا تحتاج إلى تنفيذ أي منطق داخل Closure.
وتستخدم Laravel نفسها هذا الأسلوب في بعض الأمثلة التعليمية عندما يكون Route مسؤولًا فقط عن عرض View.
تمرير البيانات إلى View
يمكنك أيضًا إرسال بيانات من Route إلى View.
مثلًا:
Route::get('/about', function () {
$name = 'نسور التقنية';
return view('about', [
'name' => $name
]);
});
ثم داخل:
resources/views/about.blade.php
يمكنك استخدام:
<h1>مرحبًا بك في {{ $name }}</h1>
عند فتح الصفحة سيظهر:
مرحبًا بك في نسور التقنية
وهذه الفكرة مهمة جدًا لأننا لاحقًا سنستخدم Controllers لإرسال البيانات إلى Views بطريقة أكثر تنظيمًا.
Route Parameters
من أهم مميزات Routing في Laravel إمكانية استقبال قيم من URL.
تخيل أن لدينا صفحة لعرض مقال معين.
بدلًا من إنشاء Route لكل مقال:
/articles/1 /articles/2 /articles/3 /articles/4
يمكننا إنشاء Route واحد:
Route::get('/articles/{id}', function ($id) {
return 'Article ID: ' . $id;
});
الجزء:
{id}
يسمى Route Parameter.
إذا زار المستخدم:
/articles/10
فإن قيمة:
10
سيتم تمريرها إلى:
$id
والنتيجة:
Article ID: 10
وإذا زار:
/articles/25
ستكون النتيجة:
Article ID: 25
توضح وثائق Laravel أن Route Parameters يتم وضعها بين الأقواس المعقوفة {}، ويمكن تمريرها إلى Closure أو Controller المرتبط بالـ Route.
أكثر من Route Parameter
يمكنك أيضًا استخدام أكثر من Parameter.
مثلًا:
Route::get('/articles/{article}/comments/{comment}', function ($article, $comment) {
return "Article: $article - Comment: $comment";
});
إذا فتح المستخدم:
/articles/5/comments/20
فستكون:
$article = 5
و:
$comment = 20
وهكذا يمكنك بناء روابط ديناميكية.
Optional Route Parameters
في بعض الحالات قد ترغب في جعل Parameter اختياريًا.
يمكنك استخدام:
?
مثل:
Route::get('/user/{name?}', function ($name = null) {
return $name ?? 'Guest';
});
الآن:
/user/Ahmed
سيعرض:
Ahmed
بينما:
/user
سيعرض:
Guest
من المهم إعطاء المتغير قيمة افتراضية عندما يكون Parameter اختياريًا.
Named Routes
مع نمو المشروع ستجد أن الاعتماد على كتابة URL مباشرة في كل مكان ليس فكرة جيدة.
مثلًا قد يكون لديك:
Route::get('/about-us', function () {
return view('about');
});
ثم في أماكن مختلفة داخل التطبيق تكتب:
<a href="/about-us">من نحن</a>
لكن ماذا يحدث إذا غيرت الرابط إلى:
/about
ستحتاج إلى البحث عن كل الأماكن التي تحتوي على:
/about-us
وتغييرها.
هنا تأتي أهمية Named Routes.
يمكنك إعطاء Route اسمًا:
Route::get('/about', function () {
return view('about');
})->name('about');
الآن أصبح اسم Route:
about
ويمكنك إنشاء الرابط باستخدام:
<a href="{{ route('about') }}">من نحن</a>
الميزة هنا أنك تتعامل مع اسم Route بدلًا من الاعتماد على URL نفسه.
وإذا تغير URL لاحقًا، تستطيع تعديل تعريف Route دون الحاجة إلى تغيير كل الروابط التي تستخدم اسم Route.
Named Routes مع Parameters
يمكن أيضًا استخدام Named Routes مع Parameters.
مثلًا:
Route::get('/articles/{id}', function ($id) {
return "Article $id";
})->name('articles.show');
لإنشاء رابط للمقال رقم 10:
<a href="{{ route('articles.show', ['id' => 10]) }}">
عرض المقال
</a>
سيقوم Laravel بتوليد رابط مشابه لـ:
/articles/10
وهذه الطريقة ستكون مهمة جدًا عندما نبدأ ببناء أنظمة حقيقية تحتوي على صفحات كثيرة.
ربط Route مع Controller
في التطبيقات الصغيرة يمكن استخدام Closure داخل Route:
Route::get('/about', function () {
return view('about');
});
لكن مع زيادة حجم المشروع، وضع منطق التطبيق داخل web.php سيجعل الملف مزدحمًا.
هنا نستخدم Controllers.
إذا كان لدينا Controller باسم:
PageController
يمكننا إنشاء Route مثل:
use App\Http\Controllers\PageController;
Route::get('/about', [PageController::class, 'about']);
هذا يعني:
عندما يزور المستخدم:
/about
يقوم Laravel باستدعاء:
PageController
وتحديدًا الدالة:
about
داخل Controller.
يمكنك إنشاء Controller باستخدام Artisan:
php artisan make:controller PageController
ثم سيكون لديك ملف داخل:
app/Http/Controllers/PageController.php
ويمكنك كتابة:
<?php
namespace App\Http\Controllers;
class PageController extends Controller
{
public function about()
{
return view('about');
}
}
ثم Route:
use App\Http\Controllers\PageController;
Route::get('/about', [PageController::class, 'about']);
هذه البنية أكثر تنظيمًا، خصوصًا عندما يبدأ التطبيق بالنمو.
Route Parameters مع Controller
يمكنك أيضًا إرسال Route Parameter إلى Controller.
مثلًا:
Route::get('/articles/{id}', [ArticleController::class, 'show']);
وفي Controller:
public function show($id)
{
return "Article ID: " . $id;
}
عند زيارة:
/articles/15
سيتم تمرير:
15
إلى:
$id
وهذه الطريقة هي بداية مهمة جدًا لفهم العلاقة بين Routing وControllers وModels.
Route Model Binding
لاحقًا ستتعامل مع قواعد البيانات وEloquent Models.
ومن المميزات القوية في Laravel ما يسمى Route Model Binding.
بدلًا من استقبال ID ثم البحث يدويًا عن Model، يستطيع Laravel في حالات معينة حل الـ Model تلقائيًا.
مثلًا:
use App\Models\Post;
Route::get('/posts/{post}', function (Post $post) {
return $post;
});
هنا Laravel يستطيع استخدام قيمة {post} للوصول إلى الـ Post المناسب وحقنه في الدالة عندما يتطابق اسم المتغير ونوع الـ Model مع Route Parameter.
هذه الميزة تجعل الكود أبسط، وسنتوسع فيها لاحقًا عندما نبدأ درس Eloquent وقواعد البيانات.
Route Groups
عندما يكون لديك مجموعة كبيرة من Routes التي تشترك في إعداد معين، يمكنك استخدام Route Groups.
مثلًا قد يكون لديك قسم خاص بالإدارة:
/admin /admin/users /admin/posts /admin/settings
يمكنك تنظيم Routes باستخدام Prefix.
الفكرة العامة:
Route::prefix('admin')->group(function () {
Route::get('/users', function () {
return 'Users';
});
Route::get('/posts', function () {
return 'Posts';
});
});
وبذلك يصبح:
/admin/users
و:
/admin/posts
بدلًا من كتابة admin في كل Route يدويًا.
Route Groups مفيدة أيضًا عند تطبيق Middleware أو خصائص مشتركة على مجموعة Routes.
معرفة جميع Routes في المشروع
من الأدوات المفيدة جدًا أثناء تطوير Laravel الأمر:
php artisan route:list
سيعرض لك قائمة بالـ Routes الموجودة في التطبيق.
سترى معلومات مثل:
- HTTP Method
- URI
- Name
- Action
- Middleware
وهذا الأمر مفيد جدًا عندما يكون المشروع كبيرًا وتريد معرفة Routes الموجودة أو اكتشاف مشكلة في Route معين.
يمكنك أيضًا استخدام خيارات Artisan الخاصة بعرض Routes عندما تحتاج إلى تصفية القائمة أو رؤية تفاصيل إضافية.
ترتيب Routes مهم
من الأخطاء التي قد يقع فيها المبتدئ عدم الانتباه إلى ترتيب Routes.
تخيل أن لديك:
Route::get('/articles/{id}', function ($id) {
return "Article $id";
});
Route::get('/articles/latest', function () {
return 'Latest Articles';
});
قد يحدث تعارض لأن:
/articles/{id}
يمكن أن يتعامل مع latest باعتبارها قيمة للـ Parameter.
لذلك عند وجود Routes ثابتة وRoutes ديناميكية يمكن أن تتطابق مع بعضها، يجب التفكير في ترتيبها وتصميمها بعناية.
مثلًا يمكنك وضع Route الخاص بـ:
/articles/latest
قبل Route:
/articles/{id}
بحسب تصميم التطبيق والقيود التي تضعها على Parameters.
استخدام Route Constraints
يمكنك أيضًا تقييد Parameter حتى يقبل نوعًا معينًا من البيانات.
مثلًا إذا كان id يجب أن يكون رقمًا، يمكنك استخدام Constraint.
مثال:
Route::get('/articles/{id}', function ($id) {
return "Article $id";
})->whereNumber('id');
الآن Laravel يتوقع أن تكون قيمة:
{id}
رقمية.
وبالتالي:
/articles/25
صالحة.
بينما:
/articles/hello
لن تتعامل معها Route بالطريقة نفسها لأن قيمة Parameter لا تحقق القيد المحدد.
هذه القيود تصبح مفيدة جدًا عندما يكون لديك Routes ديناميكية كثيرة.
مثال عملي كامل
لنقم ببناء مثال صغير يجمع ما تعلمناه.
افترض أننا نريد إنشاء موقع بسيط يحتوي على:
- الصفحة الرئيسية
- صفحة من نحن
- قائمة المقالات
- صفحة مقال معين
في:
routes/web.php
يمكننا كتابة:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('home');
})->name('home');
Route::get('/about', function () {
return view('about');
})->name('about');
Route::get('/articles', function () {
return view('articles');
})->name('articles.index');
Route::get('/articles/{id}', function ($id) {
return "Viewing article: " . $id;
})->name('articles.show');
أصبح لدينا الآن أربعة Routes.
الصفحة الرئيسية:
/
صفحة من نحن:
/about
قائمة المقالات:
/articles
مقال معين:
/articles/10
ويمكننا إنشاء روابط لها باستخدام أسماء Routes:
<a href="{{ route('home') }}">الرئيسية</a>
<a href="{{ route('about') }}">من نحن</a>
<a href="{{ route('articles.index') }}">المقالات</a>
<a href="{{ route('articles.show', ['id' => 10]) }}">
المقال رقم 10
</a>
لاحظ كيف أصبح الكود أكثر وضوحًا وتنظيمًا.
ماذا يحدث عندما يطلب المستخدم صفحة؟
من المهم أن تفهم الصورة الكاملة.
عندما يكتب المستخدم في المتصفح:
http://localhost:8000/articles/10
يصل الطلب إلى تطبيق Laravel.
Laravel يبحث عن Route مناسب.
قد يجد:
Route::get('/articles/{id}', ...)
فيتعرف على:
{id} = 10
ثم ينفذ الـ Closure أو Controller المرتبط بالـ Route.
إذا كان Route مربوطًا بـ Controller، ينتقل التنفيذ إلى Controller.
بعد ذلك يمكن للـ Controller:
- طلب بيانات من Model.
- إرسال البيانات إلى View.
- إرجاع Response.
- إعادة توجيه المستخدم.
- أو تنفيذ منطق آخر حسب احتياجات التطبيق.
هذه الدورة هي واحدة من أهم الأفكار التي يجب أن تفهمها في Laravel.
أخطاء شائعة عند التعامل مع Routing
كتابة Route في ملف خاطئ
إذا كنت تعمل على صفحات الموقع، ابدأ عادةً من:
routes/web.php
ولا تضع Routes بشكل عشوائي في ملفات أخرى.
نسيان استيراد Route
تأكد من وجود:
use Illuminate\Support\Facades\Route;
عند الحاجة إليه في الملف.
كتابة URL بشكل غير صحيح
إذا كان Route:
Route::get('/about', ...);
فالرابط هو:
/about
وليس:
/about-us
إلا إذا قمت بتعريفه بهذا الشكل.
الخلط بين GET وPOST
Route من نوع:
Route::get('/articles', ...);
ليس هو نفسه:
Route::post('/articles', ...);
فالطلب HTTP Method جزء أساسي من تعريف Route.
وضع منطق كبير داخل web.php
يمكنك استخدام Closure في البداية للتجارب، لكن عندما يصبح التطبيق أكبر من الأفضل نقل المنطق إلى Controllers وتنظيم التطبيق بشكل واضح.
تمرين عملي
قبل الانتقال إلى الدرس التالي، حاول تنفيذ هذا التمرين بنفسك.
أنشئ تطبيقًا يحتوي على Routes التالية:
الصفحة الرئيسية
/
وتعرض:
مرحبًا بك في موقعي
صفحة من نحن
/about
وتعرض View مستقلة.
صفحة المنتجات
/products
وتعرض قائمة بسيطة.
صفحة منتج معين
/products/{id}
وتعرض رقم المنتج.
Route باسم
اجعل Route الخاص بالمنتجات يحمل الاسم:
products.index
ثم أنشئ رابطًا له باستخدام:
{{ route('products.index') }}
اختبر Routes
بعد ذلك استخدم:
php artisan route:list
وتأكد من ظهور Routes التي أنشأتها.
في هذا الدرس تعرفنا على Routing في Laravel، وهو من أهم الأجزاء التي ستتعامل معها في كل مشروع تقريبًا.
تعلمنا أن Routes تحدد كيف يستجيب التطبيق للروابط وطلبات HTTP، وأن الملف:
routes/web.php
هو نقطة البداية الأساسية لصفحات الويب في Laravel.
وتعلمنا إنشاء Route باستخدام:
Route::get()
وكيفية عرض نص أو View، وكيفية تمرير البيانات إلى View.
كما تعرفنا على Route Parameters مثل:
/articles/{id}
وتعلمنا كيفية استخدام Optional Parameters وNamed Routes، بالإضافة إلى ربط Routes بالـ Controllers.
وتعرفنا أيضًا على Route Groups وRoute Constraints والأمر:
php artisan route:list
لفحص Routes الموجودة في التطبيق.
الأهم من ذلك هو أن تبدأ في التفكير في Routing كحلقة وصل بين URL → Route → Controller → Model → View → Response.
في الدروس القادمة سنبدأ في الانتقال من Routes البسيطة إلى بناء أجزاء أكثر واقعية من التطبيق، وسنتعرف بشكل أعمق على Controllers وكيفية تنظيم منطق التطبيق بدلًا من وضع كل شيء داخل ملف web.php.
وبمجرد أن تفهم Routing جيدًا، ستجد أن بناء صفحات Laravel أصبح أكثر وضوحًا، لأنك أصبحت تعرف بالضبط كيف يصل الطلب إلى الكود الذي سيقوم بتنفيذه.