okaforpeter / ussd
Laravel PHP USSD适配器
Requires
- php: ^7.3|^8.0
- ext-json: *
- ext-simplexml: *
- laravel/framework: >=5.8
- tnmdev/ussd-simulator: dev-master
- dev-master
- v2.0.0
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.1
- v1.1.0
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- v0.13.0
- v0.12.13
- v0.12.12
- v0.12.11
- v0.12.10
- v0.12.9
- v0.12.8
- v0.12.7
- v0.12.6
- v0.12.5
- v0.12.4
- v0.12.3
- v0.12.2
- v0.12.1
- v0.12.0
- v0.11.0
- v0.10.13
- v0.10.12
- v0.10.11
- v0.10.10
- v0.10.9
- v0.10.8
- v0.10.7
- v0.10.6
- v0.10.5
- v0.10.4
- v0.10.3
- v0.10.2
- v0.10.1
- v0.10.0
- v0.9.11
- v0.9.10
- v0.9.9
- v0.9.8
- v0.9.7
- v0.9.6
- v0.9.5
- v0.9.4
- v0.9.3
- v0.9.2
- v0.9.1
- v0.9.0
- v0.8.1
- v0.8.0
- v0.7.1
- v0.6.0
- v0.5.3
- v0.5.2
- v0.5.1
- v0.5.0
- v0.4.3
- v0.4.2
- v0.4.1
- v0.4.0
- v0.3.3
- v0.3.2
- v0.3.1
- v0.3.0
- v0.2.3
- v0.2.2
- v0.2.1
- v0.2.0
- v0.1.2
- v0.1.1
- v0.1.0
- dev-development
This package is auto-updated.
Last update: 2024-09-30 01:21:47 UTC
README
此包创建了一个适配器、样板代码和功能,允许您与USSDC交互,并向您的API提供USSD通道。该接口是开放的,并已记录,可用于实现各种USSD接口。
安装
composer require okaforpeter/ussd
然后安装ussd脚手架。这将运行迁移以创建会话跟踪表。
php artisan ussd:install
安装此包后,USSD应用将通过/api/ussd端点可用。将在App\Screens\Welcome.php为您创建一个着陆屏幕。
使用方法
创建USSD屏幕
php artisan make:ussd <name>
这将为您创建一个样板USSD屏幕对象。您可以继续编辑message、options和execute方法的内容。该屏幕扩展了TNM\USSD\Screen类,这为您提供了访问请求细节和编码USSD响应的手段。
Request对象
Screen有$request作为公共属性。这是一个TNM\USSD\Http\Request类的对象。
请求类公开了从USSDC传递的XML请求中的四个属性。
发送给用户的USSD屏幕由Screens表示,它扩展了TNM\USSD\Screen类。
请求负载
您可以使用请求负载在屏幕之间移动负载。会话中其他请求可以访问添加到请求负载中的任何数据。
设置请求负载
可以通过在请求的跟踪对象上调用addPayload方法来添加请求负载。它接受一个键值对参数。
$this->addPayload('key', $this->value());
检索请求负载
$this->payload('key');
在负载中使用数组
有时您有用于选项的关联数组。例如,您可以有一个包含id、price、name和humanized的产品列表。其中name是系统中对产品的引用,而humanized是您希望在屏幕上显示的方式。
可以使用第三个布尔参数将此类项目数组推送到负载中。这告诉跟踪对象在存储之前序列化输入。
$this->addPayload('products', $array, true);
通过TNM\USSD\Traits命名空间中的HasBundledOptions特质,可以操纵数组负载。因此,要在负载中使用数组,您需要在您的Screen中使用HasBundledOptions特质。
以下是捆绑选项特质的一些用途:要将关联数组作为USSD选项列表/映射,可以使用map方法映射到您选择的数组键。
public function options(): array { return $this->map('humanized', 'products'); }
map方法接受两个参数。第一个是要映射的数组键,第二个是要从负载中列出的负载键。
当用户在USSD屏幕上做出选择时,可以通过调用find方法映射回关联数组选项的任何键。
$this->addPayload('chosenProduct', $this->find('id', 'products'));
上面代码段中的实现,将所选产品的 ID 分配给负载密钥 chosenProduct。特性会查找作为第二个参数传递的用户选项。您可以通过传递第三个参数来指定要查找的字段,默认为 humanized。所以假设您的选项关联数组将有一个用于显示内容的字段。您可以将其重命名为任何适合您的名称。只需确保传递第三个参数以告诉方法在哪里查找即可。
在其他情况下,您可能只想获取特定负载键上的整个数组。方法和普通负载相同,再次带有第二个布尔参数。
$this->payload('products', true);
必须方法
Screen 类将要求您实现以下方法。
message()必须返回一个字符串消息,该消息将在屏幕上显示。options()必须返回一个选项数组,这些选项将向用户公开。对于不需要选项的屏幕,返回空数组。execute()应用于实现应用对请求数据的处理。请求数据由屏幕对象的getRequestValue()返回。您可以使用它来访问请求数据。如果您想将用户重定向到另一个屏幕,请返回目标屏幕的render()方法:return (new Register($this->request))->render()。屏幕初始化需要一个参数,即request对象。previous()应返回一个Screen类的对象。它告诉会话在用户选择后退选项时导航到何处。
可选方法
您可以通过扩展以下方法来更改屏幕的一些属性。
type()应返回一个整数,委托给TNM\USSD\Response类的RELEASE和RESPONSE常量。如果没有覆盖,则默认为RESPONSE。RESPONSE渲染一个带有输入字段的屏幕,而RELEASE渲染一个不带输入字段的屏幕,用于指示 USSD 网关关闭 USSD 会话。acceptsResponse(),而不是type()方法的复杂性,您可以使用acceptsResponse()。它应返回一个布尔值,指示屏幕是否渲染输入字段或发送一个标记 USSD 会话结束的屏幕。goesBack()返回一个布尔值,定义屏幕是否应该有back导航选项。除非您正在定义登录屏幕,否则您可以保留它。
异常处理
USSD 适配器有一个自渲染的异常处理器。要使用它,请从 TNM\USSD\Exceptions 命名空间中抛出 UssdException。它接受两个参数:请求对象和要传递给用户的消息。异常处理器将渲染一个带有错误消息的 USSD 屏幕,并终止会话。
输入数据验证
您可以使用 TNM\USSD\Http 命名空间的 Validates 特性来设置规则以验证用户输入。轨迹将要求您实现 rules() 方法,该方法应返回一个验证规则字符串。
要在 Screen 类的 execute() 方法中调用 $this->validate($this->request, $label) 以验证输入。
如果输入有验证错误,将抛出 TNM\USSD\Exceptions 命名空间的 ValidationException,并将为您自动渲染一个错误屏幕。
namespace App\Screens; use TNM\USSD\Screen; use TNM\USSD\Http\Validates; class EnterPhoneNumber extends Screen { use Validates; protected function message() : string { return 'Enter your phone number'; } //... protected function execute() { $this->validate($this->request, 'phone'); $this->addPayload('phone', $this->value()); return (new NextScreen($this->request))->render(); } protected function rules() : string { return 'regex:/(088)[0-9]{7}/'; } }
扩展以实现多个实现
此适配器设计时考虑了可扩展性。目前它支持 TNM 和 Airtel Malawi 分别使用的 TruRoute 和 Flares USSD 接口。然而,由于可插拔的接口,它可以扩展以支持任何移动网络运营商。
要扩展,创建请求和响应类。这些类必须分别实现 TNM\USSD\Http\UssdRequestInterface 和 TNM\USSD\Http\UssdResponseInterface。
请求类的实现细节可能有所不同。然而,我们强烈建议有一个构造函数,该构造函数将来自移动运营商的USSD请求解码成数组,并将该数组分配给$request私有属性,并且接口方法应该基于私有属性返回它们的值。
示例请求实现
use TNM\USSD\Http\UssdRequestInterface; class TruRouteRequest implements UssdRequestInterface { /** * @var array */ private $request; public function __construct() { $this->request = json_decode(json_encode(simplexml_load_string(request()->getContent())), true); } public function getMsisdn(): string { return $this->request['msisdn']; } // ... }
必需方法
请求接口要求您实现以下方法
getSession()应该返回由USSD网关分配的会话idgetMsisdn()应该返回发起USSD请求的msisdngetMessage()应该返回与请求一起发送的消息getType()应该返回请求的类型。
示例响应实现
以下是一个示例响应类实现。它有一个必需的公共方法:respond,它必须以网络运营商所需格式返回一条消息。
use TNM\USSD\Http\UssdResponseInterface; use TNM\USSD\Screen; class TruRouteResponse implements UssdResponseInterface { public function respond(Screen $screen) { return sprintf( "<ussd><type>%s</type><msg>%s</msg><premium><cost>0</cost><ref>NULL</ref></premium></ussd>", $screen->type(), $screen->getResponseMessage() ); } }
路由
您可以使用路由参数adapter区分来自不同移动运营商的请求。
所有使用Flares适配器的网络请求应路由到api/ussd/flares。因此,当您创建自己的扩展时,运营商的路由应为api/ussd/{adapter}。
这不是神奇地解决的。您需要定义在TNM\USSD\Factories\RequestFactory和TNM\USSD\Factories\ResponseFactory中的实现。
示例请求工厂
namespace TNM\USSD\Factories\RequestFactory; class RequestFactory { public function make(): UssdRequestInterface { switch (request()->route('adapter')) { case 'flares' : return resolve(FlaresRequest::class); default: return resolve(TruRouteRequest::class); } } }
示例响应工厂
namespace TNM\USSD\Factories\ResponseFactory; class ResponseFactory { public function make(): UssdResponseInterface { switch (request()->route('adapter')) { case 'flares': return resolve(FlaresResponse::class); default: return resolve(TruRouteResponse::class); } } }
本地化
您可以在应用程序的任何屏幕上设置会话语言。以下屏幕将以新选定的语言显示。
$this->request->trail->setLocale('en');
此功能实现了Laravel的本地化,使用语言文件。有关更多详细信息,请参阅Laravel文档。因此,您的实现可以如下所示
public function message(): string { return __("screens.welcome_message"); }
示例本地化实现
public function execute() { $locale = $this->value() == 'English' ? 'en' : 'fr'; $this->request->trail->setLocale($locale); return (new NextScreen($this->request))->render(); }
审计
您可以使用CLI工具跟踪用户会话、系统消息和用户响应。
php artisan ussd:list <phone>
此命令为您提供了一个列表,其中包含一个数字所做的所有交易。列表包含会话ID和时间戳。
php artisan ussd:audit <session-id>
此命令为您提供从会话开始到结束的所有交易的详细信息。该轨迹包括系统消息、用户对每条消息的响应以及它们的按时间顺序的时间戳。
当用户响应是选项时,它报告一个代表所选数字的字符串值,从而让您免于查找哪个选项位于数字1、2等。
会话数据清理
此软件包使用数据库表跟踪会话。此数据库表可能需要一段时间后进行清理。要清理,请在应用程序目录中运行以下命令。
php artisan ussd:clean-up --days=30
它接受要保留的天数的数据选项。如果没有传递选项,则删除60天以上的所有内容。
- 关于审计的说明:对于已清理的数据,将不会提供审计跟踪。
示例屏幕实现
// app/Screens/Subscribe.php namespace App\Screens; use TNM\USSD\Screen; class Subscribe extends Screen { public function message(): string { return "Please select a plan you want to subscribe to"; } public function options(): array { return ['Plan 1', 'Plan 2', 'Plan 3']; } public function execute() { // save the request value to session object // to access it in the next screen with $this->payload($key) $this->addPayload('plan', $this->value()); return (new ConfirmSubscription($this->request))->render(); } public function previous(): Screen { return new Welcome($this->request); } }
// app/Screens/ConfirmSubscription.php namespace App\Screens; use Exception;use TNM\USSD\Screen; use TNM\USSD\Exceptions\UssdException; class ConfirmSubscription extends Screen { public function message(): string { return sprintf("Please confirm subscription to %s", $this->payload('plan')); } public function options(): array { return ['Confirm', 'Cancel']; } public function execute() { if ($this->value() === 'Cancel') return $this->previous()->render(); $service = new SubscriptionService($this->request->msisdn); try { $service->subscribe($this->payload('plan')); return (new Subscribed($this->request))->render(); } catch (Exception $exception) { throw new UssdException($this->request, "Subscription failed. Please try again later"); } } public function previous(): Screen { return new Subscribe($this->request); } }