إطار Laravel

المتحكمات ومعالجة الطلبات

18 دقيقة الدرس 4 من 45

مقدمة في المتحكمات

المتحكمات مسؤولة عن معالجة طلبات HTTP الواردة وإرجاع الاستجابات. بدلاً من تعريف كل منطق معالجة الطلبات في closures المسارات، تنظم المتحكمات المنطق ذي الصلة في فئات مخصصة.

لماذا نستخدم المتحكمات؟ تساعدك المتحكمات على تنظيم الكود منطقياً، مما يجعل تطبيقك أكثر قابلية للصيانة والاختبار. تتبع مبدأ المسؤولية الواحدة من خلال تجميع منطق معالجة طلبات HTTP ذات الصلة معاً.

إنشاء المتحكمات

إنشاء متحكم أساسي

استخدم أمر Artisan لتوليد متحكم جديد:

# إنشاء متحكم أساسي php artisan make:controller PostController # ينشئ: app/Http/Controllers/PostController.php

هذا يُنشئ فئة متحكم أساسية:

<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class PostController extends Controller { // الدوال الخاصة بك تذهب هنا }

متحكم مع دوال

أضف دوال للتعامل مع الإجراءات المختلفة:

<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class PostController extends Controller { public function index() { return view('posts.index'); } public function show($id) { return view('posts.show', ['postId' => $id]); } public function create() { return view('posts.create'); } public function store(Request $request) { // معالجة إرسال النموذج return redirect()->route('posts.index'); } }

تعريف المسارات للمتحكمات

use App\Http\Controllers\PostController; // مسارات الإجراء الواحد Route::get('/posts', [PostController::class, 'index'])->name('posts.index'); Route::get('/posts/{id}', [PostController::class, 'show'])->name('posts.show'); Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create'); Route::post('/posts', [PostController::class, 'store'])->name('posts.store');

متحكمات الموارد

تجعل متحكمات الموارد بناء متحكمات RESTful حول مورد أمراً سهلاً. تتضمن دوالاً لعمليات CRUD النموذجية.

إنشاء متحكمات الموارد

# إنشاء متحكم موارد مع دوال CRUD قياسية php artisan make:controller PostController --resource # إنشاء مع ربط النموذج php artisan make:controller PostController --model=Post # إنشاء متحكم موارد API (بدون create/edit) php artisan make:controller PostController --api

بنية متحكم الموارد

<?php namespace App\Http\Controllers; use App\Models\Post; use Illuminate\Http\Request; class PostController extends Controller { /** * عرض قائمة بالموارد. */ public function index() { $posts = Post::all(); return view('posts.index', compact('posts')); } /** * إظهار نموذج إنشاء مورد جديد. */ public function create() { return view('posts.create'); } /** * تخزين مورد تم إنشاؤه حديثاً في التخزين. */ public function store(Request $request) { $validated = $request->validate([ 'title' => 'required|max:255', 'content' => 'required', ]); $post = Post::create($validated); return redirect() ->route('posts.show', $post) ->with('success', 'تم إنشاء المنشور بنجاح!'); } /** * عرض المورد المحدد. */ public function show(Post $post) { return view('posts.show', compact('post')); } /** * إظهار نموذج تحرير المورد المحدد. */ public function edit(Post $post) { return view('posts.edit', compact('post')); } /** * تحديث المورد المحدد في التخزين. */ public function update(Request $request, Post $post) { $validated = $request->validate([ 'title' => 'required|max:255', 'content' => 'required', ]); $post->update($validated); return redirect() ->route('posts.show', $post) ->with('success', 'تم تحديث المنشور بنجاح!'); } /** * إزالة المورد المحدد من التخزين. */ public function destroy(Post $post) { $post->delete(); return redirect() ->route('posts.index') ->with('success', 'تم حذف المنشور بنجاح!'); } }

تسجيل مسارات الموارد

use App\Http\Controllers\PostController; Route::resource('posts', PostController::class); // هذا السطر الواحد ينشئ جميع المسارات الـ 7 RESTful
الاتفاقية بدلاً من التكوين: تتبع متحكمات الموارد اتفاقيات تسمية RESTful. باتباع هذه الاتفاقيات، يمكنك تسجيل جميع مسارات CRUD بسطر واحد من الكود!

متحكمات الإجراء الواحد

أحياناً يتعامل المتحكم مع إجراء واحد فقط. استخدم الدالة السحرية __invoke:

# إنشاء متحكم قابل للاستدعاء php artisan make:controller ShowProfileController --invokable
<?php namespace App\Http\Controllers; use App\Models\User; class ShowProfileController extends Controller { /** * معالجة الطلب الوارد. */ public function __invoke($id) { $user = User::findOrFail($id); return view('profile.show', compact('user')); } }

التوجيه إلى المتحكمات القابلة للاستدعاء

use App\Http\Controllers\ShowProfileController; // لا حاجة لاسم الدالة Route::get('/profile/{id}', ShowProfileController::class);

كائن الطلب

يحتوي كائن Request على معلومات حول طلب HTTP، بما في ذلك الإدخال والكوكيز والملفات وغيرها.

الوصول إلى بيانات الطلب

use Illuminate\Http\Request; public function store(Request $request) { // الحصول على جميع بيانات الإدخال $data = $request->all(); // الحصول على إدخال محدد $name = $request->input('name'); $email = $request->input('email'); // الحصول مع القيمة الافتراضية $role = $request->input('role', 'user'); // الوصول إلى الخاصية المختصرة $name = $request->name; $email = $request->email; // الحصول فقط على الحقول المحددة $data = $request->only(['name', 'email']); // الحصول على الكل باستثناء الحقول المحددة $data = $request->except(['_token', '_method']); // التحقق من وجود الإدخال if ($request->has('name')) { // الإدخال موجود } // التحقق من أن الإدخال له قيمة (غير فارغ) if ($request->filled('name')) { // الإدخال له قيمة } // التحقق من عدم وجود الإدخال if ($request->missing('name')) { // الإدخال مفقود } }

استرجاع بيانات سلسلة الاستعلام

// URL: /posts?page=2&sort=latest public function index(Request $request) { $page = $request->query('page'); // 2 $sort = $request->query('sort'); // latest // الحصول على جميع معاملات الاستعلام $query = $request->query(); // مع القيمة الافتراضية $perPage = $request->query('per_page', 15); }

استرجاع تحميلات الملفات

public function upload(Request $request) { // التحقق من رفع الملف if ($request->hasFile('avatar')) { $file = $request->file('avatar'); // الحصول على معلومات الملف $name = $file->getClientOriginalName(); $extension = $file->getClientOriginalExtension(); $size = $file->getSize(); // تخزين الملف $path = $file->store('avatars'); // يُخزن في storage/app/avatars/ // التخزين باسم مخصص $path = $file->storeAs('avatars', 'user-avatar.jpg'); // التخزين على قرص محدد $path = $file->store('avatars', 's3'); } }

طرق الطلب و URIs

public function handle(Request $request) { // الحصول على طريقة الطلب $method = $request->method(); // GET, POST, إلخ // التحقق من طريقة الطلب if ($request->isMethod('post')) { // معالجة طلب POST } // الحصول على مسار الطلب $path = $request->path(); // يُرجع: posts/create // الحصول على URL الكامل $url = $request->url(); // يُرجع: http://example.com/posts/create // الحصول على URL الكامل مع سلسلة الاستعلام $urlWithQuery = $request->fullUrl(); // يُرجع: http://example.com/posts/create?sort=latest // التحقق من أن الطلب يتوقع JSON if ($request->expectsJson()) { return response()->json($data); } // التحقق من أن الطلب هو AJAX if ($request->ajax()) { // معالجة طلب AJAX } }

التحقق من صحة الإدخال

يوفر لارافيل ميزات تحقق قوية لضمان أن البيانات الواردة تلبي متطلباتك.

التحقق الأساسي

public function store(Request $request) { $validated = $request->validate([ 'title' => 'required|max:255', 'content' => 'required', 'category' => 'required|in:tech,lifestyle,business', 'email' => 'required|email|unique:users', 'age' => 'required|integer|min:18|max:100', 'website' => 'nullable|url', 'published_at' => 'nullable|date', ]); // إذا نجح التحقق، يتم تنفيذ هذا الكود $post = Post::create($validated); return redirect()->route('posts.show', $post); }

قواعد التحقق الشائعة

// حقل مطلوب 'name' => 'required' // سلسلة نصية بحد أدنى وأقصى للطول 'username' => 'required|string|min:3|max:20' // التحقق من البريد الإلكتروني 'email' => 'required|email' // فريد في جدول قاعدة البيانات 'email' => 'required|email|unique:users' // رقمي وضمن نطاق 'age' => 'required|numeric|min:18|max:120' // عدد صحيح 'quantity' => 'required|integer' // منطقي 'active' => 'required|boolean' // تنسيق التاريخ 'birth_date' => 'required|date|date_format:Y-m-d' // يجب أن يطابق حقلاً آخر 'password_confirmation' => 'required|same:password' // التحقق من المصفوفة 'tags' => 'required|array|min:1' 'tags.*' => 'string|max:50' // التحقق من الملف 'avatar' => 'required|file|image|max:2048' // بحد أقصى 2 ميجابايت 'document' => 'required|file|mimes:pdf,doc,docx|max:5120' // اختياري (قابل للإلغاء) 'bio' => 'nullable|string|max:500' // قواعد متعددة كمصفوفة 'email' => ['required', 'email', 'unique:users']

رسائل خطأ مخصصة

public function store(Request $request) { $validated = $request->validate([ 'title' => 'required|max:255', 'email' => 'required|email|unique:users', ], [ 'title.required' => 'يرجى تقديم عنوان لمنشورك.', 'title.max' => 'لا يمكن أن يتجاوز العنوان 255 حرفاً.', 'email.required' => 'عنوان البريد الإلكتروني مطلوب.', 'email.unique' => 'هذا البريد الإلكتروني مسجل بالفعل.', ]); }

عرض أخطاء التحقق

<!-- في قالب Blade --> @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <!-- عرض الخطأ لحقل محدد --> <input type="text" name="title" value="{{ old('title') }}"> @error('title') <div class="error">{{ $message }}</div> @enderror

التحقق من طلب النموذج

لمنطق التحقق المعقد، أنشئ فئات Form Request مخصصة:

إنشاء طلبات النموذج

# إنشاء طلب نموذج php artisan make:request StorePostRequest # ينشئ: app/Http/Requests/StorePostRequest.php

فئة طلب النموذج

<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class StorePostRequest extends FormRequest { /** * تحديد ما إذا كان المستخدم مخولاً لإجراء هذا الطلب. */ public function authorize(): bool { // التحقق من إمكانية إنشاء المنشورات return auth()->check(); } /** * الحصول على قواعد التحقق التي تنطبق على الطلب. */ public function rules(): array { return [ 'title' => 'required|max:255', 'content' => 'required|min:100', 'category_id' => 'required|exists:categories,id', 'tags' => 'array|max:5', 'tags.*' => 'string|max:50', 'featured_image' => 'nullable|image|max:2048', ]; } /** * الحصول على رسائل الخطأ المخصصة. */ public function messages(): array { return [ 'title.required' => 'كل منشور يحتاج إلى عنوان جذاب!', 'content.min' => 'يرجى كتابة ما لا يقل عن 100 حرف.', ]; } /** * الحصول على أسماء السمات المخصصة. */ public function attributes(): array { return [ 'category_id' => 'الفئة', ]; } }

استخدام طلبات النموذج في المتحكمات

use App\Http\Requests\StorePostRequest; public function store(StorePostRequest $request) { // يتم التحقق من صحة الطلب تلقائياً // إذا فشل التحقق، يتم إعادة توجيه المستخدم مع الأخطاء // الحصول على البيانات المحققة فقط $validated = $request->validated(); $post = Post::create($validated); return redirect()->route('posts.show', $post); }
فوائد طلب النموذج: تحافظ طلبات النموذج على نظافة المتحكمات، وتركز منطق التحقق، وتوفر فحوصات التفويض، وهي أسهل للاختبار وإعادة الاستخدام عبر متحكمات متعددة.

الاستجابات

إرجاع العروض

public function index() { return view('posts.index'); } // مع البيانات public function show($id) { $post = Post::findOrFail($id); return view('posts.show', compact('post')); }

استجابات JSON

public function apiIndex() { $posts = Post::all(); return response()->json($posts); } // مع كود الحالة public function apiStore(Request $request) { $post = Post::create($request->validated()); return response()->json($post, 201); // 201 Created } // استجابة خطأ public function apiError() { return response()->json([ 'error' => 'المورد غير موجود' ], 404); }

إعادة التوجيه

// إعادة التوجيه إلى URI return redirect('/dashboard'); // إعادة التوجيه إلى مسار مسمى return redirect()->route('posts.index'); // إعادة التوجيه إلى مسار مسمى مع معاملات return redirect()->route('posts.show', ['id' => 5]); // إعادة التوجيه إلى الصفحة السابقة return redirect()->back(); // إعادة التوجيه مع بيانات flash return redirect() ->route('posts.index') ->with('success', 'تم إنشاء المنشور بنجاح!'); // إعادة التوجيه مع الإدخال return redirect() ->back() ->withInput() ->withErrors(['email' => 'عنوان بريد إلكتروني غير صالح']);

استجابات التنزيل

public function download() { $file = storage_path('app/documents/report.pdf'); return response()->download($file); } // مع اسم مخصص return response()->download($file, 'monthly-report.pdf'); // بث الملف (عرض في المتصفح) return response()->file($file);

تمرين عملي 1: متحكم الموارد

أنشئ متحكم موارد كامل لإدارة المهام:

  1. أنشئ نموذج Task وترحيل: php artisan make:model Task -m
  2. أنشئ متحكم موارد: php artisan make:controller TaskController --resource
  3. نفذ جميع الدوال الـ 7 لـ CRUD (index, create, store, show, edit, update, destroy)
  4. سجل مسار الموارد في web.php
  5. أنشئ عروض Blade أساسية لكل دالة

تمرين عملي 2: التحقق من النموذج

نفذ التحقق لإنشاء مهمة:

  1. أضف قواعد التحقق إلى دالة store: العنوان (مطلوب، بحد أقصى 255)، الوصف (اختياري، بحد أقصى 1000)، تاريخ الاستحقاق (مطلوب، تاريخ، بعد اليوم)، الأولوية (مطلوب، في: منخفض، متوسط، عالي)
  2. أنشئ رسائل خطأ مخصصة لكل قاعدة
  3. اعرض أخطاء التحقق في عرض الإنشاء
  4. تأكد من الحفاظ على الإدخال القديم عند فشل التحقق

تمرين عملي 3: طلب النموذج

أعد هيكلة التحقق الخاص بك في طلب نموذج:

  1. أنشئ StoreTaskRequest: php artisan make:request StoreTaskRequest
  2. انقل قواعد التحقق من المتحكم إلى طلب النموذج
  3. أضف منطق التفويض (فقط المستخدمون المصادق عليهم يمكنهم إنشاء المهام)
  4. حدّث متحكمك لاستخدام طلب النموذج
  5. اختبر أن التحقق لا يزال يعمل بشكل صحيح

الملخص

في هذا الدرس، تعلمت:

  • كيفية إنشاء وتنظيم المتحكمات للتعامل مع طلبات HTTP
  • استخدام متحكمات الموارد لعمليات CRUD RESTful
  • إنشاء متحكمات قابلة للاستدعاء بإجراء واحد
  • العمل مع كائن Request للوصول إلى بيانات الإدخال والملفات ومعلومات الطلب
  • تنفيذ التحقق من صحة الإدخال مع القواعد والرسائل المخصصة
  • إنشاء فئات Form Request لمنطق التحقق المعقد
  • إرجاع أنواع مختلفة من الاستجابات (عروض، JSON، إعادة التوجيه، التنزيلات)

المتحكمات هي قلب معالجة الطلبات في تطبيقك. في الدرس التالي، سنستكشف قوالب Blade لإنشاء عروض جميلة وديناميكية!