اكتشف إطار PHP Laravel


الدرس: الموارد (2/2) والأخطاء


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

مدير البيانات (مستودع repository)


لقد رأينا أننا نحقن مدير بيانات في وحدة التحكم بالإضافة إلى فئتي التحقق من الصحة:

<?php
public function __construct(UserRepository $userRepository)
{
    $this->userRepository = $userRepository;
}
هذا المدير مسؤول عن جميع الإجراءات على مستوى جدول المستخدم. هنا هو الكود ( app/Repositories/UserRepository.php) :

<?php

namespace App\Repositories;

use App\User;

class UserRepository
{

    protected $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    private function save(User $user, Array $inputs)
    {
        $user->name = $inputs['name'];
        $user->email = $inputs['email'];    
        $user->admin = isset($inputs['admin']); 

        $user->save();
    }

    public function getPaginate($n)
    {
        return $this->user->paginate($n);
    }

    public function store(Array $inputs)
    {
        $user = new $this->user;        
        $user->password = bcrypt($inputs['password']);

        $this->save($user, $inputs);

        return $user;
    }

    public function getById($id)
    {
        return $this->user->findOrFail($id);
    }

    public function update($id, Array $inputs)
    {
        $this->save($this->getById($id), $inputs);
    }

    public function destroy($id)
    {
        $this->getById($id)->delete();
    }

}
لذلك يجب أن ينتهي بك الأمر مع هذا الملف في المجلد Repositories :
framework Laravel MVC
ملف للإدارة
سنقوم الآن بتحليل مختلف أعمالها.
getPaginate
تحتوي هذه الطريقة على سطر واحد فقط:

<?php
public function getPaginate($n)
{
    return $this->user->paginate($n);
}
يطلق عليه من طريقة index تحكم:

<?php
public function index()
{
    $users = $this->userRepository->getPaginate($this->nbrPerPage);
    $links = $users->render();

    return view('index', compact('users', 'links'));
}
تستجيب هذه الطريقة إلى عنوان url للنوع (مع الفعل get ) :

http://monsite.fr/user
نستخدم الطريقة paginate للمُجسم و التي تسمح لنا بأخذ جزء فقط من السجلات لعمل ترقيم الصفحات. لقد قدمت هنا القيمة 4 (المخزنة في الخاصية $nbrPerPage )، لذلك 4 سجلات لكل صفحة. إذا نظرت إلى استعلامات SQL التي تم إنشاؤها ، فستجد:

select count(*) as aggregate from `users`
select * from `users` limit 4 offset 0
يتم استخدام الاستعلام الأول لمعرفة العدد الإجمالي للسجلات في جدول المستخدمين (البيانات المطلوبة لحساب ترقيم الصفحات) والثاني لتحديد الأربعة الأولى لعرضها على الصفحة الأولى. من الواضح بالنسبة للصفحة 2 سيكون لدينا الطلب:

select * from `users` limit 4 offset 4
دائمًا 4 سجلات ولكن مع إزاحة 4 لأخذ السجلات الأربعة التالية. سيكون عنوان url بعد ذلك:

    .../user?page=2
بمجرد استرداد السجلات من الجدول ، يتم إرجاعها إلى وحدة التحكم. هذا يحولهم في شكل جدول مع مفتاح "users" . سيتم استخدام هذا الجدول بواسطة العرض كما سنرى قريبًا.
يتم تضمين ترقيم الصفحات في المتغير   $links ليتم إرساله أيضًا في العرض.
getById
تحتوي هذه الطريقة على سطر واحد فقط:

<?php
public function getById($id)
{
    return $this->user->findOrFail($id);
}
 تحاول الطريقة findOrFail  استرداد السجل id الذي يتم تمرير بياناته من الجدول  . إذا فشل ، فإنه يولد خطأ وقت التشغيل.
الخطأ الذي تم إنشاؤه هو  ModelNotFoundException . سنرى قريبا كيف نتعامل مع الأخطاء.
إليك نوع الاستعلام الذي تم إنشاؤه:

select * from `users` where `id` = '2' limit 1
في وحدة التحكم لدينا طريقتين التي تستخدم getById .
show
هنا طريقة  show في وحدة التحكم:

<?php
public function show($id)
{
    $user = $this->userRepository->getById($id);

    return view('show',  compact('user'));
}
تستجيب هذه الطريقة إلى عنوان url (مع الحصول على الفعل) :

http://monsite.fr/user/n
حيث n هو معرف المستخدم الذي نريد عرضه.
بمجرد استرداد السجل من الجدول ، يتم إرجاعه في شكل صفيف بمفتاح "user" . سيتم استخدام هذا الجدول بواسطة العرض ، كما سنرى قريبًا.
edit
 يتم استخدام الطريقة  getById أيضًا بواسطة طريقة   editفي وحدة التحكم. تستجيب هذه الطريقة إلى عنوان url (مع الحصول على الفعل) :
http://monsite.fr/user/n/edit
حيث n هو معرف المستخدم الذي نريد تعديله.
يحتوي فقط على سطرين:

<?php
public function edit($id)
{
    $user = $this->userRepository->getById($id);

    return view('edit',  compact('user'));
}
المبدأ هو بالضبط نفس الأسلوب   show الموضح أعلاه.
update
تهدف هذه الطريقة إلى تحديث السجل في الجدول من البيانات المنقولة كمُدخلات:

<?php
public function update($id, Array $inputs)
{
    $this->save($this->getById($id), $inputs);
}
نقوم باستعادة التسجيل باستخدام الطريقة التي getById ينتقل بها المعرف. ثم نقوم بالتحديث في الجدول بطريقة خاصة save :

<?php
private function save(User $user, Array $inputs)
{
    $user->name = $inputs['name'];
    $user->email = $inputs['email'];    
    $user->admin = isset($inputs['admin']); 

    $user->save();
}
الطريقة Update للمستودع يقع استدعاءها من الطريقة update في وحدة التحكم:

<?php
public function update(UserUpdateRequest $request, $id)
{
    $this->userRepository->update($id, $request->all());
    
    return redirect('user')->withOk("L'utilisateur " . $request->input('name') . " a été modifié.");
}
تستجيب هذه الطريقة إلى عنوان url (مع الفعل put ) :
http://monsite.fr/user/n
حيث n هو معرف المستخدم الذي نريد تعديله.
store
هنا هو كود لهذه الطريقة:

<?php
public function store(Array $inputs)
{
    $user = new $this->user;        
    $user->password = bcrypt($inputs['password']);

    $this->save($user, $inputs);

    return $user;
}
من أجل الأمان ، يتم هنا ترميز كلمة المرور المدخلة باستخدام المساعد   bcrypt . لذلك لن تكون مكتوبة بشكل واضح في الجدول ولكن في شكل مشفر.
نقوم بإنشاء كائن مستخدم جديد. نحن نملأ السمة   password ونحفظها في الجدول بالطريقة الخاصة   save التي سبق أن رأيناها أعلاه:

<?php
private function save(User $user, Array $inputs)
{
    $user->name = $inputs['name'];
    $user->email = $inputs['email'];    
    $user->admin = isset($inputs['admin']); 

    $user->save();
}
تسمى طريقة المستودع من طريقة store التحكم:
طريقة المستودع يقع استدعاءها من الطريقة  store في وحدة التحكم:

<?php
public function store(UserCreateRequest $request)
{
    $user = $this->userRepository->store($request->all());

    return redirect('user')->withOk("L'utilisateur " . $user->name . " a été créé.");
}
تستجيب هذه الطريقة إلى عنوان url (مع الفعل post ) :

http://monsite.fr/user
destroy
يحتوي فقط على سطر واحد:

<?php
public function destroy($id)
{
    $this->getById($id)->delete();
}
يقع استدعاءها من الطريقة destroy في وحدة تحكم:

<?php
public function destroy($id)
{
    $this->userRepository->destroy($id);

    return redirect()->back();
}
نقوم بحذف سجل باستخدام طريقة delete للمُجسم  . لاحظ إعادة التوجيه في وحدة التحكم مع الطريقة back . وبالتالي فإننا نعيد الطلب الأخير.
تستجيب هذه الطريقة إلى عنوان url (مع الفعل delete ) :

http://monsite.fr/user/n
حيث n هو معرف السجل الذي نريد حذفه.

العرض


الآن دعونا نرى العرض للتفاعل مع العملاء. أنا اعتمدت للعرض نفس الاسم مثل أساليب استدعاء وحدة تحكم لتسهيل الفهم.
القالب template
سيكون لدينا نفس القالب لجميع واجهات العرض views ، وهذا هو القالب الذي استخدمناه في الفصول السابقة:

<!DOCTYPE html>
<html lang="fr">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Mon joli site</title>
        {!! Html::style('https://netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css') !!}
        {!! Html::style('https://netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css') !!}
        <!--[if lt IE 9]>
            { { Html::style('https://oss.maxcdn.com/libs/html5shiv/3.7.2/html5shiv.js') }}
            { { Html::style('https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js') }}
        <![endif]-->
        <style> textarea { resize: none; } </style>
    </head>
    <body>
            </body>
</html>
عرض الفهرس
يهدف هذا العرض إلى عرض قائمة الصفحات المرقّمة للمستخدمين بأزرار حتى يتمكنوا من تنفيذ جميع الإجراءات. فيما يلي كود طريقة العرض هذه:

@extends('template')

@section('contenu')
    <br>
    <div class="col-sm-offset-4 col-sm-4">
        @if(session()->has('ok'))
            <div class="alert alert-success alert-dismissible">{!! session('ok') !!}</div>
        @endif
        <div class="panel panel-primary">
            <div class="panel-heading">
                <h3 class="panel-title">Liste des utilisateurs</h3>
            </div>
            <table class="table">
                <thead>
                    <tr>
                        <th>#</th>
                        <th>Nom</th>
                        <th></th>
                        <th></th>
                        <th></th>
                    </tr>
                </thead>
                <tbody>
                    @foreach ($users as $user)
                        <tr>
                            <td>{!! $user->id !!}</td>
                            <td class="text-primary"><strong>{!! $user->name !!}</strong></td>
                            <td>{!! link_to_route('user.show', 'Voir', [$user->id], ['class' => 'btn btn-success btn-block']) !!}</td>
                            <td>{!! link_to_route('user.edit', 'Modifier', [$user->id], ['class' => 'btn btn-warning btn-block']) !!}</td>
                            <td>
                                {!! Form::open(['method' => 'DELETE', 'route' => ['user.destroy', $user->id]]) !!}
                                    {!! Form::submit('Supprimer', ['class' => 'btn btn-danger btn-block', 'onclick' => 'return confirm(\'Vraiment supprimer cet utilisateur ?\')']) !!}
                                {!! Form::close() !!}
                            </td>
                        </tr>
                    @endforeach
                </tbody>
            </table>
        </div>
        {!! link_to_route('user.create', 'Ajouter un utilisateur', [], ['class' => 'btn btn-info pull-right']) !!}
        {!! $links !!}
    </div>
@endsection
مع هذا الجانب:
framework Laravel MVC
عرض الفهرس
لاحظ أنه لإنشاء الطريقة ،   delete  يجب عليك إنشاء نموذج. 
يختبر العرض أيضًا وجود متغير "ok" في الجلسة ويعرض الرسالة المقابلة في شريط إذا كان هذا هو الحال.
عرض show
يتم   استخدام طريقة   العرض show لعرض ملف مستخدم باسمه وعنوان بريده الإلكتروني وعضويته المحتملة في مجموعة المسؤولين:

@extends('template')

@section('contenu')
    <div class="col-sm-offset-4 col-sm-4">
        <br>
        <div class="panel panel-primary">   
            <div class="panel-heading">Fiche d'utilisateur</div>
            <div class="panel-body"> 
                <p>Nom : { { $user->name }}</p>
                <p>Email : { { $user->email }}</p>
                @if($user->admin == 1)
                    Administrateur
                @endif
            </div>
        </div>              
        <a href="javascript:history.back()" class="btn btn-primary">
            <span class="glyphicon glyphicon-circle-arrow-left"></span> Retour
        </a>
    </div>
@endsection
مع هذا الجانب:
framework Laravel MVC
عرض المعرض
عرض edit
يتم  استخدام طريقة العرض edit   لتعديل مستخدم ، فإنه يعرض نموذجًا:

@extends('template')

@section('contenu')
    <div class="col-sm-offset-4 col-sm-4">
        <br>
        <div class="panel panel-primary">   
            <div class="panel-heading">Modification d'un utilisateur</div>
            <div class="panel-body"> 
                <div class="col-sm-12">
                    {!! Form::model($user, ['route' => ['user.update', $user->id], 'method' => 'put', 'class' => 'form-horizontal panel']) !!}
                    <div class="form-group {!! $errors->has('name') ? 'has-error' : '' !!}">
                        {!! Form::text('name', null, ['class' => 'form-control', 'placeholder' => 'Nom']) !!}
                        {!! $errors->first('name', '<small class="help-block">:message</small>') !!}
                    </div>
                    <div class="form-group {!! $errors->has('email') ? 'has-error' : '' !!}">
                        {!! Form::email('email', null, ['class' => 'form-control', 'placeholder' => 'Email']) !!}
                        {!! $errors->first('email', '<small class="help-block">:message</small>') !!}
                    </div>
                    <div class="form-group">
                        <div class="checkbox">
                            <label>
                                {!! Form::checkbox('admin', 1, null) !!}Administrateur
                            </label>
                        </div>
                    </div>
                        {!! Form::submit('Envoyer', ['class' => 'btn btn-primary pull-right']) !!}
                    {!! Form::close() !!}
                </div>
            </div>
        </div>
        <a href="javascript:history.back()" class="btn btn-primary">
            <span class="glyphicon glyphicon-circle-arrow-left"></span> Retour
        </a>
    </div>
@endsection
مع هذا الجانب:
framework Laravel MVC
عرض edit
لاحظ استخدام:

Form::model
والذي يسمح لك بربط النموذج بالمُجسم ، وبالتالي ملء عناصر التحكم التي لها نفس اسم الحقل في السجل تلقائيًا.
عرض create
يتم استخدام طريقة العرض هذه لعرض النموذج لإنشاء مستخدم ، وهو مماثل تقريبا للتعديل مع كلمة المرور بالإضافة إلى ذلك:

@extends('template')

@section('contenu')
    <div class="col-sm-offset-4 col-sm-4">
        <br>
        <div class="panel panel-primary">   
            <div class="panel-heading">Création d'un utilisateur</div>
            <div class="panel-body"> 
                <div class="col-sm-12">
                    {!! Form::open(['route' => 'user.store', 'class' => 'form-horizontal panel']) !!}   
                    <div class="form-group {!! $errors->has('name') ? 'has-error' : '' !!}">
                        {!! Form::text('name', null, ['class' => 'form-control', 'placeholder' => 'Nom']) !!}
                        {!! $errors->first('name', '<small class="help-block">:message</small>') !!}
                    </div>
                    <div class="form-group {!! $errors->has('email') ? 'has-error' : '' !!}">
                        {!! Form::email('email', null, ['class' => 'form-control', 'placeholder' => 'Email']) !!}
                        {!! $errors->first('email', '<small class="help-block">:message</small>') !!}
                    </div>
                    <div class="form-group {!! $errors->has('password') ? 'has-error' : '' !!}">
                        {!! Form::password('password', ['class' => 'form-control', 'placeholder' => 'Mot de passe']) !!}
                        {!! $errors->first('password', '<small class="help-block">:message</small>') !!}
                    </div>
                    <div class="form-group">
                        {!! Form::password('password_confirmation', ['class' => 'form-control', 'placeholder' => 'Confirmation mot de passe']) !!}
                    </div>
                    <div class="form-group">
                        <div class="checkbox">
                            <label>
                                {!! Form::checkbox('admin', 1, null) !!} Administrateur
                            </label>
                        </div>
                    </div>
                    {!! Form::submit('Envoyer', ['class' => 'btn btn-primary pull-right']) !!}
                    {!! Form::close() !!}
                </div>
            </div>
        </div>
        <a href="javascript:history.back()" class="btn btn-primary">
            <span class="glyphicon glyphicon-circle-arrow-left"></span> Retour
        </a>
    </div>
@endsection
مع هذا الجانب:
framework Laravel MVC
إنشاء عرض
من الواضح مع التحقق النشط:
framework Laravel MVC
التحقق من الصحة في العمل
لقد رأينا في فصل سابق كيفية الحصول على هذه الرسائل
لذلك يجب أن يكون لديك هذه الملفات 5:
framework Laravel MVC
وجهات النظر الخمس للمورد

التفكير في الكود


مستودع أساسي
كودنا يعمل بشكل جيد ، لكن هل هو حقًا يعمل؟ عند إنشاء فئة ، يكون السؤال الجيد هو أن تسأل نفسك ما إذا كان الكود قابلا لإعادة الاستخدام. إذا لاحظنا المستودع الذي تم إنشاؤه للمستخدمين ، فإننا ندرك أنه مستهدف للغاية على المُجسم المعني ، وإذا كان لدينا مورد آخر في التطبيق ، فمن المحتمل جدًا أننا سنستعمل النسخ واللصق ، وهذا وهو دائما مصدر لتكرار الكود والأخطاء. هل من الممكن إنشاء مستودع أساسي للموارد؟ هنا حل:

<?php

namespace App\Repositories;

abstract class ResourceRepository
{

    protected $model;

    public function getPaginate($n)
    {
        return $this->model->paginate($n);
    }

    public function store(Array $inputs)
    {
        return $this->model->create($inputs);
    }

    public function getById($id)
    {
        return $this->model->findOrFail($id);
    }

    public function update($id, Array $inputs)
    {
        $this->getById($id)->update($inputs);
    }

    public function destroy($id)
    {
        $this->getById($id)->delete();
    }

}
من الصعب أن تكون أكثر إيجازاً. العنصر الوحيد الذي سيخبرنا أي مُجسم هو الخاصية $model . من ناحية أخرى ، الباقي مجهول تماما. لذلك سيكون مستودع المستخدمين سهل جدًا في الكتابة:

<?php

namespace App\Repositories;

use App\User;

class UserRepository extends ResourceRepository
{

    public function __construct(User $user)
    {
        $this->model = $user;
    }

}
ومع ذلك ، هناك بعض المخاوف الصغيرة. على سبيل المثال ، رأينا أنه يتعين علينا تشفير كلمة المرور وفعلنا ذلك في المستودع. يمكن أن نثقل كاهل طريقة   store  بها ولكنها ستؤدي إلى كسر الانسجام التام للكود.
المُجسم
حل آخر أكثر أناقة هو توفير "mutator" على مستوى المُجسم. ولكن دعونا نرى بالفعل ما لدينا في هذا المُجسم User  :

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    /**
     * The attributes that are mass assignable.
     *
     * @var  array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var  array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
}
سأعود بمزيد من التفاصيل إلى الميزات المستخدمة عندما نرى المصادقة. في الوقت الحالي ، سنكون مهتمين بالخاصية $fillable . عند إنشاء سجل بالطريقة create الموضحة أعلاه ، هناك مخاطرة أمنية. في الجدول الذي يتم نقله كمُدخل ، عادة ما يكون لدينا الحقول التي نريد تعبئتها فقط. ولكن إذا أرسل زميل صغير ذكي معلومات أخرى ، فمن المحتمل أن يمر إلى الجدول في قاعدة البيانات. لتجنب ذلك ، نقوم في المُجسم بتحديد الحقول التي يمكن تحديثها بهذه الطريقة (نحن نتحدث عن التحديث الشامل) في الخاصية $fillable . نظرًا لأن لدينا الحقل admin يجب ملؤه ، يجب علينا إكمال الجدول:

<?php
protected $fillable = ['name', 'email', 'password', 'admin'];
نريد أيضًا تشفير كلمة المرور. فقط قم بإعداد هذا "mutator" :

<?php
public function setPasswordAttribute($password)
{
    $this->attributes['password'] = bcrypt($password);
}
لذلك في كل مرة نقوم فيها بتعيين السمة   password ، ستنتقل إلى هذه الطريقة وسيكون لدينا تشفير للقيمة.
المراقب
لدينا فقط إدارة مربع الاختيار للإدارة. لا يمكننا حلها كما فعلنا مع كلمة المرور لأننا لا نملك المعلومات دائمًا (يتم إرسال خانة الاختيار فقط إذا تم تحديدها). لذلك سنوفر هذه المعالجة في وحدة التحكم:

<?php

namespace App\Http\Controllers;

use App\Http\Requests\UserCreateRequest;
use App\Http\Requests\UserUpdateRequest;

use App\Repositories\UserRepository;

use Illuminate\Http\Request;

class UserController extends Controller
{

    protected $userRepository;

    protected $nbrPerPage = 4;

    public function __construct(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function index()
    {
        $users = $this->userRepository->getPaginate($this->nbrPerPage);
        $links = $users->render();

        return view('index', compact('users', 'links'));
    }

    public function create()
    {
        return view('create');
    }

    public function store(UserCreateRequest $request)
    {
        $this->setAdmin($request);

        $user = $this->userRepository->store($request->all());

        return redirect('user')->withOk("L'utilisateur " . $user->name . " a été créé.");
    }

    public function show($id)
    {
        $user = $this->userRepository->getById($id);

        return view('show',  compact('user'));
    }

    public function edit($id)
    {
        $user = $this->userRepository->getById($id);

        return view('edit',  compact('user'));
    }

    public function update(UserUpdateRequest $request, $id)
    {
        $this->setAdmin($request);

        $this->userRepository->update($id, $request->all());
        
        return redirect('user')->withOk("L'utilisateur " . $request->input('name') . " a été modifié.");
    }

    public function destroy($id)
    {
        $this->userRepository->destroy($id);

        return redirect()->back();
    }

    private function setAdmin($request)
    {
        if(!$request->has('admin'))
        {
            $request->merge(['admin' => 0]);
        }       
    }

}
الوظيفة الخاصة   setAdmin مسؤولة عن إدارة خانة الاختيار. نختبر أننا لا نملك المفتاح   admin في جدول البيانات ، وإذا كان الأمر كذلك ، فإننا نضيفه باستخدام الطريقة    merge .
والنتيجة هي كود أكثر وضوحًا يسهل إعادة استخدامه وصيانته. يمكننا دفع التفكير على مستوى وحدة التحكم وإنشاء وحدة تحكم أساسية للموارد. يكفي توفير بادئة للعرض والتفكير في الحقن ، ويمكن أن نحصل على شيء أنيق للغاية ، لكنني لن أستمر في هذا التفكير حتى لا أصعّب عليكم هذا الفصل ، الشيء المهم هو فهم المبدأ. من ناحية أخرى ، نصل بسرعة إلى طريق مسدود في تطبيق حقيقي مما يعني غالبًا مضاعفة الاكواد المحددة.

الأخطاء


تعتبر معالجة الأخطاء جزءًا مهمًا من تطوير التطبيق. يقال في بعض الأحيان أنه في هذا المجال يتم الاختلاف بين المحترفين والهواة. ماذا تقدم لنا Laravel في هذا المجال؟
نظرًا لأننا بصدد الوصول إلى البيانات ، فقد تحدث مشكلة في الاتصال بالقاعدة. دعونا نرى ما نحصل عليه إذا توقف MySQL عن الاستجابة ... من خلال تطبيقنا إذا أوقفت خدمة MySQL ثم أطلقنا عنوان url :
http://monsite.fr/user
سأحصل على:
framework Laravel MVC
خطأ بعد إيقاف MySQL
لقد عرضت فقط الجزء العلوي هنا. لا تتعجب من حجم الرسائل الموجودة على صفحة الخطأ ، فعادةً ما تكون سعيدًا بالحصول على كل هذه المعلومات عند حدوث خطأ في التطبيق الخاص بك.
السؤال الأول الذي يمكن أن نطرحه على أنفسنا هو: عرض الأخطاء هذا مثالي لمرحلة التطوير ، لكن من الأفضل في تطبيق على الإنترنت إخفاء كل هذا لسببين واضحين: المستخدم لا يهتم ، من ناحية أخرى ، قد يكون من المفيد لشخص لديه نوايا سيئة وتزويده بمعلومات ثمينة عن أداء البرامج النصية الخاصة بك.
إذا نظرت إلى الملف .env الذي أخبرتك به بالفعل ، ستجد هذا السطر:

APP_DEBUG=true
إذا وضعنا false هنا لنرى الفرق:
framework Laravel MVC
رسالة الخطأ المبسطة Laravel
الآن هي ملخصة أكثر! ولكن بمجرد أن يصبح الأمر ساذجًا للغاية بالنسبة للمستخدم ، وقبل كل شيء ، لا يمنحه أي رابط للوصول إلى صفحة أخرى. يمكنك أيضًا اعتبار أن الرسالة باللغة الإنجليزية غير مناسبة لموقعك. لسوء الحظ ، الصفحة المطابقة هي في الإطار الذي من الواضح أننا لن نتعامل معه!
انظر إلى هذا الملف:
framework Laravel MVC
ملف الخطأ
مع هذا الكود:

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Foundation\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that should not be reported.
     *
     * @var  array
     */
    protected $dontReport = [
        AuthorizationException::class,
        HttpException::class,
        ModelNotFoundException::class,
        ValidationException::class,
    ];

    /**
     * Report or log an exception.
     *
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
     *
     * @param    \Exception  $e
     * @return  void
     */
    public function report(Exception $e)
    {
        return parent::report($e);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param    \Illuminate\Http\Request  $request
     * @param    \Exception  $e
     * @return  \Illuminate\Http\Response
     */
    public function render($request, Exception $e)
    {
        return parent::render($request, $e);
    }
}
تتم معالجة جميع أخطاء وقت التشغيل هنا. نكتشف أن يتم أرشفة كل شيء مع الطريقة   report . ولكن أين هذا الأرشيف؟ البحث في storage/logs، تجد ملف laravel.log . من خلال فتحه ، تجد الأخطاء المؤرشفة بتتبعها. على سبيل المثال في حالتنا لدينا:
[2015-12-28 17:09:42] local.ERROR: exception 'PDOException' with message 'SQLSTATE[HY000] [2002] 
تعذر إنشاء اتصال لأن الكمبيوتر الهدف رفضه صراحة.
من المهم أن يكون هذا النوع من أرشفة الأخطاء في تطبيق الإنتاج.
الحالة المتكررة هي الصفحة غير الموجودة (الخطأ 404):
framework Laravel MVC
خطأ 404
إذا كنا نريد تغيير رسالة Laravel لجعلها تناسب ذوقنا ومكيفة بشكل خاص مع لغتنا ، يجب أن نقدم عرض. على سبيل المثال ( resources/views/errors/404.blade.php) :

@extends('template')

@section('contenu')
    {br>
    {div class="col-sm-offset-4 col-sm-4">
        {div class="panel panel-danger">
            {div class="panel-heading">
                {h3 class="panel-title">Il y a un problème !{/h3>
            {/div>
            {div class="panel-body"> 
                {p>Nous sommes désolés mais la page que vous désirez n'existe pas...{/p>
            {/div>
        {/div>
    {/div>
@endsection
الآن للحصول على عنوان url غير موجودة ، نحصل على:
framework Laravel MVC
عرضنا خطأ 404 مخصص
أعترف أنه أفضل وLaravel ذكي بما فيه الكفاية للحصول على هذا العرض تلقائيًا دون الحاجة إلى أي شيء خاص للقيام به!
لقد رأينا في هذا الفصل أنه عند إيقاف خدمة MySql تقوم بإنشاء خطأ PDOException  . كيفية التقاط هذا الخطأ؟ إليك الحل:

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Foundation\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

class Handler extends ExceptionHandler
{
    ...

    /**
     * Render an exception into an HTTP response.
     *
     * @param    \Illuminate\Http\Request  $request
     * @param    \Exception  $e
     * @return  \Illuminate\Http\Response
     */
    public function render($request, Exception $e)
    {
        if($e instanceof \PDOException)
        {
            return response()->view('errors.pdo', [], 500);
        }
        return parent::render($request, $e);
    }
}
لذلك سوف نعرض صفحة محددة لهذا الخطأ.

في الخلاصة


  • إنشاء مدير (مستودع) مستقل عن وحدة التحكم للوصول إلى البيانات يوفر كودا واضحًا تسهل صيانته واختباره.
  • من المهم التفكير في إعادة استخدام الكود الذي ننشئه.
  • يجب أن تحقق طرق العرض أقصى استفادة من إمكانيات Blade والمساعدين وفئة النموذج لتكون موجزة وقابلة للقراءة.
  • لا ينبغي إهمال معالجة الأخطاء ، يجب عليك إزالة وضع التصحيح على موقع الإنتاج وتقديم رسائل صريحة للمستخدمين بناءً على الخطأ الذي تمت مواجهته.