nedgen / cakephp-soldo
Soldo plugin for CakePHP
Installs: 91
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 1
Forks: 0
Open Issues: 0
Type:cakephp-plugin
Requires
- php: >=5.6
- cakephp/cakephp: ^3.5
- muffin/webservice: ^2.0
- phpseclib/phpseclib: ^3.0
Requires (Dev)
- phpunit/phpunit: ^5.7.14|^6.0
README
Installation
You can install this plugin into your CakePHP application using composer:
$ composer require nedgen/cakephp-soldo
Load the plugin
Launch the following command:
$ bin/cake plugin load Soldo -b
You should see this in src/Application.php
:
class Application extends BaseApplication { public function bootstrap() { $this->addPlugin('Soldo', ['bootstrap' => true]); // ... } // ... }
Configure the datasource
Add the following to the Datasources item in the config/app.php
file:
return [ // ... 'Datasources' => [ // ... 'soldo' => [ 'className' => \Muffin\Webservice\Connection::class, 'service' => \Soldo\Webservice\Driver\Soldo::class, 'client_id' => '', // Replace with the actual value 'client_secret' => '', // Replace with the actual value 'token' => '', // Replace with the actual value 'private_key' => '', // Replace with the RSA private key you shared with Soldo, encoded in Base64 'environment' => '', // One of "production" or "demo" 'autologin' => true, // Whether to try to authenticate as soon as the plugin is initialized, or wait until needed ], ], ];
The token and private_key items are optional, but they are both needed if you need to make requests where the advanced authentication is required.
Examples:
return [ // ... 'Datasources' => [ // ... 'soldo' => [ 'className' => \Muffin\Webservice\Connection::class, 'service' => \Soldo\Webservice\Driver\Soldo::class, 'client_id' => 'sHR2rMC7yVAxWxkgRPg0LEIHpCXmpj1s', 'client_secret' => 'LTVBbG2EnUB1mc30ep3pTgheyCh5WK8O', 'environment' => 'demo', 'autologin' => true, ], ], ];
return [ // ... 'Datasources' => [ // ... 'soldo' => [ 'className' => \Muffin\Webservice\Connection::class, 'service' => \Soldo\Webservice\Driver\Soldo::class, 'client_id' => 'NF1gtE1dhuwR6Yk5bDcUsdGXtnSgTaGW', 'client_secret' => 'g50Xc5TOzMqa2jdBa3dNZ8H7ysKd9mYl', 'token' => 'VK6AEW2IAF3SR29SJW4L', 'private_key' => 'LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpjYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkCm9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2wKZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zbwpsZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zCm9sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC0Kc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocAotc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBoCnAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXAKaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZQpwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrCmVwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2EKa2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvYwpha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvCmNha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGQKb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbApkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvCmxkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXMKb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLQpzb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwCi1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGgKcC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcApocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlCnBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWsKZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYQprZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaAotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ==', 'environment' => 'production', 'autologin' => false, ], ], ];
Usage
The following Soldo resources are currently supported:
Note: For all the resources listed above, only read queries are currently supported, except for internal transfers.
Reading
The following code shows an example for the Card resource:
namespace App\Controller; /** * ... * * @property \Soldo\Model\Endpoint\CardsEndpoint $Cards */ class CardsController extends AppController { public function initialize() { $this->loadModel('Soldo/Soldo.Cards', 'Endpoint'); } public function index() { $cards = $this->Cards->find() ->select([ 'id', 'number' => 'masked_pan', 'custom_field' => 'foo', ]) ->where([ // GET parameters as expected from Soldo for this resource 'type' => 'wallet', 'customreferenceId' => '1368e647-842b-4d17-9a1a-2ad225e6dc1a', ]) ->order(['name' => 'DESC']) ->limit(10) ->toArray(); $card = $this->Cards->get('ef12ee12-5cfa-4175-b7e6-665d112aea0e', [ 'conditions' => [ // GET parameters as expected from Soldo for this resource 'showSensitiveData' => 'true', ] ]); } }
$cards
will look like this:
array (size=10) 0 => object(Muffin\Webservice\Model\Resource)[2554] public 'id' => string 'df832760-e49b-4699-b34a-46824060bf40' (length=36) public 'number' => string '098765******4321' (length=16) public 'custom_field' => string 'foo' (length=3) 1 => object(Muffin\Webservice\Model\Resource)[3094] public 'id' => string 'a438c8d6-1d94-4ed3-8895-d4565246f647' (length=36) public 'number' => string '123456******7890' (length=16) public 'custom_field' => string 'foo' (length=3) ...
$card
will look like this:
object(Muffin\Webservice\Model\Resource)[2555] public 'id' => string 'ef12ee12-5cfa-4175-b7e6-665d112aea0e' (length=36) public 'name' => string 'Bar' (length=12) public 'masked_pan' => string '012345******6789' (length=16) public 'expiration_date' => string '2025-12-31T23:59:59Z' (length=20) public 'creation_time' => string '2022-12-10T19:11:18Z' (length=20) public 'last_update' => string '2023-04-11T08:07:38Z' (length=20) public 'type' => string 'PLASTIC' (length=7) public 'status' => string 'Normal' (length=6) public 'owner_type' => string 'company' (length=7) public 'wallet_id' => string 'a73b9699-9436-4381-951d-a9da2fd6d439' (length=36) public 'currency_code' => string 'EUR' (length=3) public 'emboss_line4' => string 'Baz' (length=13) public 'active' => boolean true public 'method3ds' => string 'USER' (length=4) public 'sensitive_data' => array (size=3) 'encrypted_full_pan' => string 'MDEyMzQ1MDAwMDAwNjc4OWNha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHA=' (length=344) 'encrypted_cvv' => string 'MTIzY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHA=' (length=344) 'encrypted_pin' => string 'MTIzNGNha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGhwLXNvbGRvY2FrZXBocC1zb2xkb2Nha2VwaHAtc29sZG9jYWtlcGg=' (length=344) public 'assignees' => array (size=0) empty
Internal transfers
The only non-reading request currently supported by this plugin are internal transfers.
The following code shows an example on how to make one:
namespace App\Controller; /** * ... * * @property \Soldo\Model\Endpoint\TransfersEndpoint $Transfers */ class WalletsController extends AppController { public function initialize() { $this->loadModel('Soldo/Soldo.Transfers', 'Endpoint'); } public function add() { $transfer = $this->Transfers->newEntity([ 'fromWalletId' => '288ae0a2-4d53-4d3f-b8f9-63cbe3b06429', 'toWalletId' => '655192d7-80eb-4018-a9d3-2b9843aa4a64', 'amount' => 10, 'currencyCode' => 'EUR' ]); $result = $this->Transfers->save($transfer); } }
$result
will look like this:
object(Muffin\Webservice\Model\Resource)[1319] public 'amount' => int 10 public 'currency' => string 'EUR' (length=3) public 'datetime' => string '2024-03-01T07:36:29.509Z' (length=24) public 'from_wallet' => array (size=7) 'id' => string '288ae0a2-4d53-4d3f-b8f9-63cbe3b06429' (length=36) 'name' => string 'Foo' (length=3) 'currency_code' => string 'EUR' (length=3) 'available_amount' => float 90 'blocked_amount' => float 0 'primary_user_type' => string 'main' (length=4) 'visible' => boolean true public 'to_wallet' => array (size=8) 'id' => string '655192d7-80eb-4018-a9d3-2b9843aa4a64' (length=36) 'name' => string 'Bar' (length=3) 'currency_code' => string 'EUR' (length=3) 'available_amount' => float 10 'blocked_amount' => float 0 'primary_user_type' => string 'employee' (length=8) 'primary_user_public_id' => string 'ABCD1234-000000' (length=15) 'visible' => boolean true
Decrypting encrypted data
There are cases in which the data returned by Soldo is encrypted. In case you need to decrypt them, this plugin has a specific static function that allows you to do so.
Below is an example:
namespace App\Controller; use Soldo\Utility\Fingerprint; /** * ... * * @property \Soldo\Model\Endpoint\CardsEndpoint $Cards */ class CardsController extends AppController { public function initialize() { $this->loadModel('Soldo/Soldo.Cards', 'Endpoint'); } public function index() { $card = $this->Cards->get('ef12ee12-5cfa-4175-b7e6-665d112aea0e', [ 'conditions' => [ 'showSensitiveData' => 'true', ] ]); $decrypted_full_pan = Fingerprint::decrypt($card->sensitive_data['encrypted_full_pan']); } }
$decrypted_full_pan
will look like this:
'0123450000006789' (length=16)