-
Notifications
You must be signed in to change notification settings - Fork 36
Tutorial ‐ Part 1
Let us create a new laravel project with the name banc. This will be our personal banking ussd for clients. Ensure you change the directory to where you keep your projects.
composer create-project laravel/laravel banc
Open the new application in the edit of your choice.
In the project root run
pwd
You should get a response like /Users/cybersai/Personal/banc
Change the following values in your .env
DB_CONNECTION=sqlite
DB_DATABASE=/Users/cybersai/Personal/banc/sqlite.db
where /Users/cybersai/Personal/banc/sqlite.db
is the absolute path to your sqlite db
Lets install laravel-ussd package. Make sure you are in the same directory as your banc project and you are using the shell.
composer require sparors/laravel-ussd:3.x-dev
lets create a new controller to expose the application to the web.
php artisan make:controller UssdController --invokable
let us edit the routes/api.php file to add the USSD endpoint at the end of the file.
<?php
use App\Http\Controllers\UssdController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "api" middleware group. Make something great!
|
*/
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::post('ussd', UssdController::class)->name('ussd');
Let us create our first USSD state that guest users will see.
php artisan ussd:state GuestMenuState --init
Go to the generated file app/Ussd/States/GuestMenuState
and edit the content to look like this:
<?php
namespace App\Ussd\States;
use Sparors\Ussd\Contracts\InitialState;
use Sparors\Ussd\Menu;
class GuestMenuState implements InitialState
{
public function render(): Menu
{
return Menu::build()
->line('Banc')
->listing([
'Register',
'Helpline',
])
->text('Powered by Sparors');
}
}
Back to the USSD controller app/Http/Controllers/UssdController.php
, let's create a USSD app inside __invoke function.
<?php
namespace App\Http\Controllers;
use App\Ussd\States\GuestMenuState;
use Illuminate\Http\Request;
use Sparors\Ussd\Context;
use Sparors\Ussd\Ussd;
class UssdController extends Controller
{
/**
* Handle the incoming request.
*/
public function __invoke(Request $request)
{
$lastText = $request->input('text') ?? '';
if (strlen($lastText) > 0) {
$lastText = explode('*', $lastText);
$lastText = end($lastText);
}
return Ussd::build(
Context::create(
$request->input('sessionId'),
$request->input('phoneNumber'),
$lastText
)
->with(['phone_number' => $request->input('phoneNumber')])
)
->useInitialState(GuestMenuState::class)
->run();
}
}
Now access your USSD controller from a rest client, simulating how africastalking send the request.
You should see a response like this:
{
"message": "Banc\n1.Register\n2.Helpline\nPowered by Sparors",
"terminating": false
}
This does not match the response africastalking is expecting. Let fix that by creating a new response.
php artisan ussd:response AfricasTalkingResponse
Update the generated file app/Ussd/Responses/AfricasTalkingResponse.php
to:
<?php
namespace App\Ussd\Responses;
use Sparors\Ussd\Contracts\Response;
class AfricasTalkingResponse implements Response
{
public function respond(string $message, bool $terminating): mixed
{
return response(
($terminating ? 'END' : 'CON') . ' ' . $message,
200,
['Content-Type' => 'text/plain']
);
}
}
Then update ussd controller to:
<?php
namespace App\Http\Controllers;
use App\Ussd\Responses\AfricasTalkingResponse;
use App\Ussd\States\GuestMenuState;
use Illuminate\Http\Request;
use Sparors\Ussd\Context;
use Sparors\Ussd\Ussd;
class UssdController extends Controller
{
/**
* Handle the incoming request.
*/
public function __invoke(Request $request)
{
$lastText = $request->input('text') ?? '';
if (strlen($lastText) > 0) {
$lastText = explode('*', $lastText);
$lastText = end($lastText);
}
return Ussd::build(
Context::create(
$request->input('sessionId'),
$request->input('phoneNumber'),
$lastText
)
->with(['phone_number' => $request->input('phoneNumber')])
)
->useInitialState(GuestMenuState::class)
->useResponse(AfricasTalkingResponse::class)
->run();
}
}
You should now see the following response:
CON Banc
1.Register
2.Helpline
Powered by Sparors
Let us create the helpline state.
php artisan ussd:state HelplineState
Update the generated file app/Ussd/States/HelplineState
to look like this.
<?php
namespace App\Ussd\States;
use Sparors\Ussd\Attributes\Terminate;
use Sparors\Ussd\Contracts\State;
use Sparors\Ussd\Menu;
#[Terminate]
class HelplineState implements State
{
public function render(): Menu
{
return Menu::build()
->line('Helpline')
->listing([
'email: [email protected]',
'phone: +233 241 122 333'
]);
}
}
Then edit app/Ussd/States/GuestMenuState
to look like this.
<?php
namespace App\Ussd\States;
use Sparors\Ussd\Attributes\Transition;
use Sparors\Ussd\Contracts\InitialState;
use Sparors\Ussd\Decisions\Equal;
use Sparors\Ussd\Menu;
#[Transition(HelplineState::class, new Equal(2))]
class GuestMenuState implements InitialState
{
public function render(): Menu
{
return Menu::build()
->line('Banc')
->listing([
'Register',
'Helpline',
])
->text('Powered by Sparors');
}
}