Laravel/validation
التحقق (validation)
مقدّمة
يوفّر Laravel عدّة طرق مختلفة للتحقّق من صحّة البيانات الواردة للتطبيقك. يستخدم صنف وحدة التحكّم الأساسي في Laravel الخاصيّة ValidatesRequests التي توفّر طريقة ملائمة للتحقق من صحة الطلب HTTP الوارد بمجموعة متنوّعة من قواعد التحقق الفعّالة.
بداية سريعة في التحقّق
لمعرفة المزيد عن ميزات التحقق الفعالة في Laravel ، دعنا نلقي نظرة على مثال كامل من التحقق من صحّة استمارة وعرض رسائل الخطأ على المستخدم.
تعريف المسارات
لنفترض أولًا أنّ لدينا المسارات التالية المحدّدة في ملفّنا routes/web.php:
Route::get('post/create', 'PostController@create');
Route::post('post', 'PostController@store');
سيعرض المسار GET استمارة للمستخدم لإنشاء منشور مدوّنة جديد بينما سيخزّن المسار POST منشور المدونة الجديد في قاعدة البيانات.
إنشاء وحدة التحكّم
فلنلقي في الخطوة التالية نظرة على وحدة تحكم بسيطة تتعامل مع هذه المسارات. سنترك التابع store فارغًا حاليًّا:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* إظهار الاستمارة لإنشاء منشور مدوّنة جديد
*
* @return Response
*/
public function create()
{
return view('post.create');
}
/**
* إنشاء منشور مدوّنة جديد
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
// تحقّق وتخزّن المنشور الجديد ...
}
}
كتابة منطق التحقّق
نحن الآن مُستعدّون لملء التابع store بالمنطق للتحقق من مشاركة المدوّنة الجديدة. لذلك، سنستخدم التابع validate المقدّم من الكائن Illuminate\Http\Request. إذا نجحت قواعد التحقّق، ستواصل التعليمات البرمجيّة التنفيذ بشكل طبيعي؛ ولكن في حالة فشل التحقق من الصحّة، سيُطرح استثناء وتُرسل استجابة الخطأ المناسبة إلى المستخدم تلقائيًا. ستُنشئ في حالة طلب HTTP تقليدي استجابة إعادة توجيه، في حين تُرسل استجابة JSON لطلبات AJAX.
لفهم التابع validate بشكل أفضل، فلنعد مرّة أخرى إلى التابع store :
/**
* تخزين منشور المدوّنة الجديد
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// منشور المدونة صالح ...
}
كما ترى نُمرّر قواعد التحقق المرغوبة للتابع validate. ومرّة أخرى، إذا فشل التحقّق من الصحّة، ستُنشئ الاستجابة المناسبة تلقائيًا. إن نجحت عمليّة التحقّق، ستستمر وحدة تحكّمنا في العمل بشكل طبيعي.
التوقف عند أوّل فشل تحقّق
قد ترغب أحيانًا في إيقاف تشغيل قواعد التحقق من صحّة خاصيّة (attribute) ما بعد أول فشل في التحقّق. للقيام بذلك، عيّن القاعدة bail على السمة:
$request->validate([
'title' => 'bail|required|unique:posts|max:255',
'body' => 'required',
]);
في هذا المثال، إذا فشلت القاعدة unique مع الخاصيّة title، لن يتحقّق من القاعدة max. سيتم التحقق من القواعد بالترتيب الذي عُيّنت عليه.
ملاحظة حول الخاصيات المتداخلة
تستطيع تحديد معاملاتك 'المتداخلة"، إن احتوى طلبك HTTP عليها، في قواعد تحقّقك باستخدام الصيغة "نقطة":
$request->validate([
'title' => 'required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);
عرض أخطاء التحقق
لكن ماذا لو لم تتجاوز معاملات الطلب الوارد قواعد التحقق المحددة؟ كما ذكرنا سابقًا، سيُعيد Laravel توجيه المستخدم تلقائيًا إلى موقعه السابق. بالإضافة إلى ذلك، ستومض جميع أخطاء التحقق تلقائيًا إلى الجلسة.
مرة أخرى، لاحظ أننا لم نضطر لربط رسائل الخطأ صراحة بالواجهة في مسارنا GET
. ويرجع ذلك لتحقّق Laravel من وجود أخطاء في بيانات الجلسات وربطها تلقائيًا بالواجهة إذا كانت متوفرة. سيكون المتغيّر $errors
نسخة من Illuminate\Support\MessageBag
. لمزيد من المعلومات حول العمل مع هذا الكائن راجع توثيقه.
ملاحظة: يرتبط المتغيّر errors$
بالواجهة عبر البرمجيّة الوسيطة Illuminate\View\Middleware\ShareErrorsFromSession
التي تُوفّرها مجموعة برمجيّات web
الوسيطة. عند تطبيق هذه البرمجيّة الوسيطة، سيصبح المتغيّر $errors
متاحًا دائمًا في واجهاتك مما يتيح لك افتراض أن المتغيّر $errors
مُعرّف دائمًا ويمكن استخدامه بأمان.
إذًا في مثالنا هذا سيُعاد توجيه المستخدم إلى تابع وحدة تحكّمنا create
عند فشل عملية التحقق مما يسمح لنا بعرض رسائل الخطأ في الواجهة:
<!-- /resources/views/post/create.blade.php -->
<h1>Create Post</h1>
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- Create Post Form -->
ملاحظة حول الحقول الاختيارية
يحتوي Laravel افتراضيًّا على البرمجيّتين الوسيطتين TrimStrings
و ConvertEmptyStringsToNull
في مكدّس برمجيّات تطبيقك الوسيطة العامة. تورد قائمة هذه البرمجيّات الوسيطة في المكدس من طرف الصنف App\Http\Kernel
. وبسبب هذا، ستحتاج غالبًا لوضع علامة على حقول طلبك "الاختيارية" كقيمة nullable
إن لم تُرد أن يعتبر المحقّق القيم null
غير صالحة. على سبيل المثال:
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
نُحدّد في هذا المثال أن الحقل publish_at
يكون إما ذو قيمة null
أو تاريخ صالح. إن لم يُضف المُحدّد nullable
لتعريف القاعدة، سيعتبر المُدقّق القيمة null
غير صالحة.
طلبات وتحقّق AJAX
في هذا المثال استخدمنا نموذجًا تقليديًا لإرسال البيانات إلى التطبيق. ولكن العديد من التطبيقات تستخدم طلبات AJAX. عند استخدام التابع validate
أثناء طلب AJAX ، لن يُولّد Laravel استجابة إعادة توجيه. بدلاً من ذلك، يُولّد Laravel استجابة JSON تحتوي على جميع أخطاء التحقق من الصحة. ستُرسل هذه الاستجابة JSON برمز حالة HTTP 422.
التحقّق من صحّة طلب استمارة
إنشاء طلبات الاستمارة
قد ترغب في إنشاء "طلب استمارة" من أجل سيناريوهات التحقق الأكثر تعقيدًا. طلبات الاستمارات هي أصناف طلبات مخصّصة تحتوي على منطق التحقق من الصحة. لإنشاء صنف طلب استمارة، استخدم الأمر make:request
Artisan CLI:
php artisan make:request StoreBlogPost
سيوضع الصنف المُنشئ في المُجلّد app/Http/Requests
. إن لم يوجد هذا الدليل، سيُنشأ عند تنفيذ الأمر make:request
. فلنضف بعض قواعد التحقق إلى التابع rules
:
/**
* احصل على قواعد التحقق من الصحة التي تنطبق على الطلب.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
ملاحظة: تستطيع كتابة أي تلميح على النوع تحتاج إليه ضمن توقيع التابع rules
. سيُستبان تلقائيًا عبر حاوي خدمات Laravel.
كيف إذن تُقيّم قواعد التحّقق؟ كل ما عليك فعله هو التلميح على نوع الطلب في تابع وحدة تحكّمك. يُتحقّق من صحّة طلب الالاستمارة الوارد قبل مناداة تابع وحدة التحكّم ممّا يعني أنه لا حاجة لكركبة وحدة تحكّمك بأي منطق للتحقّق من الصحة:
/**
* تخزين منشور المدونة الوارد.
*
* @param StoreBlogPost $request
* @return Response
*/
public function store(StoreBlogPost $request)
{
// الطلب الوارد صالح...
// جلب بيانات الإدخال الصالحة ...
$validated = $request->validated();
}
في حالة فشل التحقّق من الصحّة، ستُولّد استجابة إعادة توجيه لإعادة إرسال المستخدم لموقعه السابق. كما ستُموّض (flash) الأخطاء للجلسة كي تكون متاحة للعرض. إن كان الطلب طلب AJAX، ستُردّ استجابة HTTP برمز الحالة 422 للمستخدم بما في ذلك تمثيل JSON لأخطاء التحقق من الصحة.
إضافة خطافات لاحقة إلى طلبات النموذج (Adding After Hooks To Form Requests)
إن رغبت في إضافة خطاف "لاحق" إلى طلب نموذج، تستطيع استخدام التابع withValidator
. يستقبل هذا التابع أداة التحقق المبنية بالكامل ممّا يسمح لك بمناداة أي من توابعها قبل تقييم قواعد التحقق من الصحة:
/**
* إعداد نسخة المُحقّق
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
}
تخويل طلبات الاستمارة (Authorizing Form Requests)
يحتوي صنف طلب الاستمارة أيضًا على تابع authorize. تستطيع التحقق ضمن هذا التابع ما إذا امتلك المستخدم المصادق عليه فعلًا سلطة تحديث مورد معيّن. يمكنك على سبيل المثال، تحديد ما إذا كان المستخدم يملك بالفعل تعليق مدوّنة يحاول تحديثه:
/**
* حدد ما إذا كان المستخدم مخولًا لعمل هذا الطلب.
*
* @return bool
*/
public function authorize()
{
$comment = Comment::find($this->route('comment'));
return $comment && $this->user()->can('update', $comment);
}
نظرًا لأن جميع طلبات الاستمارات تُوسّع صنف طلب Laravel الأساسي، نستطيع استخدام التابع user
للوصول إلى المستخدم المصادق عليه حاليًا. لاحظ أيضًا مناداة التابع route
في المثال أعلاه. يمنحك هذا التابع إمكانيّة الوصول إلى معاملات URI المحدّدة في المسار المُنادى، مثل المعامل {comment} في المثال التالي:
Route::post('comment/{comment}');
إن ردّ التابع authorize
القيمة false، ستُردّ استجابة HTTP مع رمز حالة 403 تلقائيًّا ولن يُنفّذ تابع وحدة تحكّمك.
إذا كنت تخطط لوضع منطق تخويل (authorization logic) في جزء آخر من تطبيقك، عليك رد القيمة true
من التابع authorize
:
/**
* حدد إذا كان المستخدم مخولًا لعمل هذا الطلب أو لا.
*
* @return bool
*/
public function authorize()
{
return true;
}
ملاحظة: تستطيع كتابة أي تلميح على النوع تحتاج إليه ضمن توقيع التابع authorize
. ستُستبان تلقائيًا عبر حاوي خدمات Laravel.
تخصيص رسائل الخطأ
يمكنك تخصيص رسائل الخطأ المستخدمة من طرف طلب الاستمارة عن طريق إعادة تعريف التابع messages
. يجب أن يردّ هذا التابع مصفوفة من أزواج خاصيّة / قاعدة ورسائل الخطأ المطابقة لها:
/**
* احصل على رسائل خطأ قواعد التحقق المُعرّفة .
*
* @return array
*/
public function messages()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
إنشاء مُتحقّقي الصحّة يدويًّا (Manually Creating Validators)
إن لم ترغب باستخدام التابع validate في الطلب، تستطيع إنشاء نسخة من متحقّق الصحّة يدويًا باستخدام واجهة Validator الساكنة. يُولّد التابع make في الواجهة الساكنة نسخة مُتحقّق جديدة:
<?php
namespace App\Http\Controllers;
use Validator;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* تخزين مشاركة مدوّنة جديدة.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
return redirect('post/create')
->withErrors($validator)
->withInput();
}
// Store the blog post...
}
}
أوّل مُتغيّر وسيط يمرّر إلى التابع make
هو البيانات تحت التحقّق من الصحة. المتغيّر الوسيط الثاني هو قواعد التحقق التي يجب تطبيقها على البيانات.
بعد فحص فشل التحقّق من صحة الطلب، تستطيع استخدام التابع withErrors
لتمويض رسائل الخطأ للجلسة. عند استخدام هذا التابع، سيُشارك المتغيّر $errors
تلقائيًا مع واجهاتك بعد إعادة التوجيه ممّا يسمح لك بعرضها بسهولة على المستخدم. يقبل التابع withErrors
مُتحقّق و MessageBag
أو array (مصفوفة) PHP.
إعادة التوجيه التلقائيّة
إن رغبت في إنشاء نسخة مُتحقّق يدويًا مع الاستفادة من إعادة التوجيه التلقائية التي يقّدمها تابع الطلبات validate
، تستطيع مناداة التابع validate
على نسخة مُتحقّق موجودة. سيُعاد توجيه المستخدم تلقائيًا إذا فشل التحقق من الصحّة أو في حالة طلب AJAX ستُرد استجابة JSON:
Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
])->validate();
حقائب الأخطاء المسمّاة (Named Error Bags)
قد ترغب في تسمية MessageBag
من الأخطاء إن امتلكت عدّة استمارات على صفحة واحدة، ممّا يسمح لك باسترداد رسائل الخطأ الخاصة باستمارة معيّنة. مرّر اسمًا ما كالمتغيّر الوسيط الثاني إلى withErrors
:
return redirect('register')
->withErrors($validator, 'login');
يمكنك بعدها الوصول إلى نسخة MessageBag
المسمّاة من المتغيّر errors$
:
{{ $errors->login->first('email') }}
خطاف التحقق من الصحة اللاحق (After Validation Hook)
يسمح لك المُتحقّق أيضًا بإرفاق ردود نداء للتشغيل بعد إكمال التحقق. يتيح لك هذا إجراء المزيد من التحقق بسهولة وإضافة المزيد من رسائل الخطأ لمجموعة الرسائل. استخدم التابع after للبدء على نسخة مُتحقّق من الصحة:
$validator = Validator::make(...);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
if ($validator->fails()) {
//
}
التعامل مع رسائل الخطأ
ستحصل، بعد مناداة التابع errors
على نسخة Validator
على نسخة Illuminate\Support\MessageBag
والتي تحتوي على مجموعة متنوّعة من التوابع الملائمة للعمل مع رسائل الخطأ. يمثّل أيضًا المتغيّر $errors
المتاح تلقائيًّا لجميع الواجهات نسخة من الصنف MessageBag
.
استرداد أول رسالة خطأ بالحقل (Retrieving The First Error Message For A Field)
استخدم التابع first
لاسترداد أول رسالة خطأ لحقل معيّن:
$errors = $validator->errors();
echo $errors->first('email');
استخدم التابع get
إن أردت استرداد مصفوفة تحتوي جميع رسائل حقل معين:
foreach ($errors->get('email') as $message) {
//
}
إن كنت تتحقق من حقل مصفوفة بالاستمارة، تستطيع استرداد جميع الرسائل لكل عنصر من عناصر المصفوفة على حدة باستخدام الحرف *
:
foreach ($errors->get('attachments.*') as $message) {
//
}
التحقق من وجود الرسائل بالحقل
يمكن استخدام التابع has
للتأكّد من وجود أي رسائل خطأ بحقل معيّن:
if ($errors->has('email')) {
//
}
رسائل الخطأ المخصّصة
تستطيع عند اللزوم استخدام رسائل خطأ مخصّصة للتحقق من الصحة بدلًا من الرسائل الافتراضية. توجد عدّة طرق لتحديد الرسائل المخصّصة. أولًا، تستطيع تمرير الرسائل المخصّصة كالمتغيّر الوسيط الثالث للتابع Validator::make
:
$messages = [
'required' => 'The :attribute field is required.',
];
$validator = Validator::make($input, $rules, $messages);
سيُستبدل في هذا المثال النص البديل (placeholder) المسمّى attribute: بالاسم الفعلي للحقل تحت التحقق. يمكنك أيضًا الاستفادة من النصوص البديلة (place-holder) الأخرى في رسائل التحقق من الصحة. على سبيل المثال:
$messages = [
'same' => 'The :attribute and :other must match.',
'size' => 'The :attribute must be exactly :size.',
'between' => 'The :attribute value :input is not between :min - :max.',
'in' => 'The :attribute must be one of the following types: :values',
];
تحديد رسالة مخصّصة لخاصيّة معيّنة
قد ترغب أحيانًا في تحديد رسائل خطأ مخصّصة لحقل معيّن فقط. تستطيع استخدام التدوين "نقطة". حدّد أولًا اسم الخاصيّة، متبوعًا بالقاعدة:
$messages = [
'email.required' => 'We need to know your e-mail address!',
];
تحديد الرسائل المخصّصة في ملفات اللغة
في معظم الحالات، ستُحدّد غالبًا رسائلك المخصّصة في ملف لغة بدلًا من تمريرها مباشرة إلى المتحقّق Validator
. أضف رسائلك إلى المصفوفة custom
في ملف اللغة resources/lang/xx/validation.php
.
'custom' => [
'email' => [
'required' => 'We need to know your e-mail address!',
],
],
تحديد خاصيّات مخصّصة في ملفات اللغة
إن رغبت في استبدال الجزء attribute:
من رسالة تحقّقك باسم خاصيّة مخصصة تستطيع تحديد الاسم المخصص في المصفوفة attributes
لملف لغتك resources/lang/xx/validation.php
:
'attributes' => [
'email' => 'email address',
],
قواعد التحقّق المتاحة
تجد أدناه قائمة بجميع قواعد التحقق المُتوفّرة ووظيفتها:
Accepted
Active URL
After (Date)
After Or Equal (Date)
Alpha
Alpha Dash
Alpha Numeric
Array
Bail
Before (Date)
Before Or Equal (Date)
Between
Boolean
Confirmed
Date
Date Equals
Date Format
Different Digits
Digits Between
Dimensions (Image Files)
Distinct E-Mail
Exists (Database)
File
Filled
Greater Than
Greater Than Or Equal
Image (File)
In
In Array
Integer
IP Address
JSON
Less Than
Less Than Or Equal
Max
MIME Types
MIME Type By File Extension
Min
Not In
Not Regex
Nullable
Numeric
Present
Regular Expression
Required
Required If
Required Unless
Required With
Required With All
Required Without
Required Without All
Same
Size
String
Timezone
Unique (Database)
URL