承接 adelowo/gbowo 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

adelowo/gbowo

Composer 安装命令:

composer require adelowo/gbowo

包简介

Unified API for hippy Nigerian payment gateways..Batteries included. Comes with adapters for Paystack and Amplifypay

README 文档

README

Latest Version on Packagist Software License Build Status Scrutinizer Coverage Quality Score Total Downloads

Installation

Install Gbowo via one of the following methods :

    composer require "adelowo/gbowo" : "~1.0"

Usage

require_once 'vendor/autoload.php';

$adapter = new \Gbowo\Adapter\Paystack\PaystackAdapter();

$response = $adapter->charge();

For the paystack and amplifypay adapters, the response received would be a string, which denotes an authorization__url. You are to make a redirect to the url to complete the transaction.

Other adapters implementation may do something much different like redirect internally ( from the adapter) but this isn't done for good reasons. This is because different systems may have different ways of performing redirects via Request or Response objects, or whatever have they. So as long as you can get the returned url, you can use the Adapter in your framework or whatever have you.

A basic example would be something like

header("Location : {$response}");
exit();

Adapters

Quick usage

$adapter = (new \Gbowo\GbowoFactory())->createAdapter("paystack"); //or "amplifypay"

return $adapter->charge();

Usage in depth

Gbowo ships with two adapters : one for paystack and the other for Amplifypay.

While both payment gateway offer similar features, there are a few subtle differences (obviously).

Gbowo requires some value to be present in the environment i.e $_ENV. For paystack, this is $_ENV['PAYSTACK_SECRET_KEY'] while the amplifypay adapter requires two values : your merchant id and an api key. This should be present in the following format : $_ENV['AMPLIFYPAY_MERCHANT_ID'] and $_ENV['AMPLIFYPAY_API_KEY'].

You are strongly advised to keep your keys and/or tokens out of your code and instead load them into $_ENV by some other means. We don't enforce this but it is a best practice, 12 Factor App Guideline. A library that would help with this is vlucas/phpdotenv. All it needs is a .env file and you are golden. Remember not to commit the .env else it still isn't out of your "code". A sample .env.example has been provided in the resources directory. You can copy and rename that to .env in your root dir.

$paystack = new \Gbowo\Adapter\Paystack\PaystackAdapter();

$amplifyPay = new \Gbowo\Adapter\Amplifypay\AmplifypayAdapter()

A GuzzleHttp Client instance would be created automatically and values gotten from the $_ENV would be used to set the appropriate authorization headers where applicable.

You can prevent this "auto-wiring" by providing an instance of Guzzlehttp Client in the constructor.

$client = new \GuzzleHttp\Client(['key' => "value"]);

$amplifyPay = new \Gbowo\Adapter\Amplifypay\AmplifypayAdapter($client)

The payment flow for both adapters is pretty much the same. User initiates first time / one time transaction and is redirected to a secure page where payment details are to be inputted. After this (a successful payment request), the gateway would issue a redirect to a url you have supplied them as a callback. In this url, you should fetch the details of a user (who is now a customer) such as an authorization_code , transaction_reference among others. This is for recurrent transactions and should be persisted to a storage mechanism.

Initiating the transaction should be performed by calling the charge method on the adapter. And making a redirect where applicable to the response as described earlier.

To fetch the data from the url callback you have registered on your chosen gateway, you have to call the getPaymentData method on the adapter. It's response would contain some data about the customer.

//paystack adapter
var_dump($adapter->getPaymentData($_GET['trxref'])) ; //you should clean this up.

//amplifypay adapter
var_dump($adapter->getPaymentData($_GET['tran_response'])); // clean up

The getPaymentData method can also be called on some transaction reference you have stored in your db or some other form of storage mechanism.

When you call the getPaymentData on the paystack adapter. The reference is verified by paystack before a response is sent

Adapters Methods.

Paystack :

  • charge(array $data = [])
  • getCustomer(int $id)
  • getAllCustomers()
  • chargeWithToken(array $userToken) // a token plus email address (or custom stuff)
  • getPaymentData(string $transRef)
  • fetchPlan($planIdentifier)
  • fetchAllPlans()

Checkout gbowo-paystack . It contains an additional set of plugins for the paystack adapter.

Amplifypay :

  • charge(array $data = [])
  • unsubcribeCustomerFromPlan(array $data)
  • chargeWithToken(array $userToken) //a token in amplifypay is a key pair of values.
  • getPaymentData(string $transRef)
  • fetchPlan($planIdentifier)
  • fetchAllPlans()

The charge method parameter (array $data = []) should contain stuffs like amount, email, x, y, z). Those would be handed over to the payment gateway

Custom Adapters

Using laravel, please check out how to add your custom adapter

//let's assume it is an enterprisey app

$interswitch = new class implements \Gbowo\Contract\Adapter\AdapterInterface
{
    protected $interswitch;

    public function __construct()
    {
        $this->interswitch = new \stdClass(new \ArrayObject(new \stdClass())); // It wasn't me
    }

    public function charge(array $data = [])
    {
        return "charged by interswitch";
    }
};

$adapter = new \Gbowo\GbowoFactory(["interswitch" => $interswitch]); //add the interswith adapter as a custom one.

$interswitchAdapter = $adapter->createAdapter("interswitch");

$interswitchAdapter->charge(['a' => 'b', 'c' => 'd']);

Extending Adapters via Plugins

Different gateways implement various features and there's no way we can support all of them without losing our sanity.

Supporting all features would lead to a bloat (an interface, class bloat). Take for instance : create InterfaceX to support feature X for AdapterE while AdapterE still makes use of features (and therefore interfaces) for AdapterA,AdapterQ and so on. Now imagine this scenario plays out for 4 -5 adapters.

Apart from the bloat, we cannot create a (visual) diagram of which interfaces are being used and it'd lead to a situation where we cannot remove a certain class or interface because we do not know who (what adapter) depends on them.

To prevent this, Gbowo implements a plugin architecture that eases extension or "adding new methods/behaviours" to an existing adapter without inheritance or touching core code. To achieve this, there is a Pluggable trait that contains the logic and MUST be imported by an adapter implementation.

A look at the paystack adapter and amplifypay would reveal that they do not have the methods described above in their public api. In fact they expose only 3 methods :

  • __construct(Client $client = null) // if it counts as one
  • getHttpClient()
  • charge(array $data = []) //This is gotten from the AdapterInterface implemented.

But a look at their registerPlugins method - which is gotten from the Pluggable trait - tells how the methods described in the Adapters method section above come about.

A plugin is a plain PHP class that MUST implement the PluginInterface. This interface exposes two methods :

  • getPluginAccessor() : string
  • setAdapter(Adapter $adapter)
  • handle(string $reference) //Typehint as much as you want. 2,3 args ? Your call.

I have written a detailed post about this here

namespace Vendor\AdapterName\Plugin;

use Gbowo/Contract/Plugin/PluginInterface;
use Gbowo\Exception\TransactionVerficationFailedException;

class ApiPinger implements PluginInterface
{

    public function getPluginAccessor():string
    {
        return "pingApi"; //Oops.. Let's confirm if the api isn't dead before making any request. And it must be a string without parenthesis
    }

    /**
     * You can also leave this method out but you must extend the `AbstractPlugin` class. Doing so, means you'd have to get rid of the plugin interface here as the abstract plugin already does that.
     */
    public function setAdapter(AdapterInterface $adapter)
    {
        //useful for helpers like getting stuffs from "accessors" on the adapter instance like the already configured HttpClient object
        $this->adapter = $adapter ;
        return $this;
    }

    /**
     * Ping the gateway Api
     * @param  bool $shouldThrow. Should an exception be thrown if the api is down ?.
     * @return bool true - if the api is up and running.
                   false - if the api is down and $throw is set to false.
     * @throws \Exception if the api is down and $throw is set to false.
     */
    public function handle(bool $shouldThrow = false)
    {
        $response = $this->adapter->getHttpClient()->get("https://api.homepage.com");

        if ($response->getStatusCode() === 200 ) {
            return true;
        }

        if ($shouldThrow) {
            throw TransactionVerficationFailedException::createFromResponse($response);
        }

        return false;
    }
}

createFromResponse is a wrapper that allows client code inspect the response for why there was a failure (say an invalid HTTP status code).. You should call getResponse on the exception in other to inspect it. This is also true for official plugins provided by Gbowo.

The getPluginAccessor is of tremendous interest here since it determines what plugin the method call should be deferred to. This is done by the magic method __call in the Pluggable trait.

$adapter->addPlugin(new Vendor\AdapterName\Plugin\ApiPinger(PaystackAdapter::API_LINK));
//Usage like this

$adapter->pingApi(true);
$adapter->pingApi();

Not all plugins would make it to the core eventually and not even all plugins in the core would be "added" on instantiation. For instance, the GetAllCustomers plugin isn't added to the PaystackAdapter internally. To use the plugin, you'd have to add it yourself.

$adapter->addPlugin(new GetAllCustomers(PaystackAdapter::API_LINK))

Framework Integration

Laravel

Prior to v1.5.0, a Laravel bridge was provided alongside this package but in light of best interests, it has been moved to it's own repository.

If upgrading from a previous version to v1.5.0, please note that you would have to run composer require adelowo/laravel-gbowo

Please note that the decision to give the Laravel bridge a life of it's own doesn't mean BC break. The namespaces were preserved and would continue to work as is.

Sample App

Gbowo-app - Built with SlimPHP.

Contributing

Awesome, I'd love that. Fork, send PR. But hey, unit testing is one honking great idea. Let's have more of that.

Bug Reports, Issue tracking and Security Vulnerabilities

Please make use of the issue tracker for bug reports, feature request and others except Security issues. If you do discover a vulnerability, please send a mail to me@lanreadelowo.com.

License

MIT

adelowo/gbowo 适用场景与选型建议

adelowo/gbowo 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 203 次下载、GitHub Stars 达 22, 最近一次更新时间为 2016 年 10 月 21 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「php」 「github」 「payments」 「paystack」 「AmplifyPay」 「Nigerian Payments」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 adelowo/gbowo 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 adelowo/gbowo 我们能提供哪些服务?
定制开发 / 二次开发

基于 adelowo/gbowo 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 203
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 23
  • 点击次数: 20
  • 依赖项目数: 2
  • 推荐数: 0

GitHub 信息

  • Stars: 22
  • Watchers: 1
  • Forks: 5
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2016-10-21