Implement PayPal: สร้างคลาส PayPalPayment
ในบทที่แล้ว เราได้สร้างคลาส StripePayment ที่ใช้สำหรับเชื่อมต่อและประมวลผลการชำระเงินผ่าน Stripe API ในบทนี้ เราจะมาสร้างคลาส PayPalPayment ซึ่งจะทำหน้าที่เดียวกัน แต่สำหรับ PayPal API โดยเราจะยังคงยึดตาม PaymentGatewayInterface ที่เราได้กำหนดไว้ เพื่อให้ระบบของเรามีความยืดหยุ่นและสามารถสลับไปมาระหว่าง Payment Gateway ต่างๆ ได้อย่างง่ายดาย
ติดตั้ง PayPal PHP SDK
ก่อนที่เราจะเริ่มเขียนโค้ด เราจำเป็นต้องติดตั้ง PayPal PHP SDK ซึ่งเป็น Library ที่ช่วยให้เราสามารถสื่อสารกับ PayPal API ได้อย่างง่ายดาย เราจะใช้ Composer ในการติดตั้ง Library นี้
เปิด Command Line หรือ Terminal แล้วไปยัง Project Directory ของเรา จากนั้นรันคำสั่ง:
composer require paypal/rest-api-sdk-php
Composer จะดาวน์โหลดและติดตั้ง PayPal PHP SDK พร้อมกับ Dependencies ที่จำเป็นทั้งหมด
Implement PaymentGatewayInterface
หลังจากที่เราติดตั้ง PayPal PHP SDK เรียบร้อยแล้ว เราจะมาสร้างคลาส PayPalPayment และ Implement PaymentGatewayInterface กัน
สร้างไฟล์ชื่อ PayPalPayment.php ใน Directory เดียวกับ StripePayment.php ของเรา (สมมติว่าเป็น Directory src/)
จากนั้นใส่โค้ดต่อไปนี้ลงในไฟล์ PayPalPayment.php:
<?php
namespace App;
use App\PaymentGatewayInterface;
use PayPal\Rest\ApiContext;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Api\Amount;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
use PayPal\Api\PaymentExecution;
class PayPalPayment implements PaymentGatewayInterface
{
private $apiContext;
private $clientId;
private $clientSecret;
public function __construct(string $clientId, string $clientSecret)
{
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
// Configure and Initialize API Context
$this->apiContext = new ApiContext(
new OAuthTokenCredential($clientId, $clientSecret)
);
$this->apiContext->setConfig(
array(
'mode' => 'sandbox', // หรือ 'live' สำหรับ Production
'log.LogEnabled' => true,
'log.FileName' => '../PayPal.log',
'log.LogLevel' => 'DEBUG'
)
);
}
public function charge(float $amount, string $currency): string
{
// Create Payer
$payer = new Payer();
$payer->setPaymentMethod("paypal");
// Set Amount
$amountObj = new Amount();
$amountObj->setCurrency($currency)
->setTotal($amount);
// Set Transaction
$transaction = new Transaction();
$transaction->setAmount($amountObj)
->setDescription("Payment with PayPal");
// Set Redirect URLs
$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl("http://localhost:8000/paypal/success") // แก้ไข URL ให้ถูกต้อง
->setCancelUrl("http://localhost:8000/paypal/cancel"); // แก้ไข URL ให้ถูกต้อง
// Create Payment
$payment = new Payment();
$payment->setIntent("sale")
->setPayer($payer)
->setRedirectUrls($redirectUrls)
->setTransactions(array($transaction));
try {
$payment->create($this->apiContext);
return $payment->getApprovalLink(); // Return the approval link
} catch (\PayPal\Exception\PayPalConnectionException $ex) {
// Log the error
error_log("PayPal Payment Error: " . $ex->getData());
throw new \Exception("PayPal Payment Failed: " . $ex->getMessage());
} catch (\Exception $e) {
// Handle other exceptions
error_log("General Error: " . $e->getMessage());
throw new \Exception("An error occurred during PayPal payment: " . $e->getMessage());
}
}
public function refund(string $transactionId, float $amount, string $currency): bool
{
// ยังไม่ได้ Implement ในบทนี้ (จะ Implement ในบทต่อๆ ไป)
throw new \Exception("Refund functionality for PayPal is not implemented yet.");
return false;
}
}
อธิบายโค้ด:
namespace App;: กำหนด Namespace ของคลาสuse App\PaymentGatewayInterface;: Import Interface ที่เราได้สร้างไว้use PayPal\...;: Import คลาสต่างๆ จาก PayPal PHP SDK ที่เราจะใช้class PayPalPayment implements PaymentGatewayInterface: ประกาศคลาสPayPalPaymentและ ImplementPaymentGatewayInterfaceprivate $apiContext;,private $clientId;,private $clientSecret;: กำหนด Properties สำหรับเก็บ API Context, Client ID และ Client Secret__construct(string $clientId, string $clientSecret): Constructor ของคลาส รับ Client ID และ Client Secret จาก PayPal และสร้างApiContextเพื่อใช้ในการสื่อสารกับ PayPal API$this->apiContext->setConfig(...): กำหนดค่า Config ให้กับApiContextเช่น Mode (Sandbox หรือ Live), Log Enabled, Log File Name และ Log Levelcharge(float $amount, string $currency): string: Implement ฟังก์ชันchargeจากPaymentGatewayInterfaceเพื่อประมวลผลการชำระเงินผ่าน PayPal- ภายในฟังก์ชัน
charge:- สร้าง
PayerObject และกำหนด Payment Method เป็น "paypal" - สร้าง
AmountObject และกำหนด Currency และ Amount - สร้าง
TransactionObject และกำหนด Amount และ Description - สร้าง
RedirectUrlsObject และกำหนด Return URL และ Cancel URL (สำคัญ: แก้ไข URL เหล่านี้ให้ถูกต้องตาม Project ของคุณ) - สร้าง
PaymentObject และกำหนด Intent, Payer, Redirect URLs และ Transaction - เรียกใช้
$payment->create($this->apiContext)เพื่อสร้าง Payment บน PayPal - ส่งคืน
$payment->getApprovalLink()ซึ่งเป็น Link ที่ผู้ใช้จะต้องคลิกเพื่ออนุมัติการชำระเงินบน PayPal - จัดการ Exception ที่อาจเกิดขึ้น เช่น
PayPalConnectionExceptionและException
- สร้าง
refund(string $transactionId, float $amount, string $currency): bool: Implement ฟังก์ชันrefundจากPaymentGatewayInterfaceสำหรับการคืนเงิน (ยังไม่ได้ Implement ในบทนี้)
เชื่อมต่อกับ PayPal API
ในการเชื่อมต่อกับ PayPal API เราจำเป็นต้องมี Client ID และ Client Secret จาก PayPal Developer Account ของเรา
- ไปที่ PayPal Developer และ Login ด้วย Account ของคุณ
- สร้าง App ใหม่ (หรือใช้ App ที่มีอยู่)
- ใน App Dashboard คุณจะพบ Client ID และ Client Secret
- สำคัญ: ตรวจสอบให้แน่ใจว่าคุณได้เปิดใช้งาน Sandbox Mode ใน App ของคุณ (สำหรับการทดสอบ)
หลังจากที่คุณได้ Client ID และ Client Secret แล้ว คุณสามารถนำไปใช้ใน Constructor ของคลาส PayPalPayment ได้:
$paypal = new PayPalPayment("YOUR_PAYPAL_CLIENT_ID", "YOUR_PAYPAL_CLIENT_SECRET");
ข้อควรระวัง: อย่าเก็บ Client ID และ Client Secret ไว้ใน Code โดยตรง ควรเก็บไว้ใน Environment Variables หรือ Configuration File ที่ปลอดภัยกว่า
กรณีใช้งานจริงและข้อผิดพลาดที่พบบ่อย
- Return URL และ Cancel URL ไม่ถูกต้อง: หาก Return URL หรือ Cancel URL ไม่ถูกต้อง PayPal จะไม่สามารถ Redirect ผู้ใช้กลับมายัง Website ของเราได้หลังจากการชำระเงินเสร็จสิ้น
- Client ID และ Client Secret ไม่ถูกต้อง: หาก Client ID หรือ Client Secret ไม่ถูกต้อง PayPal จะไม่สามารถ Authenticate App ของเราได้
- Sandbox Mode ไม่ได้เปิดใช้งาน: หาก Sandbox Mode ไม่ได้เปิดใช้งาน เราจะไม่สามารถทดสอบการชำระเงินได้โดยไม่ต้องใช้เงินจริง
- Currency ไม่รองรับ: ตรวจสอบให้แน่ใจว่า Currency ที่คุณใช้รองรับโดย PayPal
- API Permission: ตรวจสอบให้แน่ใจว่า App ของคุณมี Permission ที่จำเป็นในการเรียกใช้ API ที่คุณต้องการ
- การจัดการ Exception: การจัดการ Exception ที่ดีมีความสำคัญมากในการ Debug ปัญหาที่อาจเกิดขึ้น ควร Log Error Messages เพื่อช่วยในการแก้ไขปัญหา
สรุป
ในบทนี้ เราได้สร้างคลาส PayPalPayment ที่ Implement PaymentGatewayInterface และเชื่อมต่อกับ PayPal API โดยเราได้ติดตั้ง PayPal PHP SDK, Implement ฟังก์ชัน charge และ refund (แบบ Placeholder สำหรับ Refund) และจัดการกับ Exception ที่อาจเกิดขึ้น ในบทต่อไป เราจะมาสร้าง Factory Pattern เพื่อให้เราสามารถสร้าง Instance ของ StripePayment หรือ PayPalPayment ได้อย่างง่ายดาย