Laravel会议注册多步骤表单支付流程与代码架构咨询
Hey there! Let's work through this to keep your code clean and maintainable instead of piling everything into one controller method. Here's a structured approach tailored to your Laravel multi-step registration flow:
1. Split Controller Responsibilities
Instead of cramming all logic into RegistrationController, split things up to follow the single-responsibility principle:
- Keep
RegistrationControllerfocused on handling step 1 (user info collection) and step 2 (payment method validation/selection routing) - Create a dedicated
PaymentControllerto handle payment-specific actions (reference code generation, Stripe flows, third-party webhooks) - Extract core payment logic into a
PaymentServiceclass to keep controllers lightweight and reusable
2. Step 2 → Step 3 Flow Design
Here's a clear, user-friendly flow for both payment methods:
- User submits step 2 (payment method choice) via AJAX
- Backend validates the selection, then branches based on payment type:
- Reference payment: Generate a unique reference code, link it to the registration, and return data to render step 3 (showing the code)
- Credit card (Stripe): Initialize a Stripe checkout session, return the session ID to the frontend, and redirect the user to Stripe's payment page
- After payment completion:
- Reference: Third-party service sends a webhook to your backend to mark the payment as paid, then trigger step 4
- Stripe: Stripe redirects back to your success route, you create the payment record, then render step 4
3. Code Implementation Examples
3.1 Payment Service Class (Core Logic)
Create app/Services/PaymentService.php to encapsulate reusable payment logic:
namespace App\Services; use App\Models\Registration; use App\Models\Payment; use Stripe\Stripe; use Stripe\Checkout\Session; class PaymentService { // Generate unique reference code for offline payments public function generateReferenceCode(Registration $registration): string { $code = 'CONF-' . $registration->id . '-' . strtoupper(substr(md5(uniqid()), 0, 6)); $registration->update(['reference_code' => $code]); return $code; } // Create Stripe checkout session public function createStripeSession(Registration $registration): Session { Stripe::setApiKey(config('services.stripe.secret')); return Session::create([ 'payment_method_types' => ['card'], 'line_items' => [[ 'price_data' => [ 'currency' => 'eur', // Adjust to your currency 'product_data' => ['name' => 'Conference Registration'], 'unit_amount' => $registration->price * 100, // Stripe uses cents ], 'quantity' => 1, ]], 'mode' => 'payment', 'success_url' => route('payment.stripe.success', ['registration' => $registration->id]), 'cancel_url' => route('payment.stripe.cancel', ['registration' => $registration->id]), ]); } // Create payment record in database public function createPaymentRecord(Registration $registration, string $methodId, string $status = 'paid'): Payment { return Payment::create([ 'price' => $registration->price, 'payment_method_id' => $methodId, 'registration_id' => $registration->id, 'status' => $status, ]); } }
3.2 RegistrationController (Step 2 Handling)
Update your existing controller to route payment choices to the right logic:
namespace App\Http\Controllers; use App\Models\Registration; use App\Services\PaymentService; use Illuminate\Http\Request; class RegistrationController extends Controller { protected $paymentService; public function __construct(PaymentService $paymentService) { $this->paymentService = $paymentService; } // Handle step 2 payment method submission public function storePaymentMethod(Request $request) { $validated = $request->validate([ 'payment_method_id' => 'required|exists:payment_methods,id', 'registration_id' => 'required|exists:registrations,id', ]); $registration = Registration::findOrFail($validated['registration_id']); $methodId = $validated['payment_method_id']; // Branch based on payment method if ($methodId === 1) { // Replace with your reference method ID $referenceCode = $this->paymentService->generateReferenceCode($registration); return response()->json([ 'success' => true, 'next_step' => 3, 'reference_code' => $referenceCode, 'message' => 'Use this code to complete your payment via our partner service' ]); } elseif ($methodId === 2) { // Replace with your Stripe method ID $session = $this->paymentService->createStripeSession($registration); return response()->json([ 'success' => true, 'next_step' => 'stripe', 'session_id' => $session->id, 'stripe_key' => config('services.stripe.key') ]); } return response()->json(['success' => false, 'message' => 'Invalid payment method'], 400); } }
3.3 PaymentController (Payment Callbacks & Webhooks)
Create this controller to handle post-payment actions:
namespace App\Http\Controllers; use App\Models\Registration; use App\Services\PaymentService; use Illuminate\Http\Request; use Stripe\Webhook; class PaymentController extends Controller { protected $paymentService; public function __construct(PaymentService $paymentService) { $this->paymentService = $paymentService; } // Stripe payment success redirect public function stripeSuccess(Request $request) { $registration = Registration::findOrFail($request->registration); $this->paymentService->createPaymentRecord($registration, 2); // Stripe method ID return view('registration.success', compact('registration')); // Step 4 view } // Stripe payment cancel redirect public function stripeCancel(Request $request) { $registration = Registration::findOrFail($request->registration); return redirect()->route('registration.step2', ['registration' => $registration->id]) ->with('error', 'Payment cancelled. Please try again.'); } // Third-party reference payment webhook public function referenceWebhook(Request $request) { // Validate webhook signature (follow your third-party docs) $referenceCode = $request->input('reference_code'); $registration = Registration::where('reference_code', $referenceCode)->firstOrFail(); $this->paymentService->createPaymentRecord($registration, 1); // Reference method ID return response()->json(['status' => 'success']); } }
4. Frontend Flow Notes
- For reference payments: On receiving the step 3 response, toggle your UI to show the reference code and instructions
- For Stripe payments: Use Stripe.js to redirect the user to checkout with the returned
session_id - Optional: Add a polling mechanism on step 3 to check if the reference payment has been processed, then auto-navigate to step 4
5. Extra Optimizations
- Add a
statusfield to yourregistrationstable (e.g.,pending_payment,payment_completed) to track progress - Use Laravel queues to handle non-urgent tasks (like sending payment confirmation emails)
- Secure Stripe webhooks with Laravel's built-in signature validation
内容的提问来源于stack exchange,提问作者johnW
相关产品推荐
相关产品推荐

