الجمعية الشهرية باستخدام لارافيل – الجزء الثاني في الجزء الاول قمنا بانشاء الجمعية واضافة الادوار لها والان سنقوم باضافة الاعضاء وربط الاعضاء بالادوار وتحديد لكل عضو المبلغ الخص بة في كل دور واجمالي مبلغة في الجمعية
الجمعية الشهرية باستخدام لارافيل - الجزء الثاني
انشاء جدول الاعضاء Members
php artisan make:model Member -mrc
المايجريشن migrate
سيرتبط جدول الاعضاء بجدول الجمعيات وجدول الادوار لكن بطريقة غير مباشرة سيكون هناك علاقات بينة وبين جداول pivot لان العلاقات ستكون many to many حيث ان في الجمعية اكثر من عضو وللعضو اكثر من دور ويمكن للعضو ان يدخل في اكثر من جمعية لذا سيكون للعضو جدول منفرد
public function up(): void
{
Schema::create('members', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
// للترحيل
php artisan migrate
الموديل Model
// member model
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Member extends Model
{
protected $fillable = [
'name',
];
}
كونترولر Controller
سوف نضيف الي index , store في MemberController اسماء الاعضاء بالشكل الاتي
use App\Models\Member;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
class MemberController extends Controller
{
public function index()
{
$members = Member::all();
return Inertia::render('Members/Index', [
'members' => $members
]);
}
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'name' => 'required|string|max:255',
]);
$members = Member::create([
'name' => $validated['name'],
]);
return redirect(route('members.index'));
}
التوجهات (الراوت) Routes
//namespace
use App\Http\Controllers\MemberController;
//code
Route::resource('members', MemberController::class)
->middleware(['auth', 'verified']);
الواجهه الامامية لصفحة الاعضاء Members/Index
بظهر في اعلي الصفحة فورم لاضافة الاعضاء وكل عضو يضاف يظهر اسمة تحت الفورم بعرض الصفحة ب fade in
//resources\js\Pages\Members\Index.jsx
import React, { useState } from 'react';
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
import InputError from '@/Components/InputError';
import PrimaryButton from '@/Components/PrimaryButton';
import { useForm, Head, Link } from '@inertiajs/react';
export default function Members ({ auth, members }) {
const { data, setData, post, processing, reset, errors } = useForm({
name: '',
});
const handleSubmit = (e) => {
e.preventDefault();
post(route('members.store'), { onSuccess: () => reset() });
};
return (
{members.map((member, index) => (
{member.name}
))}
بعد ذلك اضافة navlink خاص بصفحة Member مثل صفحة Associations
npm run dev
انشاء الجدول الوسيط AssociationMember
سوف نقوم بانشاء موديل وكنترولر وميجريشن للربط بين الجمعيات و الاعضاء بحيث نحدد لكل عضو الجمعية المشترك فيها واجمالي المبلغ المدفوع باتباع التالي
php artisan make:model AssociationMember -mrc
المايجريشن migrate
سوف يكون الجدول التالي جدول مشترك بين الجمعيات والاعضاء والعلاقة بينهم many to many ليسمح للاعضاء الدخول في اي جمعية والجمعية يكون بها اكثر من عضو ويكون بالشكل التالي
public function up(): void
{
Schema::create('association_member', function (Blueprint $table) {
$table->id();
$table->foreignId('member_id')->constrained()->onDelete('cascade');
$table->foreignId('association_id')->constrained()->onDelete('cascade');
$table->decimal('total_amount', 10, 2); // المبلغ الإجمالي
$table->timestamps();
});
}
ثم ترحيل الجدول لقواعد البيانات باستخدام الامر التالي
php artisan migrate
الموديل Model
من app اختيار Models ثم AssociationMember واضافة الكود التالي
public function association()
{
return $this->belongsTo(Association::class);
}
public function member()
{
return $this->belongsTo(Member::class);
}
من app اختيار Models ثم Association واضافة الكود التالي
public function members()
{
return $this->belongsToMany(Member::class, 'association_member')
->withPivot('id', 'total_amount') // لتضمين عمود 'id' من الجدول الوسيط
->withTimestamps();
}
كونترولر Controller
من app اختيار http ثم controller ثم AssociationController واضافة الكود التالي
use App\Models\Member;
public function storeMemberAssociation(Request $request, Association $association)
{
$validated = $request->validate([
'member_id' => 'required|exists:members,id',
'total_amount' => 'required|numeric|min:0',
]);
if ($association->members()->where('member_id', $validated['member_id'])->exists()) {
return back()->withErrors(['member_id' => 'Member is already part of this group.']);
}
$association->members()->attach($validated['member_id'], ['total_amount' => $validated['total_amount']]);
return redirect()->route('associations.show', $association->id)->with('success', 'Member added to group successfully.');
}
public function show($id)
{
$associations = Association::with(['roles', 'members'])->findOrFail($id);
$roles = Role::all();
$members = Member::all();
return Inertia::render('Associations/Show', [
'associations' => $associations,
'members' => $members,
'roles' => $roles,
]);
}
التوجهات (الراوت) Routes
من routes نذهب الي web واضافة الكود
Route::post('/associations/{association}/members', [AssociationController::class, 'storeMemberAssociation'])->name('associations.members.store');
صفحة اضافة العضو و مبلغة Associations/Show
import React, { useState } from 'react';
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
import InputError from '@/Components/InputError';
import PrimaryButton from '@/Components/PrimaryButton';
import { useForm, Head, Link } from '@inertiajs/react';
export default function Associations ({ auth, associations, members }) {
const { data, setData, post, processing, errors, reset } = useForm({
member_id: '',
total_amount: '',
});
const totalAmount = associations.members.reduce((acc, member) => {
return acc + parseFloat(member.pivot?.total_amount || 0); // تحويل المبلغ إلى رقم
}, 0);
const handleSubmit = (e) => {
e.preventDefault();
post(route('associations.members.store', associations.id), {
onSuccess: () => reset(),
});
};
return (
اضافة العضو و اجمالي مبلغة في الجمعية
{associations.name}
عدد الاشهر : {associations.total_months}
مبلغ الدور : {associations.role_price}
اعضاء الجمعية
إجمالي المبلغ: {totalAmount}
{associations.members.map((member, memberIndex) => (
{member.name}
{member.pivot.total_amount}
))}
);
}
بعد ذلك نقوم باستبدال اللينك التالي في صفحة Associations/Index للدخول منة الي صفحة اضافة العضو للجمعية ومبلغة Show
{association.name}
انشاء الجدول الوسيط و الاخير RoleAssociationMember
سوف نقوم بانشاء جدول يضم id الخاص بالجدول الوسيط السابق Association_member مع الدور role مع المبلغ المدفوع في الدور وبذلك يكون لدينا العضو باجمالي المبلغ المدفوع منة في الجمعية مع الادوار المحددة لة في الجمعية مع مبلغة في كل دور
php artisan make:migration create_association_member_role_table --create=association_member_role
المايجريشن migrate
public function up(): void
{
Schema::create('association_member_role', function (Blueprint $table) {
$table->id();
$table->foreignId('association_member_id')->constrained('association_member')->onDelete('cascade');
$table->foreignId('role_id')->constrained()->onDelete('cascade');
$table->decimal('paid_amount', 10, 2); // المبلغ المدفوع لكل دور
$table->timestamps();
});
}
الموديل Model
ويجب اضافة الكود التالي في موديل Association للعلاقة بين الجمعية والادوار
// في App\Models\Association.php
public function association_members()
{
return $this->hasMany(AssociationMember::class);
}
ويجب اضافة الكود التالي في موديل AssociationMember للعلاقة بين الادوار و الجدول الوسيط
public function roles()
{
return $this->belongsToMany(Role::class, 'association_member_role')
->withPivot('paid_amount')
->withTimestamps();
}
ويجب اضافة الكود التالي في موديل Member للعلاقة بين الجمعية و العضو في الجدول الوسيط
public function associations()
{
return $this->belongsToMany(Association::class, 'association_member')
->withPivot('id','total_amount')
->withTimestamps();
}
ويجب اضافة الكود التالي في موديل Role للعلاقة بين الدور في الجداول الوسيطة و العضو في الجدول الوسيط
public function association_members()
{
return $this->belongsToMany(AssociationMember::class, 'association_member_role')
->withPivot('paid_amount')
->with('member') // تضمين بيانات العضو
->withTimestamps();
}
كونترولر Controller
تعديل دالة index في RoleController بالشكل التالي
public function index()
{
$associations = Association::with(['roles', 'members' => function($query) {
$query->select('members.id', 'name', 'association_member.id as association_member_id');
},'roles.association_members' => function ($query) {
$query->withPivot('paid_amount');
}
])->get();
$roles = Role::with(['association_members.member'])->get();
return Inertia::render('Roles/Index', [
'associations' => $associations,
]);
}
يمكنك اضافة التعديل والحذف بالرجوع الي الدروس السابقة مثال
مصادر خارجية