GithubHelp home page GithubHelp logo

sdk_php's People

Contributors

andrederoos avatar angelomelonas avatar babydino avatar bunq-bot avatar cafferata avatar casperboone avatar d0x7 avatar davide-giordano avatar dennissnijder avatar dnl-blkv avatar erkens avatar holtkamp avatar jorijn avatar laulaman avatar lexym avatar nickvandegroes avatar ogkevin avatar qurben avatar sailingdeveloper avatar sandervdo avatar smukhibillaev avatar wouterflorijn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sdk_php's Issues

Allow saving context to JSON and restoring from it

How to Reproduce

  1. Look at the methods of ApiContext

What Should Happen

  1. toJson and fromJson methods allowing to save context to or load from JSON are present

What Happens

  1. There are no toJson nor fromJson

cURL error 0

When I use the ApiContext::create() function I get a cURL error. Does anybody know why this error shows up or how to fix it?

An unexpected error occurred: cURL error 0: The cURL request was retried 3 times and did not succeed. The most likely reason for the failure is that cURL was unable to rewind the body of the request and subsequent retries resulted in the same error. Turn on the debug option to see what went wrong. See https://bugs.php.net/bug.php?id=47204 for more information. (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)

Update: I get the same issue when I use the install command

Better error handling

Steps to reproduce:

  1. Look at the exceptions that the SDK throws.

What should happen:

  1. The SDK has at least 1 exception per error status code (400+).

What happens:

  1. The SDK will only throw exceptions of two types: client-side and server-side.

Error in api context script

description

The scripts used to create an API context throw errors after inserting the API-key.
Error:

"Fatal error: Cannot use isset() on the result of an expression (you can use "null !== expression" instead) in /my/project/path/vendor/bunq/sdk_php/src/Model/BunqModel.php on line 180"

How to reproduce

  • Run the command "vendor/bin/bunq-install" in the project root folder, the error will be thrown after entering the enviroment and API-key.
  • Run the "api_context_save_example.php".

Initial feedback on project (organization)

Some feedback on the current approach:

  • why support both PHP 5.6 AND 7 and not only use / support PHP 7?
    • this is a new SDK, might be good to use that in your advantage by reducing need for backward compatibility of PHP 5.6
    • way better support for scalar and complex types, reducing chance of bugs / extensive unit tests
    • support for visibility (public, protected, private) of constants, which seem to be used extensively in the code
  • version number in composer.json should be omitted
  • composer.lock should probably not be committed to repository and part of .gitignore
  • .idea folder should probably not be committed to repository and part of .gitignore
  • the lib folder should "probably" be renamed to src
    • I believe this is not a "hard" rule, more of a PSR4 coding convention... lib suggests 3rd party code, while src is "your" code...

Add header verification test 

Steps to reproduce:

  1. Response verification should be tested,

What should happen:

  1. Response verification is not tested.

What happens:

  1. Response verification is tested.

Logs

  • Logs no logs

Extra info:

References

Assert that variables are correct when creating an ApiContext with code.

How to Reproduce

  1. Create an ApiContext with an invalid API Key, description or IP address

What Should Happen

  1. The process fails before any API calls are made because of the invalid data

What Happens

  1. An API call is made, and API returns an error saying that API Key / description / IP address was invalid

Add response id to error messages from failed requests 

Steps to reproduce:

  1. Make a bad request
  2. Try and get the response id from the X-Bunq-Server-Response-Id header.

What should happen:

  1. There is a way to get the response id to debug this error on bunq's side if needed.

What happens:

  1. 👆 is not possible.

Logs

  • Logs 'no logs

Extra info:

References

User::get returns empty object?

When I try to use the User::get function a User object will return but its completely empty.
image

I did some further debugging and it seems like the Response body is completely empty (The status code is still 200 😟 )

Im using the Sandbox Environment and the request url I'm trying to call is sandbox.public.api.bunq.com/v1/user/3427

Introduce fromJson method. 

Steps to reproduce:

  1. Take a look at the methods inside BunqModel

What should happen:

  1. There is a method to convert a JSON to class defined like to_json

What happens:

  1. 👆 is not implemented

Logs

  • Logs no logs

Extra info:

Error retrieving pinned certificates

$apiContext = ApiContext::restore(BUNQ_CONFIG);
$certificateList = CertificatePinned::listing($apiContext, BUNQ_USER_ID);

Provides an error:

Argument 1 passed to bunq\Model\BunqModel::createListFromResponseArray() must be of the type array, string given, called in vendor\bunq\sdk_php\lib\Model\BunqModel.php on line 160

User Agent header generation is broken in ApiClient

How to Reproduce

  1. Make an API request with the latest version of PHP SDK

What Should Happen

  1. Request goes smooth

What Happens

  1. Error

Notes

  1. The error happens because ApiClient tries to get the version from composer.json. However, the version is not present there anymore since #26.

Remove phpstan

Phpstan does not support PHP 5.6, we do. Therefore it is not possible for us to use it.

SDK not working on Windows (XAMPP)

When using XAMPP on a local windows development machine I get the following error:

Error: An unexpected error occurred with status code "400" and message "The request signature is invalid."

Code used:

$environmentType = BunqEnumApiEnvironmentType::SANDBOX();
$apiKey = '### Your API Key ###';
$deviceDescription = '### Your device description ###';
$permittedIps = ['my.local.ip.address'];

$apiContext = ApiContext::create(
    $environmentType,
    $apiKey,
    $deviceDescription,
    $permittedIps
);

This does not happen on Linux machines. It seems to be a problem with the session-server call, the first call that has to be signed.

Add more information to templates

Steps to reproduce:

  1. Create a new issue or pull request

What should happen:

  1. The issue template should include a template to list the SDK version number and link to its release.
  2. There are comments explaining some basic flows.
  3. The PR template should contain a Tested check box and says which issue the PR will close.

What happens:

  1. The template is to basic.

Logs

  • Logs no logs

Extra info:

"HTTP Response Code: 400 The request signature is invalid."

I'm trying to integrate the Bunq API in my Laravel project. The installation is flawless, however when I try to create a request I get an error "HTTP Response Code: 400. The request signature is invalid."

Has this something to do with the fact that I'm using Laravel Valet on my computer?

Steps to reproduce:

  1. Install SDK into laravel project

What should happen:

  1. Create apiContext and get users

What happens:

  1. apiContext gets created but the request fails with the following error:
    HTTP Response Code: 400. The request signature is invalid.

Response is missing response headers and pagination

How to Reproduce

  1. Make a valid listing request to bunq API via the PHP SDK
  2. Make a valid get/put/post/delete request to bunq API via the PHP SDK

What Should Happen

  1. The response contains response headers and pagination
  2. The response contains response headers

What Happens

  1. The response does not contain response header nor pagination
  2. The response does not contain response header

Notes

  1. The structural fix would be to introduce BunqResponse object which, besides the response model, includes the response headers and pagination

Return base class from createFromJsonString

Steps to reproduce:

  1. Create a class from JSON string by using the method createFromJsonString

What should happen:

  1. The return value is casted to the subclass.

What happens:

  1. The return value is casted to BunqModel.

Logs

  • Logs No logs

Extra info:

Improve decoder to recognise child objects

Steps to reproduce:

  1. Try and decode a child object into a model that is expecting its parent

What should happen:

  1. The model is correctly populated with data.

What happens:

  1. All the fields, including the parent field will be null.

Logs

  • Logs no logs

Extra info:

More flexibility for sessionContext handling

Steps to reproduce:

  1. Try and find out if your session context is expired

What should happen:

  1. There is a way to know if your session has expired without resetting/calling ensureSesiosActive()

What happens:

  1. There is no way to achieve such thing

Extra info:

Why

  • This way you wont have to execute this code before each call but only if your session did expire
$apiContext->ensureSessionActive();
$apiContext->save(static::FILENAME_CONTEXT_CONFIG);

Which means you will be saving an unchanged context on each call

Add strictly typed BunqResponses

How to Reproduce

  1. Write code to make a request via the SDK
  2. Write a code using the response of the request from (1)

What Should Happen

  1. The $response.getValue() has a strict type in doc block, and the IDE auto-completion works on it

What Happens

  1. The $response.getValue() doesn't have a strict type in doc block and therefore IDE auto-completion doesn't work on it

End support for PHP 5.6

How to Reproduce

  1. Try composer install with PHP 5.6 for the SDK

What Should Happen

  1. composer install fails, because PHP 5.6 is not supported

What Happens

  1. composer install succeeds
  2. Examples/tests fail due to a PHP 5.6-specific bug

Notes

  1. The SDK was not working with PHP 5.6 for some time, but the question was only raised once, and the questioning person was OK with switching to PHP 7.0
  2. Therefore, in order to be sure we provide best possible SDK for PHP 7.0+, and to contribute to the migration of developers to PHP 7.0 we would like to end support of PHP 5.6
  3. This would mean changes to the code style, such as adding scalar parameter and return type-hints or using other language features introduced in PHP 7.0

toJson() fails on ApiContext of an user person due to session context

Steps to reproduce:

  1. Make an ApiContext with an UserPerson API key
  2. Call the toJson() method on this context

What should happen:

  1. The user will get a JSON representation of the ApiContext

What happens:

  1. You will get the following error:
Return value of bunq\Model\Core\SessionServer::getUserCompany() must be an instance of bunq\Model\Generated\Endpoint\UserCompany, null returned
 /Users/khellemun/GitHub/bunq/sdk_php/src/Model/Core/SessionServer.php:79
 /Users/khellemun/GitHub/bunq/sdk_php/src/Context/SessionContext.php:76
 /Users/khellemun/GitHub/bunq/sdk_php/src/Context/SessionContext.php:64
 /Users/khellemun/GitHub/bunq/sdk_php/src/Context/SessionContext.php:52
 /Users/khellemun/GitHub/bunq/sdk_php/src/Context/ApiContext.php:164
 /Users/khellemun/GitHub/bunq/sdk_php/src/Context/ApiContext.php:123
 /Users/khellemun/GitHub/bunq/sdk_php/src/Context/ApiContext.php:110
 /Users/khellemun/GitHub/bunq/sdk_php/tests/BunqSdkTestBase.php:64
 /Users/khellemun/GitHub/bunq/sdk_php/tests/Context/ApiContextTest.php:22
 

Extra info:

Add zappr integration for better quality control 

The purpose of this issue is to introduce https://zappr.opensource.zalan.do so that quality control on pull requests can be assured.

The following configuration should be used:

autobranch:
  pattern: 'bunq/sdk_php#{number}-{title}'
  length: 100
commit:
  message:
    patterns:
      - '([A-Za-z0-9 ]+)\. (\(bunq\/sdk_php#[0-9]+\))'
specification:
  title:
    minimum-length:
      enabled: true
      length: 8
  body:
    minimum-length:
      enabled: true
      length: 8
    contains-url: true
    contains-issue-number: true
  template:
    differs-from-body: true
pull-request:
  labels:
    additional: true
    required:
      - Reviewed by André
      - Can be merged

Callback models for holding callback data.

Steps to reproduce:

  1. Receive a callback as described here: https://doc.bunq.com/api/1/page/callbacks

What should happen:

  1. There is a model available so that you can do the following:
$callbackModel = NotificationUrl::fromJson($CallbackJson);
$callbackModel->getReferencedObject();

if (!$callbackModel isntanceof CallbackModelImExcpeting) {
    throw new Exception();
}

What happens:

  1. Such thing is not possible yet

Logs

  • Logs no logs

Extra info:

Make sure received signatures headers are correctly cased

Steps to reproduce:

  1. Receive a response from the API
  2. The response headers are lowercased.
  3. Try and verify the signature

What should happen:

  1. The signature is verified correctly

What happens:

  1. The signature verification will fail

Logs

  • Logs no logs

Extra info:

Incorrect composer.json / authors sections

A composer install results in:

[Composer\Json\JsonValidationException]                        
  "./composer.json" does not match the expected JSON schema:     
   - authors[0] : String value found, but an object is required

TokenQrRequestIdeal returns the wrong type

Steps to reproduce:

  1. Try to create a TokenQrRequestIdeal using the SDK.

What should happen:

  1. The item is created and a TokenQrRequestIdeal object is returned.

What happens:

  1. The API returns a RequestResponse object, but the SDK tries to cast it to a TokenQrRequestIdeal, resulting in an error.

Logs

Together topic: https://together.bunq.com/topic/does-tokenqrrequestidealcreate-code-wrong

Report from user @china1688:

Dear Bunqer,
i am testing TokenQrRequestIdeal class, when i call TokenQrRequestIdeal::create, there is always error as below:

PHP Notice: Undefined index: TokenQrRequestIdeal in D:\xampp\htdocs\bunq_test\vendor\bunq\sdk_php\src\Model\Core\BunqModel.php on line 127
Notice: Undefined index: TokenQrRequestIdeal in D:\xampp\htdocs\bunq_test\vendor\bunq\sdk_php\src\Model\Core\BunqModel.php on line 127

i check the function of TokenQrRequestIdeal::create, the coding is different from Payment::create, RequestInquiry::create, IdealMerchantTransaction::create,
then i guess the code of TokenQrRequestIdeal::create as below mark in bold is wrong coding?

/******************TokenQrRequestIdeal::create ************************************
public static function create(ApiContext $apiContext, array $requestMap, int $userId, array $customHeaders = []): BunqResponseTokenQrRequestIdeal
{ ....
return BunqResponseTokenQrRequestIdeal::castFromBunqResponse(
static::fromJson($responseRaw, self::OBJECT_TYPE)
);}
/******************Payment::create ************************************
public static function create(ApiContext $apiContext, array $requestMap, int $userId, int $monetaryAccountId, array $customHeaders = []): BunqResponseInt
{...
return BunqResponseInt::castFromBunqResponse(
static::processForId($responseRaw)
);}
/******************IdealMerchantTransactionList::create ************************************
public static function create(ApiContext $apiContext, array $requestMap, int $userId, int $monetaryAccountId, array $customHeaders = []): BunqResponseInt
{
return BunqResponseInt::castFromBunqResponse(
static::processForId($responseRaw)
);}
/******************RequestInquiry::create ************************************
public static function create(ApiContext $apiContext, array $requestMap, int $userId, int $monetaryAccountId, array $customHeaders = []): BunqResponseInt
{...
return BunqResponseInt::castFromBunqResponse(
static::processForId($responseRaw)
);}

Could anyone help check the code?

Extra info:

Fatal error in the interactive installer when no allowed IP is given

Steps to reproduce:

  1. Run vendor/bin/bunq-install
  2. Enter no value for the allowed IP, just hit return

What should happen:

  1. The configuration is generated

What happens:

  1. The script gives a fatal error

Logs

PHP Fatal error:  Uncaught TypeError: Argument 1 passed to bunq\Util\InstallationUtil::formatIps() must be of the type string, null given, called in /Users/mbernson/bunqtest/vendor/bunq/sdk_php/src/Util/InstallationUtil.php on line 88 and defined in /Users/mbernson/bunqtest/vendor/bunq/sdk_php/src/Util/InstallationUtil.php:193
Stack trace:
#0 /Users/mbernson/bunqtest/vendor/bunq/sdk_php/src/Util/InstallationUtil.php(88): bunq\Util\InstallationUtil::formatIps(NULL)
#1 /Users/mbernson/bunqtest/vendor/bunq/sdk_php/bin/bunq-install(16): bunq\Util\InstallationUtil::interactiveInstall()
#2 {main}
  thrown in /Users/mbernson/bunqtest/vendor/bunq/sdk_php/src/Util/InstallationUtil.php on line 193

Fatal error: Uncaught TypeError: Argument 1 passed to bunq\Util\InstallationUtil::formatIps() must be of the type string, null given, called in /Users/mbernson/bunqtest/vendor/bunq/sdk_php/src/Util/InstallationUtil.php on line 88 and defined in /Users/mbernson/bunqtest/vendor/bunq/sdk_php/src/Util/InstallationUtil.php on line 193

TypeError: Argument 1 passed to bunq\Util\InstallationUtil::formatIps() must be of the type string, null given, called in /Users/mbernson/bunqtest/vendor/bunq/sdk_php/src/Util/InstallationUtil.php on line 88 in /Users/mbernson/bunqtest/vendor/bunq/sdk_php/src/Util/InstallationUtil.php on line 193

Call Stack:
    0.0003     354664   1. {main}() /Users/mbernson/bunqtest/vendor/bunq/sdk_php/bin/bunq-install:0
    0.0044     677128   2. bunq\Util\InstallationUtil::interactiveInstall() /Users/mbernson/bunqtest/vendor/bunq/sdk_php/bin/bunq-install:16
    9.4677    1736472   3. bunq\Util\InstallationUtil::formatIps() /Users/mbernson/bunqtest/vendor/bunq/sdk_php/src/Util/InstallationUtil.php:88

Extra info:

  • Error occurred on PHP 7.0.26, fix tested on PHP 7.0.26

See PR #78

Curl error "Invalid certificate chain" when running `vendor/bin/bunq-install`

When running the initialisation, I am getting an exception.

Choose an environment (SANDBOX/PRODUCTION): PRODUCTION
Please provide your api key: API_KEY_HERE
An unexpected error occurred: cURL error 60: SSL certificate problem: Invalid certificate chain (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)

Am I missing something?

PHP version:

PHP 7.1.5 (cli) (built: May 13 2017 13:30:32) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

Curl version:

curl 7.54.0 (x86_64-apple-darwin16.0) libcurl/7.54.0 SecureTransport zlib/1.2.8
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz UnixSockets

Add missing fields for cvc endpoint

Steps to reproduce:

  1. Try and get id, created or updated from CardGeneratedCvc2

What should happen:

  1. These fields are there with getters/setters

What happens:

  1. There are no such fields

Logs

  • no logs

Extra info:

SessionContext is missing timeout for UserPerson

Steps to reproduce:

  1. Make a a call as user person to any endpoint

What happens:

  1. You will get Call to a member function getSessionTimeout() on null.

What should happen:

  1. You don't get the mentioned error.

Extra info:

Traceback

Call to a member function getSessionTimeout() on null
bunq/sdk_php/lib/Context/SessionContext.php:60
bunq/sdk_php/lib/Context/SessionContext.php:48
bunq/sdk_php/lib/Context/ApiContext.php:149
bunq/sdk_php/lib/Context/ApiContext.php:106
 bunq/sdk_php/lib/Context/ApiContext.php:93
 bunq/sdk_php/test/ApiContextHandler.php:36
 bunq/sdk_php/test/Model/Generated/MonetaryAccountBankTest.php:69

Scheduled payments are not decoded because of a typo

There is a typo in the bunq\Model\Generated\Endpoint\SchedulePayment class. It has the constant const OBJECT_TYPE = 'SchedulePayment'; while the API returns an object of type ScheduledPayment. When I change the constant to this, it works fine.

Steps to reproduce:

  1. Run this piece of code: https://gist.github.com/mbernson/dd8c966e277b4acd820463335cd47e24

What should happen:

  1. I see a var_dump of my scheduled payments.

What happens:

  1. PHP Notice: Undefined index: SchedulePayment in /Users/mathijs/Code/bunqapibouwsel/vendor/bunq/sdk_php/src/Model/Core/BunqModel.php on line 115

Extra info:

  • Tested on bunq/sdk_php version 0.12.2 and the production bunq API

Monetary account joint cannot be retrieved.

Steps to reproduce:

  1. Create a new joint account
  2. try something like MonetaryAccount.list

What should happen:

  1. Monetary account joints are also listed

What happens:

  1. you will get all accounts except the new joint accounts

Logs

  • Logs no logs

Extra info:

[DX] User::listing requires ugly logic to make it user-type agnostic

At the time of writing, to be able to ascertain the user ID requires making a specific call to the method of the type of the user you're expecting. If you would run the following piece of code:

$userId = User::listing($apiContext)[0]->getUserPerson()->getId();

You would run into an exception if the API HTTP response yields a business user (or vice versa when you use getUserCompany():

Fatal error: Uncaught Error: Call to a member function getId() on null in /Users/rukn01/Projects/rknol/sdk_php/example/monetary_account_example.php:20

So logically speaking if your integration is not aware of the kind of user that will come out of the API, the only way you can express this would be something like this pre-PHP 7.1:

$userWrapper = User::listing($apiContext)[0];
$userObj = !is_null($userWrapper->getUserPerson()) 
    ? $userWrapper->getUserPerson() 
    : $userWrapper->getUserCompany();

$userId = $userObj->getId();

Or PHP 7.1+ with the null-coalesce operator:

$userWrapper = User::listing($apiContext)[0];
$userId = ($userWrapper->getUserPerson() ?? $userWrapper->getUserCompany())->getId();

Either scenarios are unfavorable, and unnecessary if the design of the SDK is more developer friendly. I understand that the reasoning behind this is because resource-wise they're 3 different resources, however it makes for very ugly implementation.

One way to solve this would to abstract away the logic inside the User resource:

class User
{
    // ...
    public function getUserObject()
    {
        return !is_null($this->userPerson)
            ? $this->userPerson
            : $this->userCompany;
    }
}

Or something in the likes so that the DX will be:

$userId = User::listing($apiContext)[0]->getUserObject()->getId();

public.api.bunq.com is using wrong certificate

when trying to run vendor/bin/bunq-install i encountered the following error:

An unexpected error occurred: cURL error 51: SSL: no alternative certificate subject name 
matches target host name 'public.api.bunq.com' 
(see http://curl.haxx.se/libcurl/c/libcurl-errors.html)

so i checked the url public.api.bunq.com using my browser.
The server is returning the certificate for the sandbox environment:
screen shot 2017-08-03 at 17 44 45

Ps. when in need of a new certificate checkout https://letsencrypt.org/

[DX] Static resource access is bad for mockability

In the current implementation of the SDK static methods on classes are used to make requests.

For example:

// ...
$users = User::listing($apiContext)->getValue();

This is not good for developer experience as it makes it non-trivial to implement the SDK in a project with high unit test coverage.

Imagine for example that in my project I have a FinanceService that has a method to accumulate total spend on saturday + sunday. If I expressed the service like this:

<?php

namespace Bla;

use bunq\Context\ApiContext;
use bunq\Model\Generated\Payment;

class FinanceService
{
    private $apiContext;

    public function __construct(ApiContext $apiContext)
    {
        $this->apiContext = $apiContext;
    }

    public function getWeekendSpending($userId, $monetaryAccountId)
    {
        $amount = 0;
        $paymentList = Payment::listing($this->apiContext, $userId, $monetaryAccountId);

        foreach ($paymentList as $payment) {
            $date = new \DateTime($payment->getCreated());

            if (in_array($date->format('D'), ['Sat', 'Sun'])) {
                $amount += $payment->getAmount();
            }
        }

        return $amount;
    }
}

Writing the unit test would not allow me to mock the API HTTP request very easily as there is no simple way to ensure that Payment::listing does not make an actual HTTP request, or to influence what the return value would be.

There is a workaround I could do on my end, but it involves wrapping each individual resource that makes HTTP requests in a wrapper object like this:

class PaymentResource implements PaymentResourceInterface
{
    private $apiContext;
    
    public function __construct(ApiContext $apiContext)
    {
        $this->apiContext = $apiContext;
    }

    public function listing($userId, $monetaryAccountId)
    {
        return Payment::listing($this->apiContext, $userId, $monetaryAccountId);
    }
}

To be able to mock (the result of) API HTTP requests in a unit test designed to test only the logic of the service method, and not invoke an actual API HTTP request (or even obtain/instantiate an ApiContext/session with the API):

class FinanceServiceTest extends \PHPUnit\Framework\TestCase
{
    public function testGetWeekendSpending()
    {
        // Friday
        $payment0 = new Payment();
        $payment0->setAmount(new Amount('199', 'EUR'));
        $payment0->setCreated('2017-08-18 10:33:17.097996');

        // Sunday
        $payment1 = new Payment();
        $payment1->setAmount(new Amount('199', 'EUR'));
        $payment1->setCreated('2017-08-20 16:21:57.295726');

        $paymentResource = $this
            ->createMock(PaymentResource::class)
            ->method('listing')
            ->willReturn([
                $payment0,
                $payment1
            ]);


        $s = new FinanceService($paymentResource);
        $this->assertEquals(199, $s->getWeekendSpending(1, 2));
    }
}

This would mean that I would end up maintaining code that is domain specific to bunq but somehow physically located in the codebase of my own projects.

Ideally, the SDK is designed in a way that there is no need to invoke static methods to make API HTTP requests - this will make the DX much smoother in modern PHP projects.

Getting a DraftPayment that has been ACCEPTED results in an error

PHP: 7.1
SDK Version: 0.12.1
Error: bunq\Exception\BunqException: Found model "BunqModel" which is not defined. in /vendor/bunq/sdk_php/src/Util/ModelUtil.php:60

As soon as you try to get a DraftPayment that has the status 'ACCEPTED', this DraftPayment will have the 'object' attribute set.
In the Endpoint/DraftPayment.php file is stated:

    /**
     * The Payment or PaymentBatch. This will only be present after the
     * DraftPayment has been accepted.
     *
     * @var BunqModel
     */
    protected $object;

The current code in ModelUtil.php doesn't allow for this since BunqModel is not a subclass of itself.

    /**
     * @param string $className
     *
     * @return bool
     */
    private static function isClassSubClassOfBunqModel(string $className): bool
    {
        return class_exists($className) && is_subclass_of($className, BunqModel::class);
    }

Quickly searching the code I think the Schedule / ScheduleInstance has the same error?

Field ID is missing from MasterCardAction

Steps to reproduce:

  1. Take a look at src/Model/Generated/Endpoint/MasterCardAction.php

What should happen:

  1. There is a field ID

What happens:

  1. Such field does not exist

Logs

  • Logs no logs

Extra info:

Auto save the session after automatic session reset has been executed 

Steps to reproduce:

  1. Make a request with an expired session

What should happen:

  1. The session gets automatically reset before the actual call is made.
  2. The reset session should be saved after the reset. So that the next call has a fresh new session, instead of resetting the session again.
  3. The user should be able to turn the automatic session save off.

What happens:

  1. If implemented incorrectly, users will make 6 calls to session-server within 2 seconds because on each call the session needs to be reset.

Logs

  • Logs no logs

Extra info:

Pagination and limit is missing for listing methods

For all listing methods, there is no pagination.

This means

  • You can only retrieve the first 10 items;
  • This limit of 10 items is not customisable;
  • There is no way of getting the next batch of x items from the resource.

This could be resolved by a complete implementation of the pagination as documented here.

Draft Payments is missing

Though the SDK I can create regular payments, but there is no way to create a DraftPayment - it seems the model is missing.

Is this correct, or is there a (hidden) option on Payment to make it a draft instead of a regular one?

Ignore generated code for reviews

How to Reproduce

  1. Look at the ./gitattributes file.

What Should Happen

  1. The generated code is listed as generated code.

What Happens

  1. The generated code is not listed in there.

Notes

  • This will make code review easier as of the generated code will be collapsed automatically .

Suggestion: use Objects instead of arrays

I think using arrays for mapping is a bad practice. It makes more sense to create an object for this:

final class PaymentMap
{
    const FIELD_AMOUNT = 'amount';
    const FIELD_COUNTERPARTY_ALIAS = 'counterparty_alias';
    const FIELD_DESCRIPTION = 'description';
    const FIELD_ATTACHMENT = 'attachment';

    private $amount;

    private $pointer;

    private $description;

    private $attachments;

    public function __construct(Amount $amount, Pointer $pointer, $description)
    {
        //... the usual stuff ...//
    }

    public function addAttachment(Attachment $attachment): void
    {
        $this->attachments[$attachment->getId()] = $attachment;
    }

    public function getAmount(): Amount
    {
        return $this->amount;
    }

    public function getAsArray(): array
    {
        return [
            self::FIELD_AMOUNT => $this->amount,
            self::FIELD_COUNTERPARTY_ALIAS => $this->pointer,
            //... Well you get the idea ...// 
        ];
    }
}
$paymentMap = new PaymentMap(
    new Amount('10.00', 'EUR'),
    new Pointer('EMAIL', '[email protected]'),
    This is a generated payment',
];

Payment::create($bunqApiContext, $paymentMap, $userId, $monetaryAccountId);
public static function create(ApiContext $apiContext, PaymentMap $paymentMap, $userId, $monetaryAccountId, array $customHeaders = [])
    {
        $apiClient = new ApiClient($apiContext);
        $response = $apiClient->post(
            vsprintf(
                self::ENDPOINT_URL_CREATE,
                [$userId, $monetaryAccountId]
            ),
            $paymentMap->getAsArray(),
            $customHeaders
        );

        return static::processForId($response);
    }

Using this approach you restrict the programmer to fill in all the required fields, and prevent making invalid API calls.

It adds more structure to the project and gives the ability to run better tests :)

you can even unit test the whole thing now:

/**
 * @small
 */
final class PaymentMapTest extends PHPUnit_Framework_TestCase
{
    /** @test */
    public function canCreateValidPaymentMap()
    {
        $amount = new Amount(10.00, 'EUR');
        $pointer= new Pointer('EMAIL', '[email protected]');
        $description = 'payment description';
        $paymentMap = new PaymentMap($amount, $pointer, $description);

        self::assertSame($amount, $paymentMap->getAmount());
        self::assertSame($pointer, $paymentMap->getPointer());
        self::assertSame($description, $paymentMap->getDescription());
    }

    /** @test */
    public function canCreateValidPaymentMapParsesValidArray()
    {
        // duplicate code maybe extract it into a method?
        $amount = new Amount(10.00, 'EUR');
        $pointer= new Pointer('EMAIL', '[email protected]');
        $description = 'payment description';
        $paymentMap = new PaymentMap($amount, $pointer, $description);

        self::assertEquals(
            [
                PaymentMap::FIELD_AMOUNT => $amount,
                PaymentMap::FIELD_COUNTERPARTY_ALIAS => $pointer,
                //... Well you get the idea ...//
            ],
            $paymentMap->getAsArray()
        );
    }

    /** @test */
    public function canAddAttachments()
    {
        // duplicate code maybe extract it into a method?
        $amount = new Amount(10.00, 'EUR');
        $pointer= new Pointer('EMAIL', '[email protected]');
        $description = 'payment description';
        $paymentMap = new PaymentMap($amount, $pointer, $description);

        $attachment = new Attachment();
        $paymentMap->addAttachment($attachment);

        // ... Well you get the idea ...//
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.