mrroot/orange-money-bundle
Composer 安装命令:
composer require mrroot/orange-money-bundle
包简介
Symfony bundle for Orange Money payment integration with complete webhook, callback and error handling support
README 文档
README
Symfony bundle for Orange Money payment integration with complete webhook support, callbacks, and advanced error handling.
Features
- Orange Money payment initiation with comprehensive validation
- Transaction status verification with enhanced parameters
- Advanced webhook and notification handling with token validation
- Robust error handling with detailed logging
- Flexible configuration via environment variables
- OAuth2 support for secure API authentication
- Symfony compatibility 5.4, 6.x and 7.x
- Automatic data validation and sanitization
- Configurable callback URLs with security features
- Webhook spoofing protection via notification token validation
- Enhanced payment response handling with comprehensive data access
Bundle Architecture
File Structure
src/OrangeMoneyBundle/
├── DependencyInjection/
│ ├── Configuration.php # Bundle configuration
│ └── OrangeMoneyExtension.php # Symfony extension
├── Exception/
│ └── OrangeMoneyException.php # Custom exceptions
├── Model/
│ ├── PaymentRequest.php # Payment request model
│ └── PaymentResponse.php # Payment response model
├── Service/
│ └── OrangeMoneyService.php # Main service
└── OrangeMoneyBundle.php # Main bundle class
Flow Diagram
Application → PaymentRequest → OrangeMoneyService → Orange Money API
↓ ↓ ↓ ↓
Controller ← PaymentResponse ← Token Management ← OAuth2 Response
Installation
1. Installation via Composer
composer require mrroot/orange-money-bundle
2. Bundle Registration
Add the bundle to config/bundles.php:
<?php return [ Mrroot\OrangeMoneyBundle\OrangeMoneyBundle::class => ['all' => true], ];
3. Configuration
Create the file config/packages/orange_money.yaml:
orange_money: client_id: '%env(OM_CLIENT_ID)%' client_secret: '%env(OM_CLIENT_SECRET)%' api_base_url: '%env(OM_API_BASE_URL)%' token_endpoint: '%env(OM_TOKEN_ENDPOINT)%' payment_endpoint: '%env(OM_PAYMENT_ENDPOINT)%' transaction_status_endpoint: '%env(OM_TRANSACTIONSTATUS_ENDPOINT)%' parameters: OM_RETURN_URL: '%env(OM_RETURN_URL)%' OM_CANCEL_URL: '%env(OM_CANCEL_URL)%' OM_NOTIF_URL: '%env(OM_NOTIF_URL)%' OM_MERCHANT_KEY: '%env(OM_MERCHANT_KEY)%'
4. Environment Variables
Add these variables to your .env file:
# Orange Money API Configuration OM_CLIENT_ID=your_client_id OM_CLIENT_SECRET=your_client_secret OM_MERCHANT_KEY=your_merchant_key OM_API_BASE_URL=https://api.orange.com # API Endpoints OM_TOKEN_ENDPOINT=/oauth/v3/token OM_PAYMENT_ENDPOINT=/orange-money-webpay/dev/v1/webpayment OM_TRANSACTIONSTATUS_ENDPOINT=/orange-money-webpay/dev/v1/transactionstatus # Callback URLs OM_RETURN_URL=https://your-site.com/payment/success OM_CANCEL_URL=https://your-site.com/payment/cancel OM_NOTIF_URL=https://your-site.com/payment/webhook
Usage
Complete Controller Example
For a complete and detailed implementation example, see: Controller Example
Payment Initiation
<?php namespace App\Controller; use Mrroot\OrangeMoneyBundle\Model\PaymentRequest; use Mrroot\OrangeMoneyBundle\Service\OrangeMoneyService; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; class PaymentController extends AbstractController { #[Route('/payment/initiate', name: 'payment_initiate', methods: ['POST'])] public function initiatePayment( Request $request, OrangeMoneyService $orangeMoneyService ): JsonResponse { try { // Create payment request $paymentRequest = new PaymentRequest( orderId: 'ORDER_' . uniqid(), amount: 10000, currency: 'GNF', reference: 'REF_' . time(), merchantKey: $this->getParameter('OM_MERCHANT_KEY'), returnUrl: $this->getParameter('OM_RETURN_URL'), cancelUrl: $this->getParameter('OM_CANCEL_URL'), notifUrl: $this->getParameter('OM_NOTIF_URL') ); // Initiate payment $paymentResponse = $orangeMoneyService->initiatePayment($paymentRequest); // IMPORTANT: Save these values for webhook validation // - $paymentResponse->getPayToken() (payToken) // - $paymentRequest->getOrderId() (orderId) // - $paymentResponse->getNotifToken() (notifToken) return new JsonResponse([ 'success' => true, 'payment_url' => $paymentResponse->getPaymentUrl(), 'pay_token' => $paymentResponse->getPayToken(), 'notif_token' => $paymentResponse->getNotifToken(), 'order_id' => $paymentRequest->getOrderId() ]); } catch (\Exception $e) { return new JsonResponse([ 'success' => false, 'error' => $e->getMessage() ], 400); } } }
Payment Status Verification
#[Route('/payment/status/{payToken}', name: 'payment_status')] public function checkPaymentStatus( string $payToken, string $orderId, float $amount, OrangeMoneyService $orangeMoneyService ): JsonResponse { try { // Enhanced status check with required parameters $response = $orangeMoneyService->checkTransactionStatus($payToken, $orderId, $amount); return new JsonResponse([ 'pay_token' => $payToken, 'order_id' => $response->getOrderId(), 'status' => $response->getStatus(), 'amount' => $response->getAmount(), 'currency' => $response->getCurrency(), 'txn_id' => $response->getTxnId() ]); } catch (\Exception $e) { return new JsonResponse([ 'error' => $e->getMessage() ], 400); } }
Webhook Handling with Security Validation
#[Route('/payment/webhook', name: 'payment_webhook', methods: ['POST'])] public function handleWebhook( Request $request, OrangeMoneyService $orangeMoneyService ): JsonResponse { try { // Retrieve stored values from your database/session // These values should have been saved during payment initiation: $payToken = "your-stored-pay-token"; // Get from database $orderId = "your-stored-order-id"; // Get from database $notifToken = "your-stored-notif-token"; // Get from database $amount = 50.0; // Get from database // Optional: Check transaction status separately if needed // $checkResponse = $orangeMoneyService->checkTransactionStatus( // $payToken, // $orderId, // $amount // ); $webhookData = json_decode($request->getContent(), true); // Automatic notif_token verification $paymentStatus = $orangeMoneyService->processNotification($webhookData, $notifToken); // Your business logic here if ($paymentStatus->getStatus() === 'SUCCESS') { // Confirm order $this->confirmOrder($paymentStatus->getOrderId()); } return new JsonResponse([ 'status' => 'success', 'message' => 'Notification processed', 'txn_id' => $paymentStatus->getTxnId() ]); } catch (\Exception $e) { return new JsonResponse([ 'status' => 'error', 'message' => $e->getMessage() ], 500); } private function getStoredNotifToken(?string $orderId): ?string { // Retrieve the notification token stored during payment initiation // This could be from database, cache, session, etc. return $orderId ? $this->paymentRepository->getNotifTokenByOrderId($orderId) : null; } private function confirmOrder(string $orderId): void { // Your order confirmation logic } }
Transaction Status Verification (Optional)
public function checkStatus(OrangeMoneyService $orangeMoneyService): JsonResponse { try { // Use values saved during payment initiation $response = $orangeMoneyService->checkTransactionStatus( 'pay-token-from-initiation', // Saved payment token 'ORDER-123', // Saved order ID 10000 // Saved amount ); return new JsonResponse([ 'status' => $response->getStatus(), 'transaction_id' => $response->getTxnId(), 'order_id' => $response->getOrderId() ]); } catch (OrangeMoneyException $e) { return new JsonResponse([ 'error' => $e->getMessage() ], 400); } }
Data Models
PaymentRequest
$paymentRequest = new PaymentRequest( orderId: 'ORDER_123', // Unique order ID amount: 10000, // Amount currency: 'OUV', // Currency (OUV for Ouguiya) reference: 'REF_123', // Optional reference merchantKey: 'merchant_key', // Merchant key returnUrl: 'https://...', // Success return URL cancelUrl: 'https://...', // Cancellation URL notifUrl: 'https://...' // Notification URL );
PaymentResponse
// Available methods $response->getPaymentUrl(); // Payment URL $response->getPayToken(); // Payment token $response->getNotifToken(); // Notification token (for webhook validation) $response->getTxnId(); // Transaction ID $response->getStatus(); // Payment status $response->getOrderId(); // Order ID $response->getAmount(); // Amount $response->getCurrency(); // Currency $response->isSuccessful(); // Success verification $response->hasError(); // Error verification $response->getErrorMessage(); // Error message $response->getErrorCode(); // Error code $response->hasPaymentUrl(); // Payment URL validation $response->getRawData(); // Raw data
Security
Enhanced Webhook Validation
The bundle provides comprehensive webhook security:
// Required fields validated automatically $requiredFields = ['status', 'notif_token', 'txnid']; // Process notification with token validation $paymentStatus = $orangeMoneyService->processNotification($data, $expectedNotifToken);
Webhook Spoofing Protection
To prevent webhook spoofing attacks:
- Store the notification token during payment initiation:
$paymentResponse = $orangeMoneyService->initiatePayment($paymentRequest); $notifToken = $paymentResponse->getNotifToken(); // Store this token securely (database, cache, etc.) $this->storeNotifToken($paymentRequest->getOrderId(), $notifToken);
- Validate the token in webhook processing:
$expectedToken = $this->getStoredNotifToken($orderId); $paymentStatus = $orangeMoneyService->processNotification($webhookData, $expectedToken);
Error Handling
All errors are encapsulated in OrangeMoneyException:
try { $paymentResponse = $orangeMoneyService->initiatePayment($paymentRequest); } catch (OrangeMoneyException $e) { // Orange Money specific error $errorMessage = $e->getMessage(); $errorData = $e->getData(); }
Logging
The bundle uses Symfony's logging system:
# config/packages/monolog.yaml monolog: channels: ['orange_money'] handlers: orange_money: type: rotating_file path: '%kernel.logs_dir%/orange_money.log' level: info channels: ['orange_money']
Advanced Configuration
Endpoint Customization for Development or Production Environment
# config/packages/orange_money.yaml orange_money: api_base_url: 'https://api.orange.com' payment_endpoint: '/orange-money-webpay/dev/v1/webpayment' transaction_status_endpoint: '/orange-money-webpay/dev/v1/transactionstatus'
Complete Examples
Implementation examples are integrated directly into this documentation and include:
- Complete payment controller
- Callback handling
- Transaction status verification
- Webhook handling
Contributing
Contributions are welcome! Please:
- Fork the project
- Create a branch for your feature
- Commit your changes
- Push to the branch
- Open a Pull Request
License
This project is licensed under the MIT License. See the LICENSE file for more details.
Support
- Issues: GitHub Issues
- Email: camaraabdoulayeroo@mail.com
Changelog
v1.1.0
- Enhanced webhook security with notification token validation
- Improved transaction status checking with required parameters (payToken, orderId, amount)
- Extended PaymentResponse model with notifToken and txnId properties
- Code quality improvements and consistency fixes
- Better error handling and validation
- Webhook spoofing protection implementation
v1.0.0
- First stable version
- Complete Orange Money API support
- Webhook handling
- Complete documentation
Developed with ❤️ by Abdoulaye CAMARA alias MrROOT
mrroot/orange-money-bundle 适用场景与选型建议
mrroot/orange-money-bundle 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 29 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 09 月 02 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「symfony」 「payment」 「bundle」 「callback」 「webhook」 「orange」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 mrroot/orange-money-bundle 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 mrroot/orange-money-bundle 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 mrroot/orange-money-bundle 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
2lenet/EasyAdminPlusBundle
The bundle for easy using json-rpc api on your project
Provide a way to secure accesses to all routes of an symfony application.
DMS Meetup API Bundle, enables Meetup API clients in services
Bundle Symfony DaplosBundle
Provides a Data Grid tables for your Symfony project.
统计信息
- 总下载量: 29
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 36
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-09-02