جدول المحتويات
يمكن تعريف middleware بمثابة بوابة أو جسر بين الطلبات requests والإستجابة response ، فهي بمثابة فلتره للطلبات بحيث تقرر هل يسمح لهذا الطلب أن يحصل على هذه الإستجابة، فهو يشكل طبقة إضافية بين الطلب والإستجابة.
مثال لفرض أن لدينا حارس عمارة middleware ، وأنت طلبت منه الدخول إلى هذه العمارة request ، فهو سيتأكد من أنك أحد السكان أو من السبب لدخول العمارة، بعد التأكد سيقرر هل يسمح لك بالدخول أم لا response.
المثال الأقوى الذي نواجهه في جميع تطبيقاتنا هو auth middleware حيث بعد تسجيل الدخول يقرر middleware هل البيانات صحيحة وإن كانت صحيحة ما هي الصفحة التي سوف تعرض لك.
كما يأتي إطار العمل لارافيل مع بعض middleware المبنية مسبقا، مثل التعامل مع طلبات الإدخال، تحديد حالة الموقع هل هو في وضع الصيانة أم لا.
مؤخرا في أحد التطبيقات التي كنت أعمل عليها، طلب مني العميل أنه في حالة تم زيارة الموقع من أجهزة هاتف فإنه يجب توجيههم إلى نطاق فرعي.
وفي هذه الحالة قمت بإنشاء middlware يتحقق من جهاز المستخدم إذا كان mobile سيتم توجييهه إلى النطاق الفرعي وإذا كان جهاز حاسوب أن يتم توجيهه إلى الموقع مباشرة.
إنشاء middlware بإستخدام أوامر artisan.
php artisan make:middleware MobileRedirect
بعد تنفيذ الأمر أعلاه سيتم إنشاء كلاس باسم MobileRedirect.php في المسار
App/Http/Middleware/MobileRedirect.php
class MobileRedirect { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle(Request $request, Closure $next) { return $next($request); } }
نلاحظ في الكلاس MobileRedirect وهو الـ middleware الذي تم إنشاؤه، أنه يوجد دالة handle وهي بمثابة العمود الفقري، فبداخلها نضع logic الذي نريد إعتماده وهي تقرر أين سيتم توجيه المستخدم.
هنا يوجد أمران يجب فهمهما وهما بمثابة أنواع للـ middlware وهما:
وفي مثالنا هنا سوف نقرأ الطلب هل هو من جهاز محمول وبناءا عليه سوف نظهر الإستجابه وهي إعادة توجيه المستخدم بالتالي سوف نحتاج على before middlware.
إذا سوف يتم التعديل في middlware الذي تم إنشاؤه
namespace App\Http\Middleware; use Closure; class MobileRedirect { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { // check if the request is from mobile device if ($request->mobile == "1") { return redirect('mobile-site-url-goes-here'); } return $next($request); }
ففي المثال أعلاه سوف نتحقق إذا كانت قيمة mobile query string parameter تساوي true فإنه سوف يتم توجيهه للنطاق الفرعي.
نلاحظ أيضا في الدالة أنه تم إستدعاء $next($request) وهو ما سيتم تنفيذه في حالة أن قيمة mobile query string parameter تساوي false إي الذهاب إلى النطاق الحقيقي.
لغاية الأن نحن قمنا بإنشاء middlware وكتابة منطق العمل، لكن لارافيل لا تعلم بوجود هذه middlware، لذلك يجب القيام بتسجيل هذا middlware، ولتسجيله نذهب إلى
App/Http/Kernel.php
protected $middleware = [ // \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Fruitcake\Cors\HandleCors::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ];
كما نرى أن المتغير middlware يحتوي على مصفوفة من middlware المثبة مسبقا، ويتم تنفيذها عند كل طلب في الموقع.
في هذه المصفوفة سيتم إضافة middleware الخاص بنا
protected $middleware = [ \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, \App\Http\Middleware\MobileRedirect::class ];
الأن عند القيام بزيارة الموقع بإستخدام querystring mobile=1
www.test.test/?mobile=1
فإنه سوف يتم تنفيذ middlware الذي تم إنشاؤه، أي توجيهنا إلى subdomain.
الطريقة أعلاه كما قلنا سابقا فإنه سوف يتم تشغيلها عند كل طلب request، لكن ببعض الأحيان نرغب في تشغيل middlware لمسارات محدده، وللقيام بذلك عوضا عن تسجيله في مصفوفة $middleware يتم تسجيله في $routeMiddleware والذي يوجد في نفس المسار
App/Http/Kernel.php
protected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, ];
وهنا يجب أن يتم تسجيل middlware
protected $routeMiddleware = [ 'mobile.redirect'=> \App\Http\Middleware\MobileRedirect::class ]
حيث يمكن إنشاء إسم alias وهو mobile.redirect.
ومن ثم تنفيذ middlware على المسار مباشرة
Route::get('/contact', 'ContactController@index')->middleware('mobile.redirect');
فعند زيارة الرابط
http://www.test.test/contact?mobile=1
هنا سيتم تنفيذ middleware فقط على المسار /contact أما باقي المسارات لن يتم تسجيل middleware عليها.
ماذا لو كان لدي ٥ روابط في الموقع أريد تطبيق middlware عليها هل سوف إقوم بإضافة middleware('mobile.redirect') عليها جميعها؟
Route::get('/contact', [EmailController::class,'index'])->middleware('mobile.redirect'); Route::get('/hellow', [HellowController::class,'index'])->middleware('mobile.redirect'); Route::get('/cats', [CatController::class,'index'])->middleware('mobile.redirect');
بالطبع هذه الطريقة تعمل دون مشاكل لكن يمكن إختصار الكود وإنشاء group يتم تطبيق middlware عليها :
Route::group(['middleware' => 'mobile.redirect'], function () { Route::get('/contact', [EmailController::class, 'index']); Route::get('/hellow', [HellowController::class, 'index']); Route::get('/cats', [CatController::class, 'index']); });
يوجد ثلاث حالات يمكن تطبيق middleware بها على الدوال وهي:
ولتنفيذ ذلك في بداية Controller ننشئ دالة __construct ونضع بها middleware.
public function __construct() { $this->middleware('auth');//apply to all methods. $this->middleware('auth',['only'=>['show']]);//apply just on show method $this->middleware('auth',['except'=>['show']]);//apply to all except show }
php artisan make:middleware MobileRedirect
public function handle($request, Closure $next) { // check if the request is from mobile device if ($request->mobile == "1") { return redirect('mobile-site-url-goes-here'); } return $next($request); }
protected $middleware = [ \App\Http\Middleware\MobileRedirect::class ]; //or protected $routeMiddleware = [ 'mobile.redirect'=> \App\Http\Middleware\MobileRedirect::class ]
protected $middleware = [
\App\Http\Middleware\MobileRedirect::class
];
//or
protected $routeMiddleware = [
'mobile.redirect'=> \App\Http\Middleware\MobileRedirect::class
//or
Route::get('/contact', 'ContactController@index')->middleware('mobile.redirect');
//or
Route::group(['middleware' => 'mobile.redirect'], function () {
Route::get('/contact', [EmailController::class, 'index']);
Route::get('/hellow', [HellowController::class, 'index']);
Route::get('/cats', [CatController::class, 'index']);
});
//or
public function __construct()
{
$this->middleware('auth');//apply to all methods.
$this->middleware('auth',['only'=>['show']]);//apply just on show method
$this->middleware('auth',['except'=>['show']]);//apply to all except show
}
مدونة حضرتك بقت من اهم مراجعي .. شكرا
:
ابداااع
هشام محمد
شرح ممتاز ما شاء الله