استخدام الاستثناءات Exceptions المخصصة في Laravel


محمد أحمد العيل

يستخدم Laravel الصنف Handler الموجود على المسار app/Exceptions للتعامل مع جميع الاستثناءات. يحوي هذا الصّنف دالتين: report وrender. تُستخدَم دالة report لتسجيل الاستثناءات أو إرسالها إلى خدمة خارجية؛ أما الدالة render فتُستخدَم لاعتراض الاستثناءات وإرسال إجابة مناسبة إلى المتصفّح ليعرضها للزّائر.

laravel-custom-exceptions.png

ملحوظة: اعتمدنا العروض، المسارات والمتحكّم الذي أنشأناه في درس كيف تستخدم PHPUnit لاختبار تطبيقات Laravel وبنينا عليها لتطبيق الخطوات الواردة هنا. يمكنك تجربة الدّرس على مشروعك الخاص أو استخدام الملفّ المرفَق الذي يمثّل الحصيلة النهائية لهذا الدرس. إن استخدمت الملفّ المرفق فستحتاج لتسجيل مستخدم أولا عبر رابط register والدخول إلى الموقع حتى يظهر بقية المحتوى (سنترك لك اكتشاف الآلية المستخدمة في ذلك. كلمة السّر: المسارات المحميّة).

تخصيص رسائل الاستثناءات

يُعدّ ErrorException أحد أكثر الاستثناءات انتشارا ويظهر مثلا عند إضافة معرف كائن غير موجود إلى مسار URL، أو عند طلب خاصيّة غير موجودة في الكائن. عند محاولة دخول المسار التالي دون أن تكون التسجيلة ذات المعرّف 56 موجودة في جدول البيانات widgets:

laravel.dev/widget/56

فستظهر في المتصفّح صفحة خطأ كالتالي:

01_ErrorException.png

صفحة الخطأ هذه مفيدة للمطوّرين إلا أننا لا نرغب في أن يراها زوار الموقع؛ لذا يجب علينا التعامل مع هذا الاستثناء وقت حدوثه وعرض رسالة مغايرة للزائر.

نعدّل دالة render في ملف Handler.php لتصبِح على النحو التالي:

public function render($request, Exception $e)
    {
        switch($e){

            case ($e instanceof ErrorException):

                return $this->ErrorException($e);
                break

            default:

                return parent::render($request, $e);

    }
}

ثم نضيف الدالة التالية إلى الملف:

protected function renderErrorException($e)
    {
        return response()->view('errors.404', [], 404);/*
    }

يمكنك أن تلاحظ أننا أضفنا عبارة switch إلى الدالة من أجل تحديد نوعيّة الاستثناء فإن كان من نوع ErrorException استدعينا الدالة renderErrorException وإلا نترك الدالة المبدئية تتكفّل بالموضوع. استخدمنا عبارة switch هنا لتسهيل إضافة معالَجات خاصّة في ما بعد لأنواع أخرى من الاستثناءات.

نستخدم في الدالة renderErrorException عرضا خاصّا سميناه 404. يحوي مجلد العروض في Laravel مجلّدا خاصّا لعروض الأخطاء errors؛ ننشئ فيه العرض 404 ذي المحتوى التالي مع إضافة اللاحقة blade.php.:

@extends('layouts.app')

@section('content')

<div class="alert alert-danger alert-dismissible alert-important" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<strong>Oh Snap!</strong> We can't find what you are looking for...
</div>

@endsection

بقي لنا استيراد صنف الاستثناءات ErrorException في ملف Handler.php

use ErrorException;

هذا كل ما نحتاجه. نعود الآن لنرى الرابط السابق:

laravel.dev/widget/56

إن لم يكن الكائن ذو المعرّف موجودا فستظهر رسالة الخطأ التالية:

02_ErrorException.png

تخصيص الاستثناءات

استخدمنا في الفقرة السابقة استثناءً موجودا وخصّصنا النتيجة التي يعرضها للزائر. نريد في هذه الفقرة إنشاء استثناء مخصَّص لتلبية حاجة خاصّة بمشروعنا. سنفرض مثلا أننا نريد إظهار رسالة خطأ للزائر عند تصفّح الرابط /create/widget/، سنسمّي الاستثناء الجديد WidgetCreateException.

نبدأ بإنشاء ملف WidgetCreateException.php في المجلّد Exceptions:

<?php

namespace App\Exceptions;

class WidgetCreateException extends \Exception
{


}

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

نعود للملف Handler.php ونعدّله باستيراد الصّنف الذي أنشأناه للتّو:

use App\Exceptions\WidgetCreateException;

ثم نعدّل دالّة render كالتالي:

public function render($request, Exception $e)
    {
            switch($e)
            {

            case ($e instanceof ErrorException):

                return $this->renderErrorException($e);
                break;

            case ($e instanceof WidgetCreateException):

                return $this->renderWidgetCreateException($e);
                break;

            default:

                return parent::render($request, $e);

        }
    }

ونضيف أيضا الدالة التالية:

protected function renderWidgetCreateException($e)
    {
            return response()->view('errors.widgetcreate', [], 404);
    }

يعني هذا أنه في حالة ظهور استثناء من نوع WidgetCreateException فسنستدعي الدالة renderWidgetCreateException التي تُظهر العرض widgetcreate.

بقي لنا الآن إنشاء ملف العرض widgetcreate.blade.php في المجلّد errors التابع لمجلد العروض:

@extends('layouts.app')

@section('content')

<div class="alert alert-danger alert-dismissible alert-important" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<strong>Yes!</strong> You threw a Widget Creation Exception...
</div>

@endsection

سننشئ لتجربة صنف الاستثناء الجديد داالةً في المتحكّم المناسب (HomeController في حالتي) كما يلي:

public function create()
{
    throw new WidgetCreateException;
}

لا تنس استيراد الصنف WidgetCreateException في المتحكم: 

use App\Exceptions\WidgetCreateException;

وإضافة مسار لـ/create/widget في ملف routes.php:

Route::group(['middleware' => 'web'], function () {
    Route::auth();

    Route::get('/create/widget', 'HomeController@create');
});

نجرّب عمل الاستثناء بزيارة المسار التالي:

http://laranew.dev/create/widget

لاحظ النتيجة:

03_WidgetCreationException.png

قدّمنا في هذا المقال أساسيات تخصيص الاستثناءات في Laravel؛ ما زال يوجد الكثير لتعلمّه في هذا الإطار انطلاقا من هذه الأساسيات.

حمل الملف المرفق لهذا الدرس.

ترجمة -وبتصرّف- للمقال Handling Exceptions and Custom Exceptions in Laravel 5.1 لصاحبه Bill Keck.



1 شخص أعجب بهذا


تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن