الدليل المتكامل لتركيب واستدعاء Nafezly Payments وربطها بالعميل
شرح عملي خطوة بخطوة لتركيب حزمة Nafezly Payments في لارافيل، إعداد بوابات الدفع، استدعاء عملية الدفع وربطها ببيانات العميل والتحقق من نتيجة العملية.
شرح عملي خطوة بخطوة لتركيب حزمة Nafezly Payments في لارافيل، إعداد بوابات الدفع، استدعاء عملية الدفع وربطها ببيانات العميل والتحقق من نتيجة العملية.
شرح عملي خطوة بخطوة مع قاعدة البيانات ومتحكمات العميل ولوحة تحكم الإدارة (متجاوب بالكامل ومع أزرار نسخ للأكواد).
قم بتثبيت الحزمة ونشر ملفات Configuration والـ Views إلى مشروعك:
composer require nafezly/payments
php artisan vendor:publish --tag=nafezly-payments-config
php artisan vendor:publish --tag=nafezly-payments-views
ضع بيانات الاعتماد للبوابات في ملف .env:
PAYMOB_API_KEY=your_api_key
PAYMOB_INTEGRATION_ID=your_integration_id
PAYMOB_IFRAME_ID=your_iframe_id
PAYMOB_HMAC_TITLE=your_hmac_secret
NAFEZLY_PAYMENT_CURRENCY=EGP
PAYMENT_REDIRECT_URL=http://localhost:8000/payment/verify
أنشئ Model مع ملف Migration لتخزين عمليات الدفع المربوطة بالعميل:
php artisan make:model Payment -m
افتح ملف الـ Migration وأضف هيكل الجدول التالي:
id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');$table->string('payment_id')->nullable();
$table->string('driver'); // paymob, fawry, tap...$table->decimal('amount', 10, 2);
$table->string('currency', 3)->default('EGP');$table->enum('status', ['pending', 'paid', 'failed'])->default('pending');
$table->json('process_data')->nullable();$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('payments');
}
};
php artisan migrate
'array',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
// أضف هذه الدالة داخل كلاس User
public function payments()
{
return $this->hasMany(Payment::class);
}
متحكم معالجة إنشاء المعاملة والتحويل للبوابة واستقبال النتيجة:
validate([
'amount' => 'required|numeric|min:1',
'gateway' => 'required|in:paymob,fawry,tap'
]);
$user = auth()->user();
// 1. تسجيل سجل معلق بالعميل
$paymentRecord = Payment::create([
'user_id' => $user->id,
'driver' => $request->gateway,
'amount' => $request->amount,
'currency' => config('nafezly-payments.currency', 'EGP'),
'status' => 'pending',
]);
// 2. استدعاء بوابة الدفع
$gateway = match($request->gateway) {
'paymob' => new PaymobPayment(),
'fawry' => new FawryPayment(),
'tap' => new TapPayment(),
};
// 3. التنفيذ عبر مكتبة Nafezly
$response =$gateway->pay(
amount: $request->amount,
user_first_name: $user->name,
user_last_name: 'Customer',
user_email: $user->email,
user_phone: $user->phone ?? '01000000000'
);
if (isset($response['payment_id'])) {
$paymentRecord->update(['payment_id' => $response['payment_id']]);
}
session(['current_payment_db_id' => $paymentRecord->id]);
if (isset($response['redirect_url'])) {
return redirect($response['redirect_url']);
}
return view('payment-redirect', ['payment' => $response]);
}
public function verify(Request $request)
{
$paymentDbId = session('current_payment_db_id');
$paymentRecord = Payment::findOrFail($paymentDbId);
$gateway = match($paymentRecord->driver) {
'paymob' => new PaymobPayment(),
'fawry' => new FawryPayment(),
'tap' => new TapPayment(),
};
$response = $gateway->verify($request);
if ($response['success'] === true) {$paymentRecord->update([
'status' => 'paid',
'payment_id' => $response['payment_id'] ?? $paymentRecord->payment_id,
'process_data' => $response['process_data'] ?? null
]);
return redirect()->route('dashboard')
->with('success', 'تم الدفع بنجاح وتسجيل المعاملة!');
}
$paymentRecord->update([
'status' => 'failed',
'process_data' => $response['process_data'] ?? null
]);
return redirect()->route('dashboard')
->with('error', 'فشلت عملية الدفع!');
}
}
latest();
if ($request->filled('status')) {
$query->where('status',$request->status);
}
if ($request->filled('driver')) {
$query->where('driver',$request->driver);
}
$payments = $query->paginate(15);$totalPaid = Payment::where('status', 'paid')->sum('amount');
return view('admin.payments.index', compact('payments', 'totalPaid'));
}
public function show($id)
{
$payment = Payment::with('user')->findOrFail($id);
return view('admin.payments.show', compact('payment'));
}
}
واجهة لوحة الأدمن (Blade View) المتجاوبة بالكامل وبدون حواف خارجية:
إدارة المعاملات المالية
إجمالي المبيعات الناجحة: {{ number_format($totalPaid, 2) }} EGP
@forelse(payments aspayment)
@empty
@endforelse
# المعاملة
العميل
البوابة
المبلغ
الحالة
التاريخ
التفاصيل
{{ $payment->payment_id ?? $payment->id }}
{{ $payment->user->name }}
{{ $payment->user->email }}
{{ strtoupper($payment->driver) }}
{{ $payment->amount }} {{$payment->currency }}
@if($payment->status == 'paid')
ناجح
@elseif($payment->status == 'pending')
معلق
@else
فاشل
@endif
{{ $payment->created_at->format('Y-m-d H:i') }}
عرض
لا توجد معاملات حالياً.
{{ $payments->links() }}
use App\Http\Controllers\PaymentController;
use App\Http\Controllers\Admin\AdminPaymentController;
// مسارات العملاء
Route::middleware(['auth'])->group(function () {
Route::post('/payment/process', [PaymentController::class, 'pay'])->name('payment.process');
Route::any('/payment/verify', [PaymentController::class, 'verify'])->name('payment.verify');
});
// مسارات الأدمن
Route::middleware(['auth', 'admin'])->prefix('admin')->name('admin.')->group(function () {
Route::get('/payments', [AdminPaymentController::class, 'index'])->name('payments.index');
Route::get('/payments/{id}', [AdminPaymentController::class, 'show'])->name('payments.show');
});
A step-by-step practical guide covering database structure, customer checkout flow, and admin panel management (fully responsive with copy code buttons).
Install the nafezly/payments package via Composer and publish the config and view files to your project:
composer require nafezly/payments
php artisan vendor:publish --tag=nafezly-payments-config
php artisan vendor:publish --tag=nafezly-payments-views
Add your payment gateway credentials in the .env file:
PAYMOB_API_KEY=your_api_key
PAYMOB_INTEGRATION_ID=your_integration_id
PAYMOB_IFRAME_ID=your_iframe_id
PAYMOB_HMAC_TITLE=your_hmac_secret
NAFEZLY_PAYMENT_CURRENCY=EGP
PAYMENT_REDIRECT_URL=http://localhost:8000/payment/verify
Create a Payment model and migration file to record payment transactions associated with users:
php artisan make:model Payment -m
Open the migration file and define the schema as follows:
id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');$table->string('payment_id')->nullable();
$table->string('driver'); // paymob, fawry, tap...$table->decimal('amount', 10, 2);
$table->string('currency', 3)->default('EGP');$table->enum('status', ['pending', 'paid', 'failed'])->default('pending');
$table->json('process_data')->nullable();$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('payments');
}
};
php artisan migrate
'array',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
// Add this relationship method inside the User class
public function payments()
{
return $this->hasMany(Payment::class);
}
Controller logic to create pending transactions, redirect users to gateways, and verify callback results:
validate([
'amount' => 'required|numeric|min:1',
'gateway' => 'required|in:paymob,fawry,tap'
]);
$user = auth()->user();
// 1. Create a pending transaction record
$paymentRecord = Payment::create([
'user_id' => $user->id,
'driver' => $request->gateway,
'amount' => $request->amount,
'currency' => config('nafezly-payments.currency', 'EGP'),
'status' => 'pending',
]);
// 2. Instantiate selected gateway driver
$gateway = match($request->gateway) {
'paymob' => new PaymobPayment(),
'fawry' => new FawryPayment(),
'tap' => new TapPayment(),
};
// 3. Initiate payment request via Nafezly package
$response =$gateway->pay(
amount: $request->amount,
user_first_name: $user->name,
user_last_name: 'Customer',
user_email: $user->email,
user_phone: $user->phone ?? '01000000000'
);
if (isset($response['payment_id'])) {
$paymentRecord->update(['payment_id' => $response['payment_id']]);
}
session(['current_payment_db_id' => $paymentRecord->id]);
if (isset($response['redirect_url'])) {
return redirect($response['redirect_url']);
}
return view('payment-redirect', ['payment' => $response]);
}
public function verify(Request $request)
{
$paymentDbId = session('current_payment_db_id');
$paymentRecord = Payment::findOrFail($paymentDbId);
$gateway = match($paymentRecord->driver) {
'paymob' => new PaymobPayment(),
'fawry' => new FawryPayment(),
'tap' => new TapPayment(),
};
$response = $gateway->verify($request);
if ($response['success'] === true) {$paymentRecord->update([
'status' => 'paid',
'payment_id' => $response['payment_id'] ?? $paymentRecord->payment_id,
'process_data' => $response['process_data'] ?? null
]);
return redirect()->route('dashboard')
->with('success', 'Payment successfully processed!');
}
$paymentRecord->update([
'status' => 'failed',
'process_data' => $response['process_data'] ?? null
]);
return redirect()->route('dashboard')
->with('error', 'Payment transaction failed!');
}
}
latest();
if ($request->filled('status')) {
$query->where('status',$request->status);
}
if ($request->filled('driver')) {
$query->where('driver',$request->driver);
}
$payments = $query->paginate(15);$totalPaid = Payment::where('status', 'paid')->sum('amount');
return view('admin.payments.index', compact('payments', 'totalPaid'));
}
public function show($id)
{
$payment = Payment::with('user')->findOrFail($id);
return view('admin.payments.show', compact('payment'));
}
}
Responsive Admin Dashboard Blade View (zero outer margin):
Payment Transactions Management
Total Successful Revenue: {{ number_format($totalPaid, 2) }} EGP
@forelse(payments aspayment)
@empty
@endforelse
# Transaction
Customer
Gateway
Amount
Status
Date
Actions
{{ $payment->payment_id ?? $payment->id }}
{{ $payment->user->name }}
{{ $payment->user->email }}
{{ strtoupper($payment->driver) }}
{{ $payment->amount }} {{$payment->currency }}
@if($payment->status == 'paid')
Paid
@elseif($payment->status == 'pending')
Pending
@else
Failed
@endif
{{ $payment->created_at->format('Y-m-d H:i') }}
View
No payment transactions found.
{{ $payments->links() }}
use App\Http\Controllers\PaymentController;
use App\Http\Controllers\Admin\AdminPaymentController;
// Customer Routes
Route::middleware(['auth'])->group(function () {
Route::post('/payment/process', [PaymentController::class, 'pay'])->name('payment.process');
Route::any('/payment/verify', [PaymentController::class, 'verify'])->name('payment.verify');
});
// Admin Control Panel Routes
Route::middleware(['auth', 'admin'])->prefix('admin')->name('admin.')->group(function () {
Route::get('/payments', [AdminPaymentController::class, 'index'])->name('payments.index');
Route::get('/payments/{id}', [AdminPaymentController::class, 'show'])->name('payments.show');
});