اذهب إلى المحتوى

إنشاء تطبيق Todo List بسيط باستخدام Laravel 5 - الجزء الثالث


هشام رزق الله

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

laravel5-todo-app.thumb.png.d151d8c381e3

إضافة روابط التصفح

قبل أن نفعل أي شيء، سنقوم بإضافة روابط create/edit/delete/back إلى صفحات المشاريع والمهام:

<!-- /resources/views/projects/index.blade.php -->
@extends('app')

@section('content')
    <h2>Projects</h2>

    @if ( !$projects->count() )
        You have no projects
    @else
        <ul>
            @foreach( $projects as $project )
                <li>
                    {!! Form::open(array('class' => 'form-inline', 'method' => 'DELETE', 'route' => array('projects.destroy', $project->slug))) !!}
                        <a href="{{ route('projects.show', $project->slug) }}">{{ $project->name }}</a>
                        (
                            {!! link_to_route('projects.edit', 'Edit', array($project->slug), array('class' => 'btn btn-info')) !!},
                            {!! Form::submit('Delete', array('class' => 'btn btn-danger')) !!}
                        )
                    {!! Form::close() !!}
                </li>
            @endforeach
        </ul>
    @endif

    <p>
        {!! link_to_route('projects.create', 'Create Project') !!}
    </p>
@endsection

<!-- /resources/views/projects/show.blade.php -->
@extends('app')

@section('content')
    <h2>{{ $project->name }}</h2>

    @if ( !$project->tasks->count() )
        Your project has no tasks.
    @else
        <ul>
            @foreach( $project->tasks as $task )
                <li>
                    {!! Form::open(array('class' => 'form-inline', 'method' => 'DELETE', 'route' => array('projects.tasks.destroy', $project->slug, $task->slug))) !!}
                        <a href="{{ route('projects.tasks.show', [$project->slug, $task->slug]) }}">{{ $task->name }}</a>
                        (
                            {!! link_to_route('projects.tasks.edit', 'Edit', array($project->slug, $task->slug), array('class' => 'btn btn-info')) !!},

                            {!! Form::submit('Delete', array('class' => 'btn btn-danger')) !!}
                        )
                    {!! Form::close() !!}
                </li>
            @endforeach
        </ul>
    @endif

    <p>
        {!! link_to_route('projects.index', 'Back to Projects') !!} |
        {!! link_to_route('projects.tasks.create', 'Create Task', $project->slug) !!}
    </p>
@endsection

هذه الشفرة البرمجية مفهومة، الصعوبة تكمن في رابط الحذف، متحكِّمات الموارد تتطلب إرسال وظيفة HTTP DELETE، وهذا لا يمكن أن يتم مع رابط عادي، لذلك يتطلب نموذج يتم تقديمه إلى طريق route محدد. للمزيد من المعلومات قُم بزيارة إجراءات يتم التحكم بها عن طريق متحكِّمات الموارد.

إنشاء صفحات الإضافة والتعديل

بعد الانتهاء من صفحات عرض قائمة المشاريع، نحتاج إلى إمكانية إضافة وحذف المشاريع والمهام. استمارات الإضافة والحذف ستكون متشابهة كثيرا، لذلك بدلا من تكرارهم، سنقوم بوراثتهم من نموذج واحد.

سوف نبدأ مع عروض create/edit للمشروع:

<!-- /resources/views/projects/create.blade.php -->
@extends('app')

@section('content')
    <h2>Create Project</h2>

    {!! Form::model(new App\Project, ['route' => ['projects.store']]) !!}
        @include('projects/partials/_form', ['submit_text' => 'Create Project'])
    {!! Form::close() !!}
@endsection

<!-- /resources/views/projects/edit.blade.php -->
@extends('app')

@section('content')
    <h2>Edit Project</h2>

    {!! Form::model($project, ['method' => 'PATCH', 'route' => ['projects.update', $project->slug]]) !!}
        @include('projects/partials/_form', ['submit_text' => 'Edit Project'])
    {!! Form::close() !!}
@endsection

قُم بعمل نفس الشيء مع المهام لكن لا تنسَ تحديث الطرق (routes):

<!-- /resources/views/tasks/create.blade.php -->
@extends('app')

@section('content')
    <h2>Create Task for Project "{{ $project->name }}"</h2>

    {!! Form::model(new App\Task, ['route' => ['projects.tasks.store', $project->slug], 'class'=>'']) !!}
        @include('tasks/partials/_form', ['submit_text' => 'Create Task'])
    {!! Form::close() !!}
@endsection

<!-- /resources/views/tasks/edit.blade.php -->
@extends('app')

@section('content')
    <h2>Edit Task "{{ $task->name }}"</h2>

    {!! Form::model($task, ['method' => 'PATCH', 'route' => ['projects.tasks.update', $project->slug, $task->slug]]) !!}
        @include('tasks/partials/_form', ['submit_text' => 'Edit Task'])
    {!! Form::close() !!}
@endsection

الآن توجد عدة مفاهيم جديدة:

إضافة جزئية

الاستمارة تتطلب عدة وسوم، وبدلا من ذلك سنقوم بتقسيمها من جزئية _form ونضعها مباشرة في العرض، استمارة Add هي من نوع POST ترسل البيانات إلى طريق projects.store واستمارة Edit هي من نوع PATCH وترسل البيانات إلى projects.update. قد يبدوا هذا معقدا ومبهم لكن هذه هي الطريقة التي تعمل بها المتحكِّمات.

لاحظ أننا استخدمنا ()Form::model، وتسمى هذه نموذج الاستمارة الملزمة و ليس لدى هذه أهمية كبيرة الآن، فهي تُستخدم للتعبئة التلقائية وسوف نحتاجها في وقت لاحقا عندما نضيف الحقول باستخدام ()Form::input.

الحماية من CSRF:

مساعدي الاستمارة (Form helpers) توفر العديد من الوظائف مجانا، فإذا ذهبت إلى projects/create/ ورأيت مصدر الصفحة ستجد شيئا مشابها لهذا:

<form method="POST" action="http://l4todo.localhost.com/projects" accept-charset="UTF-8">
    <input name="_token" type="hidden" value="Y8uOo7SeD5tQZExezDf5a7UwiYR4P6qIHEUKJNxI">
</form>

هل ترى حقل token_ ؟ هذا هو الرمز المميز لـ CSRF مُنشئ تِلقائيا بواسطة استدعاء {{ ()Form::model }} الذي يمنع ثغرة CSRF. يكفي أن نقول أن هذا شيئ مفيد وأننا لم نقم بأي شيئ للحصول عليه.

إنشاء استمارة التعديل

نحن بحاجة إلى ترميز (markup) الاستمارة للمشاريع والمهام، وبفضل نموذج الاستمارة الملزمة يمكننا فقط استخدام مساعدي الاستمارة في Laravel لإخراج كافة الحقول التي نحتاجها.

<!-- /resources/views/projects/partials/_form.blade.php -->
<div class="form-group">
    {!! Form::label('name', 'Name:') !!}
    {!! Form::text('name') !!}
</div>
<div class="form-group">
    {!! Form::label('slug', 'Slug:') !!}
    {!! Form::text('slug') !!}
</div>
<div class="form-group">
    {!! Form::submit($submit_text, ['class'=>'btn primary']) !!}
</div>


<!-- /resources/views/tasks/partials/_form.blade.php -->
<div class="form-group">
    {!! Form::label('name', 'Name:') !!}
    {!! Form::text('name') !!}
</div>

<div class="form-group">
    {!! Form::label('slug', 'Slug:') !!}
    {!! Form::text('slug') !!}
</div>

<div class="form-group">
    {!! Form::label('completed', 'Completed:') !!}
    {!! Form::checkbox('completed') !!}
</div>

<div class="form-group">
    {!! Form::label('description', 'Description:') !!}
    {!! Form::textarea('description') !!}
</div>

<div class="form-group">
    {!! Form::submit($submit_text) !!}
</div>

هذا كل شيئ، سوف تستطيع الأن التصفح في صفحات الإضافة والتعديل، الأمر كان سهلا للغاية.

جعل الاستمارات تعمل

لدينا استمارات الإضافة والتعديل للمشروع و المهام، بالإضافة إلى استمارة مُضللة لحذفهم، الآن يجب علينا أن نجعلهم يعملون لأداء مهامهم.

أولا، أضف هذا في أعلى المتحكِّمات:

use Input;
use Redirect;

والآن لوظائف store و update و destroy:

// ProjectsController
public function store()
{
    $input = Input::all();
    Project::create( $input );

    return Redirect::route('projects.index')
                          ->with('message', 'Project created');
}

public function update(Project $project)
{
    $input = array_except(Input::all(), '_method');
    $project->update($input);

    return Redirect::route('projects.show', $project->slug)
                          ->with('message', 'Project updated.');
}

public function destroy(Project $project)
{
    $project->delete();

    return Redirect::route('projects.index')->with('message', 'Project deleted.');
}

// TasksController
public function store(Project $project)
{
    $input = Input::all();
    $input['project_id'] = $project->id;
    Task::create( $input );

    return Redirect::route('projects.show', $project->slug)
                          ->with('message', 'Task created.');
}

public function update(Project $project, Task $task)
{
    $input = array_except(Input::all(), '_method');
    $task->update($input);

    return Redirect::route('projects.tasks.show', [$project->slug, $task->slug])
                          ->with('message', 'Task updated.');
}

public function destroy(Project $project, Task $task)
{
    $task->delete();

    return Redirect::route('projects.show', $project->slug)->with('message', 'Task deleted.');
}

الشفرة البرمجية في الأعلى مفهومة ولا داعي لشرحها.
إذا قمت الآن بتقديم إحدى الاستمارات فسوف تحصل على خطأ MassAssignmentException: _token، فالإحالة الكتلية تحدث عندما تقوم بتمرير مصفوفة بيانات إلى ()Model::create أو ()Model::update من المتحكِّمات بدل من وضع حقل واحد في نفس الوقت، ولإصلاح هذا، قم ببساطة بإضافة خاصية guarded إلى كل نموذج.

class Project extends Model {

    protected $guarded = [];


class Task extends Model {

    protected $guarded = [];

رسائل الفلاش

سوف تلاحظ من الشفرة السابقة أننا استخدمنا دالة ()with، وهذه الدالة تقوم بتمرير متغير فلاش (يستخدم لمرة واحدة) للجلسة session والتي يمكن قراءتها عند تحميل الصفحة التالية.
والآن نحتاج إلى التأكد من تلك الرسالة وعرضها على المستخدم. قُم بفتح resources/views/app.blade.php/ وأضف التالي:

...

<div class="content">
    @if (Session::has('message'))       
       <div class="flash alert-info">          
         <p>{{ Session::get('message') }}</p>        
       </div>  
    @endif 
    
    @yield('content')
</div>

...

حاول إنشاء مشروع، هذه الرسالة ستظهر مهما حدّثت الصفحة وستذهب بعد فترة.

خاتمة

اليوم قمنا بأشياء مثيرة للغاية، فلقد أضفنا استمارات الإضافة والتعديل والحذف وتعلمنا حول CSRF و نموذج الاستمارة الملزمة بالإضافة إلى تعلمنا المزيد حول blade و الدوال.
كل شيئ الآن يعمل، يمكن تجربة التطبيق وإنشاء وتعديل وحذف المهام والمشاريع، وفي أي وقت يمكنك كتابة الأمر:

php artisan migrate:refresh –seed 

وسوف يتم إعادة تعيين قواعد البيانات.
في المرحلة القادمة والتي ستكون النهائية سوف نقوم بالتحقق من الاستمارات.

ترجمة -وبتصرّف- للمقال Creating a Basic ToDo Application in Laravel 5 – Part 3.

حقوق الصورة البارزة: Designed by Freepik.


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

أفضل التعليقات

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



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...