إطار Laravel

معالجة النماذج والتحقق

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

معالجة النماذج والتحقق

النماذج هي الطريقة الأساسية التي يتفاعل بها المستخدمون مع تطبيقات الويب. يوفر Laravel أدوات قوية للتعامل مع إرسالات النماذج، والتحقق من صحة المدخلات، وعرض الأخطاء. في هذا الدرس، ستتعلم كيفية بناء نماذج آمنة ومتحقق منها مع معالجة أخطاء أنيقة.

لماذا يهم التحقق

لا تثق أبدًا في مدخلات المستخدم. يضمن التحقق ما يلي:

  • تلبي البيانات متطلباتك قبل المعالجة
  • تبقى قاعدة البيانات نظيفة ومتسقة
  • يتم حماية تطبيقك من المدخلات الضارة
  • يتلقى المستخدمون ملاحظات واضحة حول الأخطاء
نصيحة: نظام التحقق في Laravel تصريحي—تصف كيف تبدو البيانات الصالحة، و Laravel يتعامل مع الباقي.

حماية CSRF

يحمي Laravel تطبيقك تلقائيًا من هجمات تزوير الطلبات عبر المواقع (CSRF). يجب أن يتضمن كل نموذج يستخدم POST أو PUT أو PATCH أو DELETE رمز CSRF.

<form action="/posts" method="POST">
    @csrf
    <!-- حقول النموذج -->
    <button type="submit">إرسال</button>
</form>
تحذير: بدون @csrf، سيتم رفض طلبات POST/PUT/PATCH/DELETE الخاصة بك مع خطأ 419. قم بتضمينه دائمًا في نماذجك.

انتحال طريقة النموذج

نماذج HTML تدعم فقط طرق GET و POST. لاستخدام PUT أو PATCH أو DELETE، تحتاج إلى انتحال الطريقة:

<!-- نموذج التحديث (PUT) -->
<form action="/posts/{{ $post->id }}" method="POST">
    @csrf
    @method('PUT')
    <!-- حقول النموذج -->
</form>

<!-- نموذج الحذف -->
<form action="/posts/{{ $post->id }}" method="POST">
    @csrf
    @method('DELETE')
    <button type="submit">حذف</button>
</form>

التحقق الأساسي في وحدات التحكم

أبسط طريقة للتحقق هي مباشرة في وحدة التحكم الخاصة بك باستخدام طريقة validate():

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;

class PostController extends Controller
{
    public function store(Request $request)
    {
        // التحقق من الطلب
        $validated = $request->validate([
            'title' => 'required|max:255',
            'content' => 'required',
            'published_at' => 'nullable|date',
        ]);

        // إذا نجح التحقق، قم بإنشاء المنشور
        $post = Post::create($validated);

        return redirect()->route('posts.show', $post)
            ->with('success', 'تم إنشاء المنشور بنجاح!');
    }
}

إذا فشل التحقق، يعيد Laravel التوجيه تلقائيًا مع الأخطاء والمدخلات القديمة. لا حاجة لكود إضافي!

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

// مطلوب واختياري
'field' => 'required'           // يجب أن يكون موجودًا وغير فارغ
'field' => 'nullable'           // يمكن أن يكون null
'field' => 'sometimes'          // التحقق فقط إذا كان موجودًا

// قواعد النص
'field' => 'string'             // يجب أن يكون نصًا
'field' => 'max:255'            // حد أقصى 255 حرف
'field' => 'min:3'              // حد أدنى 3 أحرف
'field' => 'between:3,255'      // بين 3-255 حرف

// قواعد رقمية
'field' => 'integer'            // يجب أن يكون عدد صحيح
'field' => 'numeric'            // يجب أن يكون رقميًا (int/float)
'field' => 'min:1'              // قيمة دنيا 1
'field' => 'max:100'            // قيمة قصوى 100
'field' => 'between:1,100'      // بين 1-100

// قواعد التاريخ
'field' => 'date'               // تاريخ صالح
'field' => 'date_format:Y-m-d'  // تنسيق محدد
'field' => 'before:tomorrow'    // قبل الغد
'field' => 'after:yesterday'    // بعد الأمس
'field' => 'before_or_equal:today'
'field' => 'after_or_equal:2023-01-01'

// البريد الإلكتروني وعنوان URL
'field' => 'email'              // بريد إلكتروني صالح
'field' => 'email:rfc,dns'      // التحقق الصارم من البريد الإلكتروني
'field' => 'url'                // عنوان URL صالح
'field' => 'active_url'         // عنوان URL يستجيب

// منطقي
'field' => 'boolean'            // true, false, 1, 0, "1", "0"
'field' => 'accepted'           // yes, on, 1, true (للشروط والأحكام)

// المصفوفات
'field' => 'array'              // يجب أن يكون مصفوفة
'field' => 'array:key1,key2'    // مصفوفة بمفاتيح محددة
'field.*' => 'string'           // كل عنصر في المصفوفة نص

// تحميل الملفات
'field' => 'file'               // يجب أن يكون ملف
'field' => 'image'              // يجب أن يكون صورة
'field' => 'mimes:jpg,png,pdf'  // أنواع MIME محددة
'field' => 'max:2048'           // حد أقصى 2 ميجابايت (بالكيلوبايت)
'field' => 'dimensions:min_width=100,min_height=100'

// قواعد قاعدة البيانات
'field' => 'unique:users,email' // فريد في users.email
'field' => 'exists:users,id'    // موجود في users.id
'field' => 'unique:users,email,' . $user->id  // تجاهل المستخدم الحالي

قواعد متعددة

دمج قواعد متعددة باستخدام فاصل الأنبوب أو صيغة المصفوفة:

// صيغة الأنبوب
$request->validate([
    'email' => 'required|email|unique:users,email',
    'password' => 'required|min:8|confirmed',
]);

// صيغة المصفوفة (موصى بها للقواعد المعقدة)
$request->validate([
    'email' => ['required', 'email', 'unique:users,email'],
    'password' => ['required', 'min:8', 'confirmed'],
]);

رسائل التحقق المخصصة

تجاوز رسائل الخطأ الافتراضية:

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

أسماء السمات المخصصة

تخصيص أسماء السمات في رسائل الخطأ:

$request->validate(
    [
        'user_email' => 'required|email',
    ],
    [],
    [
        'user_email' => 'عنوان البريد الإلكتروني',
    ]
);

// رسالة الخطأ: "حقل عنوان البريد الإلكتروني مطلوب."
// بدلاً من: "حقل user email مطلوب."

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

يجعل Laravel الأخطاء متاحة تلقائيًا لعروضك:

<!-- عرض جميع الأخطاء -->
@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

<!-- التحقق من وجود خطأ في الحقل -->
<input type="email"
       name="email"
       class="@error('email') is-invalid @enderror"
       value="{{ old('email') }}">

الحفاظ على المدخلات القديمة

عندما يفشل التحقق، احفظ مدخلات المستخدم باستخدام مساعد old():

<input type="text" name="title" value="{{ old('title') }}">

<textarea name="content">{{ old('content') }}</textarea>

<select name="category">
    <option value="1" {{ old('category') == 1 ? 'selected' : '' }}>تقنية</option>
    <option value="2" {{ old('category') == 2 ? 'selected' : '' }}>أخبار</option>
</select>

<input type="checkbox"
       name="terms"
       {{ old('terms') ? 'checked' : '' }}>

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

للمنطق المعقد للتحقق، قم بإنشاء فئة طلب نموذج مخصصة:

# إنشاء طلب نموذج
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
    {
        // إرجاع true للسماح لجميع المستخدمين
        // أو إضافة منطق التخويل
        return true;
    }

    /**
     * الحصول على قواعد التحقق.
     */
    public function rules(): array
    {
        return [
            'title' => 'required|max:255',
            'content' => 'required',
            'category_id' => 'required|exists:categories,id',
            'tags' => 'array',
            'tags.*' => 'exists:tags,id',
            'published_at' => 'nullable|date|after:now',
            'featured_image' => 'nullable|image|max:2048',
        ];
    }

    /**
     * رسائل خطأ مخصصة.
     */
    public function messages(): array
    {
        return [
            'title.required' => 'يرجى تقديم عنوان لمنشورك.',
            'category_id.exists' => 'الفئة المحددة غير صالحة.',
        ];
    }

    /**
     * أسماء سمات مخصصة.
     */
    public function attributes(): array
    {
        return [
            'category_id' => 'الفئة',
            'featured_image' => 'صورة الغلاف',
        ];
    }
}

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

<?php

namespace App\Http\Controllers;

use App\Http\Requests\StorePostRequest;
use App\Models\Post;

class PostController extends Controller
{
    public function store(StorePostRequest $request)
    {
        // يحدث التحقق تلقائيًا قبل تشغيل هذه الطريقة
        // إذا فشل التحقق، يتم إعادة توجيه المستخدم مع الأخطاء

        // الحصول على البيانات المتحقق منها فقط
        $validated = $request->validated();

        $post = Post::create($validated);

        return redirect()->route('posts.show', $post)
            ->with('success', 'تم إنشاء المنشور!');
    }
}

التحقق المشروط

إضافة قواعد بناءً على الظروف:

use Illuminate\Validation\Rule;

$request->validate([
    'role' => 'required|in:user,admin',

    // التحقق من الأذونات فقط إذا كان الدور مسؤول
    'permissions' => Rule::requiredIf(fn () => $request->role === 'admin'),

    // التحقق فقط إذا كان الحقل موجودًا
    'website' => 'sometimes|url',

    // استبعاد إذا كان الشرط صحيحًا
    'password' => 'exclude_if:oauth_login,true|required|min:8',
]);

التحقق من المصفوفة المتداخلة

التحقق من المصفوفات والكائنات المتداخلة:

// نموذج بمنتجات متعددة
$request->validate([
    'products' => 'required|array|min:1',
    'products.*.name' => 'required|string|max:255',
    'products.*.price' => 'required|numeric|min:0',
    'products.*.quantity' => 'required|integer|min:1',
]);

// كائنات متداخلة
$request->validate([
    'user.name' => 'required|string',
    'user.email' => 'required|email',
    'user.address.street' => 'required',
    'user.address.city' => 'required',
]);

التحقق من تحميل الملفات

$request->validate([
    // التحقق الأساسي من الملف
    'document' => 'required|file|max:10240',  // حد أقصى 10 ميجابايت

    // التحقق من الصورة
    'photo' => 'required|image|mimes:jpeg,png,jpg|max:2048',

    // أبعاد الصورة
    'avatar' => [
        'required',
        'image',
        'dimensions:min_width=100,min_height=100,max_width=1000,max_height=1000'
    ],

    // ملفات متعددة
    'photos' => 'required|array|min:1|max:5',
    'photos.*' => 'image|max:2048',
]);

// التعامل مع تحميل الملف
if ($request->hasFile('photo')) {
    $path = $request->file('photo')->store('photos', 'public');
}
تمرين 1: نموذج اتصال

قم بإنشاء نموذج اتصال مع التحقق:

  • إنشاء مسار ووحدة تحكم وعرض لنموذج الاتصال
  • الحقول: الاسم (مطلوب، حد أقصى 100)، البريد الإلكتروني (مطلوب، بريد إلكتروني صالح)، الموضوع (مطلوب، حد أقصى 200)، الرسالة (مطلوبة، حد أدنى 10)
  • إضافة حماية CSRF
  • عرض أخطاء التحقق أسفل كل حقل
  • الحفاظ على المدخلات القديمة عند فشل التحقق
  • إظهار رسالة نجاح بعد الإرسال
تمرين 2: طلب نموذج منشور مدونة

قم بإنشاء طلب نموذج لمنشورات المدونة:

  • إنشاء StorePostRequest و UpdatePostRequest
  • التحقق: العنوان (مطلوب، حد أقصى 255)، الرابط (مطلوب، فريد)، المحتوى (مطلوب، حد أدنى 50)، معرف الفئة (موجود في الفئات)، العلامات (مصفوفة من معرفات العلامات الموجودة)، الصورة المميزة (صورة اختيارية، حد أقصى 2 ميجابايت)
  • رسائل مخصصة لجميع قواعد التحقق
  • التخويل: المستخدمون المصادق عليهم فقط يمكنهم الإنشاء/التحديث
  • التنفيذ في PostController
تمرين 3: التحقق الديناميكي من النموذج

قم بإنشاء نموذج منتج مع التحقق المشروط:

  • إذا كان نوع المنتج "مادي": يتطلب الوزن والأبعاد وتكلفة الشحن
  • إذا كان نوع المنتج "رقمي": يتطلب رابط التنزيل وحجم الملف
  • جميع المنتجات تتطلب: الاسم والسعر (حد أدنى 0.01) والوصف
  • إذا تم تحديد "مخفض": يتطلب سعر الخصم (أقل من السعر العادي)
  • السماح بصور منتج متعددة (1-5 صور، كل منها حد أقصى 1 ميجابايت)

أفضل الممارسات

  • تحقق دائمًا من مدخلات المستخدم: لا تثق أبدًا بالبيانات من النماذج أو واجهات برمجة التطبيقات أو أي مصدر خارجي.
  • استخدم طلبات النماذج: انقل منطق التحقق المعقد إلى فئات طلب النموذج لتنظيم أفضل.
  • الفشل السريع: ضع القواعد الأكثر تقييدًا أولاً (على سبيل المثال، required قبل email).
  • قدم رسائل خطأ واضحة: يجب أن يفهم المستخدمون بالضبط ما حدث خطأ وكيفية إصلاحه.
  • احتفظ بمدخلات المستخدم: استخدم دائمًا old() للحفاظ على المدخلات عند فشل التحقق.
  • تحقق من تحميلات الملفات: تحقق دائمًا من نوع الملف وحجمه وأبعاده لمنع المشكلات الأمنية.
  • استخدم حماية CSRF: لا تعطل أبدًا حماية CSRF ما لم يكن لديك سبب وجيه للغاية.

الخلاصة

في هذا الدرس، أتقنت:

  • حماية CSRF وانتحال طريقة النموذج
  • التحقق الأساسي من وحدة التحكم مع القواعد الشائعة
  • رسائل التحقق المخصصة وأسماء السمات
  • عرض أخطاء التحقق في العروض
  • الحفاظ على المدخلات القديمة باستخدام مساعد old()
  • إنشاء فئات طلب النموذج للتحقق المعقد
  • التحقق المشروط والمصفوفة المتداخلة
  • التحقق من تحميل الملفات ومعالجتها

التحقق من النموذج أمر بالغ الأهمية لسلامة البيانات والأمان. مع نظام التحقق في Laravel، يمكنك بناء نماذج قوية وسهلة الاستخدام بأقل قدر من الكود!