How to Integrate Paypal Payment Gateway with Cakephp
Cakephp 3 is a PHP framework that is the most popular for rapid application development and Paypal is the most popular payment gateway. So today we will learn how to integrate Paypal with CakePHP.
For this tutorial, I am using CakePHP 4 which is the latest version of CakePHP but steps will be the same for CakePHP 3x.
So Keep following the below steps.
First, we will create a sandbox account to test our payment gateway later and we need to create both accounts personal and business so we can test, so if you have already created that then skip this step, and if you want to create a new sandbox test account then click here.
Also, we need client id and secret that we can get by creating an app in the PayPal developer account.
Go to the developer website and click on My Apps & Credentials then click on Create App Button
Then fill the App name and select a business account that we have recently created, like the below screenshot, and then click on Create App button.
And after submit it will show you both, client Id and secret Key like the below screenshot.
Ok so now we need to install PHP SDK in our CakePHP Application so open command prompt or Terminal in your root folder . and run below command:
composer require "paypal/rest-api-sdk-php:*"
The above command will install the latest REST API PHP SDK of PayPal.
Now open config/bootstrap.php and add below code at the bottom of the file and replace details with your account details
$aSetting = []; $aSetting['PAYPAL_clientId'] = 'YOUR_CLIENT_ID'; $aSetting['PAYPAL_secret'] = 'YOUR_SECRET_KEY'; $aSetting['PAYPAL_mode'] = 'sandbox'; Configure::write('Site', $aSetting);
Now we will create a controller that will handle all payment actions. You can create a controller by two methods, manually and with the command line, I prefer to create controller, action, modal always with the command line. so to create a controller with the command line, run below command in your project root directory:
bin\cake bake controller Payments
Now after this command CakePHP will create a controller and now create an index.php file in ROOT/templates/Payments/index.php, please note that this is for CakePHP 4 version, if you are using CakePHP 3 then create the file as ROOT/src/templates/Payments/index.ctp
Now paste below form code in it
<?= $this->Form->create(null,['class'=>'cls-form']) ?> <h2 class="w3-text-blue">Payment CakePHP Form</h2> <label class="w3-text-blue"><b>Enter Amount</b></label> <?= $this->Form->control('amount',['class'=>'form-control','value'=>100]) ?> <button class="btn btn-primary">Pay with PayPal</button></p> <?= $this->Form->end() ?>
Now we will create two actions in our Payments controller, index() and status()
index(), in the index we will get a price on the form to submit and then will redirect on payment gateway and status() action we will use to handle the response from PayPal payment gateway.
Copy below code and replace with your controller code (src/Controller/PaymentsController.php)
<?php declare(strict_types=1); namespace App\Controller; use Cake\Routing\Router; use Cake\Event\Event; use Cake\Event\EventInterface; use Cake\Core\Configure; use PayPal\Api\Payer; use PayPal\Api\Item; use PayPal\Api\ItemList; use PayPal\Api\Amount; use PayPal\Api\Details; use PayPal\Api\Payment; use PayPal\Api\PaymentExecution; use PayPal\Api\Transaction; /** * Payments Controller * * * @method \App\Model\Entity\Payment[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) */ class PaymentsController extends AppController { public function beforeFilter(EventInterface $event) { parent::beforeFilter($event); $this->Auth->allow(); $this->viewBuilder()->setLayout('user-layout'); } /** * Index method * * @return \Cake\Http\Response|null */ public function index() { if($this->request->is('post')) { $clientId = Configure::read('Site.PAYPAL_clientId'); $secret = Configure::read('Site.PAYPAL_secret'); $apiContext = new \PayPal\Rest\ApiContext( new \PayPal\Auth\OAuthTokenCredential( $clientId, // you will get information about client id and secret once you have created test account in paypal sandbox $secret ) ); $price = $this->request->getData('amount'); $payer = new Payer(); $payer->setPaymentMethod('paypal'); $item_1 = new Item(); $item_1->setName('Membership Plan') /** item name **/ ->setCurrency('USD') ->setQuantity(1) ->setPrice($price); /** unit price **/ $item_list = new ItemList(); $item_list->setItems(array($item_1)); $amount = new \PayPal\Api\Amount(); $amount->setCurrency('USD') ->setTotal($price); $transaction = new \PayPal\Api\Transaction(); $transaction->setAmount($amount) ->setItemList($item_list) ->setDescription('My Membership'); $redirect_urls = new \PayPal\Api\RedirectUrls(); $redirect_urls->setReturnUrl(Router::url(['controller' => 'Payments', 'action' => 'status'], true)) /** Specify return URL **/ ->setCancelUrl(Router::url(['controller' => 'Payments', 'action' => 'status'], true)); $payment = new \PayPal\Api\Payment(); $payment->setIntent('Sale') ->setPayer($payer) ->setRedirectUrls($redirect_urls) ->setTransactions(array($transaction)); /** dd($payment->create($this->_api_context));exit; **/ try { $payment->create($apiContext); } catch (\PayPal\Exception\PPConnectionException $ex) { $this->Flash->error('Something went wrong! Please try again.'); return $this->redirect(['action'=>'index']); } foreach ($payment->getLinks() as $link) { if ($link->getRel() == 'approval_url') { $redirect = $link->getHref(); break; } } $this->getRequest()->getSession()->write('paypalPaymentId',$payment->getId()); if (isset($redirect)) { return $this->redirect($redirect); } $this->Flash->error('Something went wrong! Please try again.'); return $this->redirect(['action'=>'index']); } } public function status() { $clientId = Configure::read('Site.PAYPAL_clientId'); $secret = Configure::read('Site.PAYPAL_secret'); $apiContext = new \PayPal\Rest\ApiContext( new \PayPal\Auth\OAuthTokenCredential( $clientId, $secret ) ); $paymentSessionId = $this->getRequest()->getSession()->read('paypalPaymentId'); //$this->getRequest()->getSession()->delete('paypalPaymentId'); $getPayeerId = $this->request->getQuery('PayerID'); $token = $this->request->getQuery('token'); if (empty($getPayeerId) || empty($token)) { $this->Flash->error('Something went wrong! Please try again.'); return $this->redirect(['action'=>'index']); } $payment = Payment::get($paymentSessionId, $apiContext); $execution = new \PayPal\Api\PaymentExecution(); $execution->setPayerId($getPayeerId); try { $result = $payment->execute($execution, $apiContext); } catch (PayPal\Exception\PPConnectionException $ex) { //echo '<pre>';print_r(json_decode($ex->getData()));exit; } // echo '<pre>'; print_r($result); echo '</pre>'; if($result->getState() == 'approved') { $this->Flash->success('Payment Successfull.'); return $this->redirect(['action'=>'index']); } $this->Flash->error('Payment failed.'); return $this->redirect(['action'=>'index']); } }
Code explanation:
we are submitting the form and getting the price and then we are adding details that is required for gateway request and then we are saving Payment ID in a session so we can get after success and can fetch results by using that Payment ID and then we are redirecting to gateway page.
status()
In status(), we are getting payer ID by using getQuery() and also getting session payment ID that we have saved in session in the index(). Now then we are passing both values in PayPal API and getting a response and then we matching getState() output is equal to approved or not, if it's matched then its transaction is successful and if it's not matched then its failed, you can check all other values by printing $result variable after a try-catch function.
And now you can test it with your sandbox account and later you can off sandbox mode and then it will work for a real account too. Thanks
Important Links
This comment has been removed by a blog administrator.
ReplyDelete