Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
قبل ما نبدأ، لازمك تتأكد من الأمور التالية:
افتح الـ Terminal أو Command Prompt.
استخدم الأمر التالي لإنشاء مشروع Laravel جديد:
composer create-project laravel/laravel membership
بعد التثبيت، انتقل إلى مجلد المشروع:
cd membership
قم بتشغيل الخادم الداخلي الخاص بـ Laravel:
php artisan serve
ستجد أن المشروع يعمل على الرابط: http://127.0.0.1:8000
.
env.
في مجلد المشروع، وعدّل إعدادات قاعدة البيانات: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
: حسب إعدادات الخادم المحلي.
php artisan make:migration create_members_table
افتح ملف Migration الذي تم إنشاؤه في database/migrations
وأضف الأكواد التالية:
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();
});
}
نفذ أمر الترحيل لتحديث قاعدة البيانات:
php artisan migrate
php artisan make:model Member
افتح ملف النموذج في app/Models/Member.php
وأضف الحقول المسموحة:
protected $fillable = [
'first_name', 'last_name', 'picture', 'email', 'phone_number', 'join_date', 'status'
];
php artisan make:controller MembersController
في ملف routes/web.php
، أضف المسارات:
Route::get('/members', [MembersController::class, 'index'])->name('members.index');
الدالة في Controller:
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:
<!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>
@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
@extends('layouts.app')
: هذه هي السطر الذي يربط الواجهة بالقالب العام. في هذه الحالة، نستخدم القالب layouts.app
، ويمكنك تخصيصه بناءً على اسم القالب الذي تستخدمه في المشروع. عادة ما يكون هذا القالب في resources/views/layouts/app.blade.php
.
@section('content')
: هذا القسم يعبر عن محتوى الصفحة الذي سيحل محل العلامة @yield('content')
في القالب العام. هنا يمكنك إضافة أي محتوى مخصص للصفحة.
Route::get('/members/create', [MembersController::class, 'create'])->name('members.create');
الدالة في Controller:
public function create()
{
return view('members.create'); // عرض صفحة إضافة عضو جديد
}
الواجهة (View): في ملف resources/views/members/create.blade.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
Route::post('/members', [MembersController::class, 'store'])->name('members.store');
الدالة في Controller:
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.
Route::get('/members/{id}', [MembersController::class, 'show'])->name('members.show');
الدالة في Controller:
public function show($id)
{
$member = Members::findOrFail($id); // البحث عن العضو باستخدام المعرف أو إظهار خطأ 404
return view('members.show', compact('member')); // عرض بيانات العضو في الصفحة
}
الواجهة (View): أنشئ الملف resources/views/members/show.blade.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
/members/{id}
، يتم تنفيذ الدالة show
.findOrFail
للبحث عن العضو بناءً على معرفه (ID). إذا لم يتم العثور عليه، سيتم عرض صفحة خطأ 404 تلقائيًا.show.blade.php
باستخدام compact
.Route::get('/members/{id}/edit', [MembersController::class, 'edit'])->name('members.edit');
public function edit($id)
{
$member = Members::findOrFail($id); // البحث عن العضو باستخدام المعرف أو إظهار خطأ 404
return view('members.edit', compact('member')); // عرض البيانات في صفحة التعديل
}
Route::put('/members/{id}', [MembersController::class, 'update'])->name('members.update');
الدالة في Controller:
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.
@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
Route::delete('/members/{id}', [MembersController::class, 'destroy'])->name('members.destroy');
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'); // إعادة التوجيه إلى صفحة الأعضاء
}
<form action="{{ route('members.destroy', $member->id) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit">حذف</button>
</form>
لقد أكملنا الآن إنشاء CRUD للأعضاء باستخدام Laravel:
في الختام، إذا كنت ترغب في متابعة المزيد من التفاصيل حول كيفية بناء مشروع CRUD باستخدام Laravel، يمكنك زيارة الروابط التالية:
دورة الفيديو التعليمية على YouTube:
CRUD Laravel – YouTube Playlist
المشروع على GitHub:
CRUD Laravel – GitHub Repository
نتمنى أن تكون قد استفدت من هذا المقال، ولا تتردد في متابعة الروابط لتطوير مهاراتك أكثر في Laravel!