Create an Instant Push Notification(IPN) Service in Laravel
Let’s create an Instant Push Notificaion(IPN) service for user’s card add and delete in a payment gateway service. We will notifify the IPN listener about this user action.
First, we will create notifications table using php artisan command
php artisan make:migration create_notifications_table --create=notifications
please add the scemea inside the migration file
Schema::create('notifications', function (Blueprint $table) {
$table->id();
$table->string('action_type');
$table->string('ipn_listener_url');
$table->text('post_data');
$table->integer('tries')->default(0);
$table->timestamp('last_tried_at')->nullable();
$table->timestamps();
$table->timestamp('deleted_at')->nullable(); //for soft delete
});
}
Now, migrate this file using the command
php artisan migrate
Let’s create a model call Notification.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Notification extends Model
{
use SoftDeletes;
protected $table = 'notifications';
}
Now, we will save a notification to this notification table when a user add/delete a card.
First, create a route for action of a card. We will send card index, action type to indentify which card is added/deleted.
$router->post('card/action', 'CardController@cardAction');
Create a controller CardController.php and add a method called cardAction
public function cardAction(Request $request){
// store this action to notificaion table
$notification = new Notification();
$notification->action_type = $request->action_type;
$notification->ipn_listener_url = 'http://localhost/my-ipn-listener'; // please change it to your ipn listener url who will receive the IPN data
$notification->post_data = json_encode(['action_type'=>$request->action_type, 'card_index'=>$request->card_index]);
$notification->tries = 0;
$notification->last_tried_at = null;
if(!$notification->save())
return false;
return true;
}
It’s time to create our artisan command which will send notificiaon to the IPN listener. Let’s create a artisan command first. In your terminal type,
php artisan make:command IpnNotification --command=ipn:notification
We will see a new file IpnNotification.php file is created inside app/console/Commands folder.
In the IpnNotification.php class we will first add the description of the command.
/**
* The console command description.
*
* @var string
*/
protected $description = 'notify data to IPN';
Next, to send the IPN data we will add our notificaion send logic inside the handle method which is already provided in the class.
public function handle()
{
$tryLimit = 3; // max try limit for a failed notificaion
$intervalMinute = 5; // try a failed one after each five minutes
// send all the notifications between yesterday and today
$notifications = Notification::whereBetween('created_at', [Carbon::yesterday()->startOfDay(), Carbon::now()])
->where(function($query) use($intervalMinute){
$query->where('last_tried_at', '<', Carbon::now()->subMinutes($intervalMinute))
->orWhereNull('last_tried_at');
})
->where('tries', '<=', $tryLimit)
->get();
if(!$notifications->isEmpty()){
foreach($notifications as $notification) {
$payload = ['ipn_data'=>$notification->post_data];
// sending notification using CURL request
$isSent = $this->sendNotification($notification->ipn_listener_url, $payload);
if($isSent) {
$notification->delete(); // soft delete the notifcaion as it's successful and no need to send further
}
else{
$notification->tries = $notification->tries + 1;
$notification->save();
}
}
}
}
private function sendNotification(string $url, array $body)
{
try{
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_TIMEOUT_MS => 60000, // Set the timeout value in milliseconds
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => $body,
));
$curlResponse = curl_exec($curl);
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$err = curl_error($curl);
curl_close($curl);
if (curl_errno($curl) == CURLE_OPERATION_TIMEDOUT || $err || $httpcode != 200)
return false;
return true;
} catch(\Throwable $e) {
return false;
}
}
Now, we will register our notification command inside app/console/Kernel.php file.
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
'App\Console\Commands\IpnNotification',
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('ipn:notification')
->everyMinute()
->withoutOverlapping();
}
}
To Send the notificaion we will run our specific schedule command
php artisan ipn:notification
Or we can run the scheduer
php artisan schedule:run
If we always want to run the scheduler every minute then we can achieve it by adding the following Cron entry to our server.
* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
Tags: Laravel PHP Web Development IPN Push Notification