تطوير تطبيق إدارة المهام Todo – 3


بناء الواجهات والعروض

 

هذ التطبيق يحوي على واجهة واحدة فقط والتي تحتوي على نموذج لإضافة مهام جديدة بالإضافة إلى سرد المهام الموجودة بشكل مسبق في تطبيقنا ولمساعدة توضيح هذا الأمر بشكل رسومي في الأسفل سترى كيف هو شكل هذا العرض عندما نتهي منه مع إستخدامنا لمكتبة Bootstrap

app-main-view

تعريف الواجهة

 

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

كما ناقشنا سابقا فإن لارافيل تقوم بتخزين جميع العروض في المجلد resources/views 

وبالتالي دعونا نعرف واجهة جديدة أو عرض جديد تحت المسار والمسمى
resources/views/layouts/app.blade.php


الإمتداد
blade.php    يُعلم إطار العمل على لزوم استخدام محرك القوالب Blade لتصيير العرض، بالطبع يمكنك استخدام قوالب PHPعادية مع لارافيل! ولكن بليد Balde يزود شفرات مختصرة لكتابة قوالب نظيفة.

العرض app.blade.php   يجب أن يكون محتواه كالتالي:

 

// resources/views/layouts/app.blade.php

<!DOCTYPE html>

<html lang="en">

<head>
      <title>Laravel Quickstart - Basic</title>

      <!-- CSS And JavaScript -->

</head>

<body>
      <div class="container">

            <nav class="navbar navbar-default">

                  <!-- Navbar Contents -->

            </nav>
      </div>

      @yield('content')

</body>

</html>

 

لاحظ الجزئية @yield    هذه تعليمة خاصة بمحرك Blade والتي تساعده على  تحديد جميع الصفحات التي ستقوم بوراثة هذا القالب الأب أي تمكن لهذه الصفحات الوريثة من حقن محتواهم الخاص، وبالتالي دعونا نقوم  بتعريف واجهة وريثة (ابن) تقوم بإستخدام القالب الأساسي (الأب) وبحقن محتواها الأساسي تماماً مكان هذه التعليمة المذكورة في الأعلى.

تعريف عرض وريث (ابن)

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

resources/views/tasks.blade.php

سنقوم هنا بتخطي بعض الأمور المتعلقة بالبنية المسبقة التي تأتي مع  Bootstrap CSS   وبالمقابل سنقوم بالتركيز على الأمور الأهم ، وتذكر أنه يمكنك تحميل شفرة المصدر للتطبيق هذا بشكل كامل من المستودع الخاص بها على الـ GitHub.

 

// resources/views/tasks.blade.php

@extends('layouts.app')

@section('content')

    <!-- Bootstrap Boilerplate... -->

    <div class="panel-body">
        <!-- Display Validation Errors -->
        @include('common.errors')

        <!-- New Task Form -->
        <form action="/task" method="POST" class="form-horizontal">
            {{ csrf_field() }}

            <!-- Task Name -->
            <div class="form-group">
                <label for="task" class="col-sm-3 control-label">Task</label>

                <div class="col-sm-6">
                    <input type="text" name="name" id="task-name" class="form-control">
                </div>
            </div>

            <!-- Add Task Button -->
            <div class="form-group">
                <div class="col-sm-offset-3 col-sm-6">
                    <button type="submit" class="btn btn-default">
                        <i class="fa fa-plus"></i> Add Task
                    </button>
                </div>
            </div>
        </form>
    </div>

    <!-- TODO: Current Tasks -->
@endsection

 

بعض الشروحات

قبل أن نكمل في تطوير تطبيقنا دعونا نتحدث قليلاً عن القالب المسرود في الأعلى، أولاً الأمر @extends   يقوم بإطلاع لارافيل على أننا نستخدم الواجهة المعرفة في

resources/views/layouts/app.blade.php


جميع المحتوى المحصور مابين

@section(‘content’)  و @endsection 

سيتم حقنه (إستبداله) في السطر

@yield(‘contents’)

الموجود في الواجهة

app.blade.php


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

laravelme.app/

 

 كما هو موضح:

 

Route::get('/', function () {

      return view('tasks');

});

 

نحن الأن جاهزون لإضافة إرسال طلب من نوع بوست POST على الرابط

laravelme.app/task

 

ليقوم بإستلام الطلبات القادمة  من نموذج اللإضافة والتي هي حقول الإدخال الموجودة بنموذج الإضافة Inputs وبالتالي إضافة مهمة جديدة على قاعدة البيانات

ملاحظة: السطر 

@include('common.errors')

 

سيقوم بإضافة محتوى القالب الموجود في


resources/views/common/errors.blade.php


لم نقم بعد بتعريف محتوى هذا القالب! ولكن سنقوم بالخطوات القليلة القادمة 🙂

إضافة مهام

المصادقة:
الآن نحن نملك نموذج في عرضنا ونحتاج إلى إضافة شفرات إلى إرسال طلب من نوع POST على الرابط

laravelme.app/task

 

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

laravelme.com/

 

وسنقوم بإسناد القيم القديمة للدخل مع الخطأ داخل محتول الجلسة Session:

Route::post('/task', function (Request $request) {
    $validator = Validator::make($request->all(), [
        'name' => 'required|max:255',
    ]);

    if ($validator->fails()) {
        return redirect('/')
            ->withInput()
            ->withErrors($validator);
    }

    // Create The Task...
});

 

متحول الأخطاء Errors

لنأخذ فاصلاً منشطاً نتحدث فيه عن الجزئية

->withErrors($validator);

إستعدعاء لهذه التعليمة ( هذا الـ Function ) سيقوم بحقن الأخطاء القادمة من المُصادق Validador إلى متحول الجلسة Session لنتمكن في العرض View من الوصول إليهم عبر المتحول $errors  .

الآن دعونا نتذكر سويتاً أننا قمنا بإستخدام التعليمة

@include(‘common.errors’)

 

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

 

// resources/views/common/errors.blade.php

@if (count($errors) > 0)
    <!-- Form Error List -->
    <div class="alert alert-danger">
        <strong>Whoops! Something went wrong!</strong>

        <br><br>

        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

 

لاحظ أنه من الممكن الوصول إلى  المتحول $errors  في جميع عروض Views تطبيقنا ببساطة هو عبارة عن مشتق Instance لـ ViewErrorBag في حال عدم وجود أية أخطاء خلال عملية المصادقة

إنشاء مهمة جديدة

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

laravelme.app/

 

 

لإنشاء المهمة الجديدة ( تخزينها في قاعدة البيانات ). لإنشائها يمكننا إستخدام الدالة save على كائن إلكونت Eloquent مباشرة بعد ضبط خصائصه ليكون الناتج كالتالي:

Route::post('/task', function (Request $request) {
    $validator = Validator::make($request->all(), [
        'name' => 'required|max:255',
    ]);

    if ($validator->fails()) {
        return redirect('/')
            ->withInput()
            ->withErrors($validator);
    }

    $task = new Task;
    $task->name = $request->name;
    $task->save();

    return redirect('/');
});

 

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

عرض المهام الموجودة

أولاً نحتاج إلى تحرير المسار

laravelme.app/

لتمرير جميع المهام الموجودة مسبقاً إلى العرض View ، بكل سهولة الدالة view()  تأخذ قيمة إضافية غير الاولى ( اسم ملف العرض ذو الإمتداد Blade) والتي هي عبارة عن مصفوفة من البيانات التي ستكون متاحة للإستخدام في العرض View بحيث كل مفتاح في هذه المصفوفة سيكون عبارة عن متحول في العرض View .
وبالتالي شكل ملف المسارات سيكون كما يلي:

 

Route::get('/', function () {
    $tasks = Task::orderBy('created_at', 'asc')->get();

    return view('tasks', [
        'tasks' => $tasks
    ]);
});

 

حالما يتم تمرير البيانات للعرض نستطيع المرور على هذه المهام وعرضها داخل جدول html table في ملف العرض tasks.blade.php 

التعليمة @foreach تتيح لنا كتابة حلقات موجزة التي تتحول بدورها إلى شفرات بي اتش بي عادية أي plain PHP، وبالتالي يكون الناتج:

@extends('layouts.app')

@section('content')
    <!-- Create Task Form... -->

    <!-- Current Tasks -->
    @if (count($tasks) > 0)
        <div class="panel panel-default">
            <div class="panel-heading">
                Current Tasks
            </div>

            <div class="panel-body">
                <table class="table table-striped task-table">

                    <!-- Table Headings -->
                    <thead>
                        <th>Task</th>
                        <th>&nbsp;</th>
                    </thead>

                    <!-- Table Body -->
                    <tbody>
                        @foreach ($tasks as $task)
                            <tr>
                                <!-- Task Name -->
                                <td class="table-text">
                                    <div>{{ $task->name }}</div>
                                </td>

                                <td>
                                    <!-- TODO: Delete Button -->
                                </td>
                            </tr>
                        @endforeach
                    </tbody>
                </table>
            </div>
        </div>
    @endif
@endsection

 

تطبيقنا شارف على الإنتهاء ولكن! لا نملك طريقة لحذف المهام عندما ننتهي من تنفيذها.

حذف المهام

 

إضافة زر الحذف


لقد قمنا بإدراج سطر مهمة للتنفيذ لاحقاً TODO في الأسطر المسرودة في الأعلى، في حال كنت تستخدم محرر نصوص محترم مثل PhpStorm فستلاحظ أنه أخذ هذه كمهمة ووضعها لك في مكانها المخصص كما تم تغير لون الخط للدلالة على أنك تحتاج للعودة لهذا المكان وإكمال عملك.

ولإكمال عملنا يجب علينا وضع شفرات لزر الحذف مكان المهمة TODO ، دعونا نضيف زر لكل سطر من سرد المهام الموجود في ملف العرضtasks.blade.php . سنقوم بإنشاء زر لكل مهمة من القائمة، عند الضغط عليه سنقوم بإرسال طلب حذف DELETE إلى الرابط

 

laravelme.app/task

 

<tr>
    <!-- Task Name -->
    <td class="table-text">
        <div>{{ $task->name }}</div>
    </td>

    <!-- Delete Button -->
    <td>
        <form action="/task/{{ $task->id }}" method="POST">
            {{ csrf_field() }}
            {{ method_field('DELETE') }}

            <button>Delete Task</button>
        </form>
    </td>
</tr>

 

ملاحظة حول التحايل في المسارات

لاحظ أن الطريقة المختارة في نموذج زر الحذف هي Post ، علماً اننا نقوم بالرد على الطلب بإستخدام رابط Route::delete 

وهذا يعود إلى أنّ نماذج HTML تسمح فقط للنوعين GET و  POST كمتحولات ترسل عبر بروتوكول HTTP وبالتالي احتجنا لطريقة لنحتال ونستخدم نوع حذف لطلب نموذج الحذف.

نستطيع الإحتيال على طلب الحذف عن طريق عرض ناتج الدالة

 method_field(‘DELETE')

 

داخل نموذجنا، هذه الدالة تقوم بتوليد دخل خفي للنموذج Hidden input والذي تقوم لارافيل بالتعرف عليه والذي سيستخدم كتجاوز على الطلب الأساسي والذي هو HTTP POST.
الناتج المولد يكون على هذا الشكل ( في حال أحببت عدم استخدام الدالة في الأعلى ، استخدم الناتج التالي )

<input type="hidden" name="_method" value=“DELETE">

حذف المهمة

وأخيراً! دعونا نضيف المنطق إلى مسارنا لنقوم فعلياً بحذف المهمة المختارة، يمكننا استخدام الدالة الخاصة بإلكونت  findOrFail  لجلب  المودل المطلوب عبر رقمه التسلسلي ID وستقوم هذه الدالة برمي استثناء 404 في حال عدم وجود المودل المطلوب. حالما يأتينا المودل سنستخدم دالة الحذف Delete  عليه ليتم حذفه كسجل من جدول المهام في قاعدة البيانات، حالما يتم الحذف سنقوم بإعادة توجيه المستخدم للوراء إلى جذر التطبيق، للرابط 

laravelme.app/

 

Route::delete('/task/{id}', function ($id) {
    Task::findOrFail($id)->delete();

    return redirect('/');
});

 

لقد انتهينا، هنيئاً لكم على إكمال هذه القراءة

هذا التعليم جزء من مستندات لارافيل، تمت ترجمته بعد موافقة تايلور آوت ويل

أخوكم محمد قوصرة