Physical Address

304 North Cardinal St.
Dorchester Center, MA 02124

كيفية إنشاء CRUD في Laravel 11

دليل شامل لإنشاء أول مشروع Laravel


1. تثبيت Laravel

قبل ما نبدأ، لازمك تتأكد من الأمور التالية:

  • PHP 8.0 أو أكثر
  • Composer (مدير الحزم الخاص بـ PHP)
  • خادم محلي (مثل XAMPP أو Laragon)

تثبيت Laravel:

  1. افتح الـ Terminal أو Command Prompt.

  2. استخدم الأمر التالي لإنشاء مشروع Laravel جديد:

Bash
composer create-project laravel/laravel membership

  • membership هو اسم المشروع، يمكنك تغييره حسب الحاجة.

بعد التثبيت، انتقل إلى مجلد المشروع:

Bash
cd membership 

قم بتشغيل الخادم الداخلي الخاص بـ Laravel:

Bash
php artisan serve

ستجد أن المشروع يعمل على الرابط: http://127.0.0.1:8000.

2. إعداد قاعدة البيانات

    1. قم بإنشاء قاعدة بيانات جديدة باستخدام MySQL (عبر phpMyAdmin أو أي أداة أخرى).

    1. افتح ملف env. في مجلد المشروع، وعدّل إعدادات قاعدة البيانات:

.env
PHP
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=membership
DB_USERNAME=root
DB_PASSWORD=

DB_DATABASE: اسم قاعدة البيانات التي أنشأتها.

DB_USERNAME و DB_PASSWORD: حسب إعدادات الخادم المحلي.

3. إنشاء جدول في قاعدة البيانات

  1. قم بإنشاء Migration لإنشاء جدول الأعضاء

Bash
php artisan make:migration create_members_table

افتح ملف Migration الذي تم إنشاؤه في database/migrations وأضف الأكواد التالية:

create_members_table.php
PHP
public function up(): void
{
    Schema::create('members', function (Blueprint $table) {
        $table->id();
        $table->string('first_name');
        $table->string('last_name');
        $table->string('picture')->nullable();
        $table->string('email')->unique();
        $table->string('phone_number')->nullable();
        $table->date('join_date');
        $table->boolean('status')->default(true);
        $table->timestamps();
    });
}

نفذ أمر الترحيل لتحديث قاعدة البيانات:

Bash
php artisan migrate

4. إعداد النموذج (Model)

  1. أنشئ نموذجًا لجدول الأعضاء:
Bash
php artisan make:model Member

افتح ملف النموذج في app/Models/Member.php وأضف الحقول المسموحة:

Member.php
PHP
protected $fillable = [
    'first_name', 'last_name', 'picture', 'email', 'phone_number', 'join_date', 'status'
];

5. إعداد Controller والمسارات (Routes)

  1. أنشئ Controller لإدارة CRUD:

    5.1 المسار الأول: عرض جميع الأعضاء (Index Route)

Bash
php artisan make:controller MembersController

في ملف routes/web.php، أضف المسارات:

web.php
PHP
Route::get('/members', [MembersController::class, 'index'])->name('members.index');

الدالة في Controller:

MembersController.php
PHP
public function index()
{
    $members = Members::all(); // جلب جميع الأعضاء
    return view('members.index', compact('members')); // عرض البيانات في الصفحة
}

عادةً في Laravel، يتم استخدام القالب العام (Layout) في جميع الصفحات بحيث يحتوي على هيكل مشترك (مثل الـ header والـ footer) لجميع الصفحات. لذلك، في البداية سنقوم بإنشاء صفحة القالب العام (layout) التي تحتوي على الهيكل المشترك، وبعد ذلك سنقوم بإنشاء صفحة index.blade.php التي ستقوم بتمديد هذا القالب العام لعرض المحتوى الخاص بالصفحة.

الواجهة (View): في ملف resources/views/members/layout.blade.php:

layout.blade.php
PHP
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=
    , initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>aplication members</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
    
    <div class="container mt-5 ">
        <div class="row">
            <div class="col-md-6">
                <h1> @yield('title') </h1>
            </div>
        </div>


        @yield('content')


    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>
الواجهة (View): في ملف resources/views/members/index.blade.php:
index.blade.php
PHP
@extends('members.layout')
@section('title', 'Member List')

@section('content')

<a href="{{ route('members.create') }}" class="btn btn-primary">add new member</a>

<table class="table">
    <thead>
        <tr>
            <th scope="col">ID</th>
            <th scope="col">Picture</th>
            <th scope="col">First Name</th>
            <th scope="col">Last Name</th>
            <th scope="col">Email</th>
            <th scope="col">Phone number</th>
            <th scope="col">Join Date</th>
            <th scope="col">Status</th>
            <th scope="col">Action</th>
        </tr>
    </thead>
    <tbody>
        @foreach ($members as $member)
            <tr>
                <th scope="row">{{ $member->id }}</th>
                <td>
                    @if ($member->picture)
                        <img src="{{ asset('storage/' . $member->picture) }}" style="max-width: 50px">
                    @endif
                </td>
                <td>{{ $member->first_name }}</td>
                <td>{{ $member->last_name }}</td>
                <td>{{ $member->email }}</td>
                <td>{{ $member->phone_number }}</td>
                <td>{{ $member->join_date }}</td>
                <td>{{ $member->status }}</td>
                <td>
                    <a href="{{ route('members.show', $member->id) }}" class="btn btn-info">view</a>
                    <a href="{{ route('members.edit', $member->id) }}" class="btn btn-warning">Edit</a>
                    <form action="{{ route('members.destroy', $member->id) }}" method="POST" style="display: inline">
                        @csrf
                        @method('DELETE')
                        <button type="submit" class="btn btn-danger"
                            onclick="return confirm ('Are you Sure you want delete this member')"> Delete </button>
                    </form>
                </td>
            </tr>
        @endforeach
    </tbody>
</table>
</div>


@endsection

3. شرح الكود: layout & index

  • @extends('layouts.app'): هذه هي السطر الذي يربط الواجهة بالقالب العام. في هذه الحالة، نستخدم القالب layouts.app، ويمكنك تخصيصه بناءً على اسم القالب الذي تستخدمه في المشروع. عادة ما يكون هذا القالب في resources/views/layouts/app.blade.php.

  • @section('content'): هذا القسم يعبر عن محتوى الصفحة الذي سيحل محل العلامة @yield('content') في القالب العام. هنا يمكنك إضافة أي محتوى مخصص للصفحة.

5.2 المسار الثاني: إنشاء عضو جديد (Create Route)

web.php
PHP
Route::get('/members/create', [MembersController::class, 'create'])->name('members.create');

الدالة في Controller:

MembersController.php
PHP
public function create()
{
    return view('members.create'); // عرض صفحة إضافة عضو جديد
}

الواجهة (View): في ملف resources/views/members/create.blade.php

MembersController.php
PHP
@extends('members.layout')
@section('title','Add Members' )

@section('content')

        @if ($errors->any())
            <div class="alert alert-danger">
                <ul>
                    @foreach ($errors->all() as $error)
                        <li>{{ $error }}</li>
                    @endforeach
                </ul>
            </div>
        @endif

        <form action="{{ route('members.store') }}" method="POST" enctype="multipart/form-data">
            @csrf
            <div class="mb-3">
                <label for="first_name" class="form-label">first name: </label>
                <input type="text" name="first_name" class="form-control" id="first_name">
            </div>
            <div class="mb-3">
                <label for="last_name" class="form-label">last name: </label>
                <input type="text" name="last_name" class="form-control" id="last_name">
            </div>
            <div class="mb-3">
                <label for="email" class="form-label">Email: </label>
                <input type="email" name="email" class="form-control" id="email">
            </div>
            <div class="mb-3">
                <label for="phone_number" class="form-label">Phone number: </label>
                <input type="text" name="phone_number" class="form-control" id="phone_number">
            </div>
            <div class="mb-3">
                <label for="join_date" class="form-label">join date: </label>
                <input type="date" name="join_date" class="form-control" id="join_date">
            </div>
            <div class="mb-3">
                <label for="status" class="form-label">Status: </label>
                <input type="text" name="status" class="form-control" id="status">
            </div>
            <div class="mb-3">
                <label for="picture" class="form-label">picture: </label>
                <input type="file" name="picture" class="form-control" id="picture">
            </div>

            <button type="submit" class="btn btn-primary">Submit</button>
            <a href="{{ route('members.index') }}" class="btn btn-secondary">Back to list</a>
        </form>


    </div>




@endsection

5.3 المسار الثالث: تخزين عضو جديد (Store Route)

web.php
PHP
Route::post('/members', [MembersController::class, 'store'])->name('members.store');

الدالة في Controller:

MembersController.php
PHP
 public function store(Request $request)
    {
        // validate data 

        $request->validate([
            'first_name' => 'required|string|max:255',
            'last_name' => 'required|string|max:255',
            'email' => 'required|email|max:255',
            'join_date' => 'required|date',
            'phone_number' => 'nullable|string|max:8',
            'picture' => 'nullable|image|mimes:jpeg,png,jpeg,gif|max:2048',
        ]);

        $existingemail = Members::where('email',$request->email)->first();
        if($existingemail){

            return redirect()->back()->withErrors(['email'=>'this email mawjoud']);
        }

        // create new member

        $member = new Members();
        $member->first_name = $request->first_name;
        $member->last_name = $request->last_name;
        $member->email = $request->email;
        $member->phone_number = $request->phone_number;
        $member->join_date = $request->join_date;

        // Handle picture upload
        if ($request->hasFile('picture')) {
            $path = $request->file('picture')->store('pictures', 'public');
            $member->picture = $path;
        } else {
            $member->picture = 'pictures/no-photo.png'; // Path relative to 'public/storage'
        }

        $member->save(); // Save the member to the database
        return redirect()->route('members.index');
        //Redirect to the index
    }

الواجهة (View): الواجهة التي تم إنشاؤها في الخطوة السابقة (create.blade.php) سيتم استخدامها في هذه الحالة. بعد التعديل، عند إرسال النموذج سيتم إرسال البيانات إلى مسار members.store عبر طلب post.

5.4 المسار الرابع: عرض عضو معين (Show Route)

 

web.php
PHP
Route::get('/members/{id}', [MembersController::class, 'show'])->name('members.show');

الدالة في Controller:

MembersController.php
PHP
public function show($id)
{
    $member = Members::findOrFail($id); // البحث عن العضو باستخدام المعرف أو إظهار خطأ 404
    return view('members.show', compact('member')); // عرض بيانات العضو في الصفحة
}

الواجهة (View):   أنشئ الملف resources/views/members/show.blade.php:

show.blade.php
PHP
@extends('members.layout')
@section('title', 'Show MemberById')
@section('content')
    <div class="container mt-5">
        <div class="d-flex justify-content-center align-items-center">
            <div class="card" style="width: 18rem;">
                @if($member->picture)
                <img src="{{asset('storage/'. $member->picture)}}" class="card-img-top" alt="...">
                @endif
                <div class="card-body">
                   <p><strong>first name : </strong>{{ $member->first_name }}</p>
                   <p><strong>last name : </strong>{{ $member->last_name }}</p>
                   <p><strong>email : </strong>{{ $member->email }}</p>
                   <p><strong>phone number : </strong>{{ $member->phone_number }}</p>
                   <p><strong>join date : </strong>{{ $member->join_date }}</p>
                   <p><strong>status : </strong>{{ $member->status }}</p>
                   <a href="{{route('members.edit',$member->id)}}" class="btn btn-warning">Edit</a>
                   <a href="{{route ('members.index')}}" class="btn btn-danger">back to list member</a>
                </div>
            </div>
        </div>
    </div>
 

    @endsection

شرح المسار الرابع (Show Route):

  • عندما يزور المستخدم المسار /members/{id}، يتم تنفيذ الدالة show.
  • يتم استخدام findOrFail للبحث عن العضو بناءً على معرفه (ID). إذا لم يتم العثور عليه، سيتم عرض صفحة خطأ 404 تلقائيًا.
  • تُرسل بيانات العضو إلى صفحة العرض show.blade.php باستخدام compact.

5.5 المسار الخامس: تعديل عضو (Edit Route)

web.php
PHP
Route::get('/members/{id}/edit', [MembersController::class, 'edit'])->name('members.edit');
الدالة في Controller:
MembersController.php
PHP
public function edit($id)
{
    $member = Members::findOrFail($id); // البحث عن العضو باستخدام المعرف أو إظهار خطأ 404
    return view('members.edit', compact('member')); // عرض البيانات في صفحة التعديل
}

5.6 المسار السادس: تحديث عضو (Update Route)

 

web.php
PHP
Route::put('/members/{id}', [MembersController::class, 'update'])->name('members.update');

الدالة في Controller:

MembersController.php
PHP
public function update(Request $request, $id)
{
    $member = Members::findOrFail($id); // البحث عن العضو باستخدام المعرف أو إظهار خطأ 404

    // التحقق من صحة البيانات المدخلة
    $request->validate([
        'first_name' => 'required|string|max:255',
        'last_name' => 'required|string|max:255',
        'email' => 'required|email|max:255,' . $member->id,
        'join_date' => 'required|date',
        'phone_number' => 'nullable|string|max:8',
        'picture' => 'nullable|image|mimes:jpeg,png,jpeg,gif|max:2048',
    ]);

    // تحديث بيانات العضو
    $member->first_name = $request->first_name;
    $member->last_name = $request->last_name;
    $member->email = $request->email;
    $member->phone_number = $request->phone_number;
    $member->join_date = $request->join_date;
    $member->status = $request->status;

    // التحقق إذا كانت الصورة جديدة قد تم تحميلها
    if ($request->hasFile('picture')) {
        // حفظ الصورة الجديدة
        $member->picture = $request->file('picture')->store('pictures', 'public');
    }

    $member->save(); // حفظ التعديلات

    return redirect()->route('members.index'); // إعادة التوجيه إلى صفحة الأعضاء
}

الواجهة (View): الواجهة التي تم إنشاؤها في الخطوة السابقة (edit.blade.php) سيتم استخدامها في هذه الحالة. بعد التعديل، عند إرسال النموذج سيتم إرسال البيانات إلى مسار members.update عبر طلب PUT.

edit.blade.php
PHP
@extends('members.layout')
@section('title', 'Show MemberById')
@section('content')
    <div class="container mt-5">
        <div class="d-flex justify-content-center align-items-center">
            <div class="card" style="width: 18rem;">
                @if($member->picture)
                <img src="{{asset('storage/'. $member->picture)}}" class="card-img-top" alt="...">
                @endif
                <div class="card-body">
                   <p><strong>first name : </strong>{{ $member->first_name }}</p>
                   <p><strong>last name : </strong>{{ $member->last_name }}</p>
                   <p><strong>email : </strong>{{ $member->email }}</p>
                   <p><strong>phone number : </strong>{{ $member->phone_number }}</p>
                   <p><strong>join date : </strong>{{ $member->join_date }}</p>
                   <p><strong>status : </strong>{{ $member->status }}</p>
                   <a href="{{route('members.edit',$member->id)}}" class="btn btn-warning">Edit</a>
                   <a href="{{route ('members.index')}}" class="btn btn-danger">back to list member</a>
                </div>
            </div>
        </div>
    </div>
 

    @endsection

5.7 المسار السابع: حذف عضو (Delete Route)

 

web.php
PHP
Route::delete('/members/{id}', [MembersController::class, 'destroy'])->name('members.destroy');
الدالة في Controller:
MembersController.php
PHP
public function destroy($id)
{
    $member = Members::findOrFail($id); // البحث عن العضو باستخدام المعرف أو إظهار خطأ 404

    // التحقق إذا كانت هناك صورة للعضو وحذفها من التخزين
    if ($member->picture && $member->picture !== 'pictures/no-photo.png') {
        Storage::disk('public')->delete($member->picture); // حذف الصورة من مجلد التخزين
    }

    // حذف العضو من قاعدة البيانات
    $member->delete();

    return redirect()->route('members.index'); // إعادة التوجيه إلى صفحة الأعضاء
}

الواجهة (View): في هذه الحالة، لا نحتاج إلى واجهة خاصة لعملية الحذف، ولكن يمكننا إضافة زر الحذف في صفحة عرض الأعضاء أو قائمة الأعضاء. مثلاً:
any view you want
PHP
<form action="{{ route('members.destroy', $member->id) }}" method="POST">
    @csrf
    @method('DELETE')
    <button type="submit">حذف</button>
</form>

الختام

لقد أكملنا الآن إنشاء CRUD للأعضاء باستخدام Laravel:

  1. مسار عرض قائمة الأعضاء: يتم عرض جميع الأعضاء.
  2. مسار إضافة عضو جديد: يتم إضافة عضو جديد.
  3. مسار عرض تفاصيل عضو معين: يتم عرض تفاصيل العضو عند النقر عليه.
  4. مسار تعديل عضو: يتم تعديل بيانات العضو.
  5. مسار حذف عضو: يتم حذف العضو.

في الختام، إذا كنت ترغب في متابعة المزيد من التفاصيل حول كيفية بناء مشروع CRUD باستخدام Laravel، يمكنك زيارة الروابط التالية:

  1. دورة الفيديو التعليمية على YouTube:
    CRUD Laravel – YouTube Playlist

  2. المشروع على GitHub:
    CRUD Laravel – GitHub Repository

نتمنى أن تكون قد استفدت من هذا المقال، ولا تتردد في متابعة الروابط لتطوير مهاراتك أكثر في Laravel!

Amor boudabbous
Amor boudabbous
المقالات: 21