diff --git a/README.md b/README.md index 6fda84e..c0e2f8a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ php-figo [![Build Status](https://secure.travis-ci.org/figo-connect/php-figo.png)](https://travis-ci.org/figo-connect/php-figo) [![Packagist Version](http://img.shields.io/packagist/v/figo/figo.svg)](https://packagist.org/packages/figo/figo) ======== -PHP bindings for the figo Connect API: http://docs.figo.io +PHP bindings for the figo Connect API: http://docs.figo.io/v3/ Usage ===== diff --git a/composer.json b/composer.json index 8d972da..3ea56ad 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "figo/figo", "description": "API wrapper for figo Connect.", "homepage": "https://github.com/figo-connect/php-figo", - "version": "1.3.0", + "version": "3.0.0", "license": "MIT", "autoload": { "psr-0": { diff --git a/figo/Config.php b/figo/Config.php index 9f2f076..33b6f81 100644 --- a/figo/Config.php +++ b/figo/Config.php @@ -29,8 +29,8 @@ */ class Config { - /** @var string figo Connect server hostname */ - public static $API_ENDPOINT = "api.figo.me"; + /** @var string figo Connect server address. This should be the full base url of the API */ + public static $API_ENDPOINT = "https://api.figo.me/v3"; /** @var string figo Connect SSL/TLS certificate fingerprints */ public static $VALID_FINGERPRINTS = array("07:0F:14:AE:B9:4A:FB:3D:F8:00:E8:2B:69:A8:51:5C:EE:D2:F5:B1:BA:89:7B:EF:64:32:45:8F:61:CF:9E:33", @@ -42,7 +42,7 @@ class Config { /** * @var string Version of this SDK, used in user agent for API requests */ - public static $SDK_VERSION = '1.3.0'; + public static $SDK_VERSION = '2.0.0'; } ?> diff --git a/figo/Connection.php b/figo/Connection.php index 23c3f5c..49e04f3 100644 --- a/figo/Connection.php +++ b/figo/Connection.php @@ -23,6 +23,8 @@ namespace figo; +require_once("utils.php"); + use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; @@ -68,6 +70,7 @@ public function __construct($client_id, $client_secret, $redirect_uri = null, $a if ($apiEndpoint) { $this->apiEndpoint = $apiEndpoint; } + $this->apiUrl = parse_api_endpoint($this->apiEndpoint); if ($fingerprints) { $this->fingerprints = $fingerprints; @@ -107,7 +110,8 @@ public function query_api($path, array $data = null, $method='POST', $encode='ht "Content-Type" => $content_type, "Content-Length" => strlen($data)); - $request = new HttpsRequest($this->apiEndpoint, $this->fingerprints, $this->logger); + $request = new HttpsRequest($this->apiUrl['host'], $this->fingerprints, $this->logger); + $path = $this->apiUrl['path'] . $path; return $request->request($path, $data, $method, $headers, $language); } @@ -134,7 +138,7 @@ public function login_url($state, $scope = null) { if (!is_null($scope)) { $data["scope"] = $scope; } - return "https://".Config::$API_ENDPOINT."/auth/code?".http_build_query($data); + return $this->apiEndpoint."/auth/code?".http_build_query($data); } @@ -288,16 +292,7 @@ public function create_user($name, $email, $password, $language='de') { */ public function credential_login($username, $password, $device_name = null, $device_type = null, $device_udid = null, $scope = null) { - $options = [ "grant_type" => "password", "username" => $username, "password" => $password ]; - if ($device_name) - $options["device_name"] = $device_name; - if ($device_type) - $options["device_type"] = $device_type; - if ($device_udid) - $options["device_udid"] = $device_udid; - if ($scope) - $options["scope"] = $scope; - return $this->query_api("/auth/token", $options, "POST", "json_encode"); + return $this->native_client_login($username, $password, $scope); } diff --git a/figo/HttpsRequest.php b/figo/HttpsRequest.php index 7318a04..6a85078 100644 --- a/figo/HttpsRequest.php +++ b/figo/HttpsRequest.php @@ -86,7 +86,7 @@ public function request($path, $data, $method, array $headers, $language = 'de') } // Setup common HTTP headers. - $headers["Host"] = Config::$API_ENDPOINT; + $headers["Host"] = parse_url(Config::$API_ENDPOINT)['host']; $headers["Accept"] = "application/json"; $headers["User-Agent"] = Config::$USER_AGENT . '/' . Config::$SDK_VERSION; $headers["Connection"] = "close"; @@ -148,7 +148,7 @@ public function request($path, $data, $method, array $headers, $language = 'de') if ($code >= 400 && $code < 500) { $this->logFailedRequest($path, $responseArray, $loggingData); - throw new Exception($responseArray["error"]["name"] .": ". $responseArray["error"]["message"]." (Status: ".$responseArray["status"].")" , $responseArray["error"]["description"]); + throw new Exception("Code: ".$responseArray["error"]["code"], $responseArray["error"]["description"]); } if ($code === 503) { diff --git a/figo/Session.php b/figo/Session.php index 78f6ca4..ee828b5 100644 --- a/figo/Session.php +++ b/figo/Session.php @@ -23,6 +23,8 @@ namespace figo; +require_once("utils.php"); + use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; @@ -62,6 +64,7 @@ public function __construct($access_token, $apiEndpoint = null, array $fingerpri if ($apiEndpoint) { $this->apiEndpoint = $apiEndpoint; } + $this->apiUrl = parse_api_endpoint($this->apiEndpoint); if ($fingerprints) { $this->fingerprints = $fingerprints; @@ -93,8 +96,8 @@ public function query_api($path, array $data = null, $method = "GET") { "Content-Type" => "application/json", "Content-Length" => strlen($data)); - $request = new HttpsRequest($this->apiEndpoint, $this->fingerprints, $this->logger); - + $request = new HttpsRequest($this->apiUrl['host'], $this->fingerprints, $this->logger); + $path = $this->apiUrl['path'] . $path; return $request->request($path, $data, $method, $headers); } @@ -248,17 +251,6 @@ public function add_account($country, $credentials, $bank_code, $iban, $save_pin return (is_null($response) ? null : new Account($this, $response)); } - /** - * Modify an account - * - * @param Account the modified account to be saved - * @return Account 'Account' object for the updated account returned by server - */ - public function modify_account($account) { - $response = $this->query_api("/rest/accounts/".$account->account_id, $account->dump(), "PUT"); - return (is_null($response) ? null : new Account($this, $response)); - } - /** * Remove an account * @@ -465,7 +457,7 @@ public function remove_bank_pin($bank_or_id) { public function get_sync_url($redirect_uri, $state) { $data = array("redirect_uri" => $redirect_uri, "state" => $state); $response = $this->query_api("/rest/sync", $data, "POST"); - return "https://".Config::$API_ENDPOINT."/task/start?id=".$response["task_token"]; + return $this->apiEndpoint."/task/start?id=".$response["task_token"]; } @@ -717,7 +709,7 @@ public function submit_payment($payment, $tan_scheme_id, $state, $redirect_uri=n if (is_null($response)) { return null; } else { - return "https://".Config::$API_ENDPOINT."/task/start?id=".$response["task_token"]; + return $this->apiEndpoint."/task/start?id=".$response["task_token"]; } } } diff --git a/figo/utils.php b/figo/utils.php new file mode 100644 index 0000000..a8a97fa --- /dev/null +++ b/figo/utils.php @@ -0,0 +1,13 @@ +create_user($name, self::$email, self::$password); + $response = self::$connection->native_client_login(self::$email, self::$password); + $access_token = $response["access_token"]; + self::$session = new Session($access_token, $api_endpoint, $fingerprints); + } + + public static function tearDownAfterClass() { + self::$session->remove_user(); + } + + public function test_credential_login() { + + $accounts = $this::$session->get_accounts(); + $this->assertEquals([], $accounts); + } - protected function setUp() { - $this->sut = new Session("ASHWLIkouP2O6_bgA2wWReRhletgWKHYjLqDaqb0LFfamim9RjexTo22ujRIP_cjLiRiSyQXyt2kM1eXU2XLFZQ0Hro15HikJQT_eNeT_9XQ"); + public function test_setup_account() { + $response = $this::$session->setup_bank_account("90090042", array("figo", "figo"), array()); + for($i = 0; $i <= 20; $i++) { + $task_state = $this::$session->get_task_state($response['task_token']); + if($task_state['is_ended'] == true) { + break; + } + $this->assertFalse($task_state['is_erroneous']); + sleep(1); + } } - public function test_accounts() { - $accounts = $this->sut->get_accounts(); - $this->assertGreaterThan(0, count($accounts)); + public function test_get_accounts() { + $accounts = $this::$session->get_accounts(); + $this->assertEquals(3, count($accounts)); + $this->account_id = $accounts[0]->account_id; + $single_account = $this::$session->get_account($this->account_id); + $this->assertEquals($this->account_id, $single_account->account_id); + $this->assertNotNull($single_account->balance->balance); + $this->assertNotNull($single_account->balance->balance_date); + } - $account = $this->sut->get_account("A1.1"); - $this->assertEquals($account->account_id, "A1.1"); + public function test_list_transactions() + { + $accounts = $this::$session->get_accounts(); + $this->account_id = $accounts[0]->account_id; + $transactions = $this::$session->get_transactions(); + $this->assertGreaterThan(0, $transactions); + $transactions = $this::$session->get_transactions($this->account_id); + $this->assertGreaterThan(0, $transactions); + } - $account = $this->sut->get_account("A1.2"); - $this->assertEquals($account->account_id, "A1.2"); - $this->assertNotNull($account->balance->balance); - $this->assertNotNull($account->balance->balance_date); + public function test_list_all_standing_orders() { + $standing_orders = $this::$session->get_standing_orders(); + $this->assertEquals(0, count($standing_orders)); + } - $transactions = $account->get_transactions(); - $this->assertGreaterThan(0, count($transactions)); + public function test_list_securities() { + $options = array(); + $securities = $this::$session->get_securities($options); + $this->assertGreaterThan(0, $securities); + $this->account_id = $securities[0]->account_id; + $options["account_id"] = $this->account_id; + $securities = $this::$session->get_securities($options); + $this->assertGreaterThan(0, $securities); + } - $payments = $account->get_payments(); - $this->assertGreaterThanOrEqual(0, count($payments)); + public function test_list_all_payments() { + $payments = $this::$session->get_payments(); + $this->assertEquals(0, count($payments)); } - public function test_global_transactions() { - $transactions = $this->sut->get_transactions(); - $this->assertGreaterThan(0, count($transactions)); + public function test_list_account_payments() { + $accounts = $this::$session->get_accounts(); + $this->account_id = $accounts[0]->account_id; + $payments = $this::$session->get_payments($this->account_id); + $this->assertEquals(0, count($payments)); } - public function test_global_notifications() { - $notifications = $this->sut->get_notifications(); - $this->assertGreaterThanOrEqual(0, count($notifications)); + public function test_list_all_notification_subscriptions() { + $notifications = $this::$session->get_notifications(); + $this->assertEquals(0, count($notifications)); } - public function test_global_payments() { - $payments = $this->sut->get_payments(); - $this->assertGreaterThanOrEqual(0, count($payments)); + public function test_list_user_information() { + $user = $this::$session->get_user(); + $this->assertEquals($this::$email, $user->email); } public function test_missing_handling() { - $this->assertNull($this->sut->get_account("A1.42")); + $this->assertNull($this::$session->get_account("WRONG")); } public function test_error_handling() { $this->setExpectedException('Exception'); - $this->sut->get_sync_url("http://localhost:3003/", ""); + $this::$session->get_sync_url("random", ""); } public function test_sync_url() { - $sync_url = $this->sut->get_sync_url("qwe", "qew"); + $sync_url = $this::$session->get_sync_url("http://example.com/callback.php", "qew"); $this->assertGreaterThan(0, strlen($sync_url)); } - public function test_user() { - $this->assertEquals($this->sut->get_user()->email, "demo@figo.me"); - } - public function test_create_update_delete_notification() { - $notification = $this->sut->add_notification(new Notification($this->sut, array("observe_key" => "/rest/transactions", "notify_uri" => "http://figo.me/test", "state" => "qwe"))); + $notification = $this::$session->add_notification(new Notification($this::$session, array("observe_key" => "/rest/transactions", "notify_uri" => "http://figo.me/test", "state" => "qwe"))); $this->assertEquals($notification->observe_key, "/rest/transactions"); $this->assertEquals($notification->notify_uri, "http://figo.me/test"); $this->assertEquals($notification->state, "qwe"); $notification->state = "asd"; - $this->sut->modify_notification($notification); + $this::$session->modify_notification($notification); - $notification = $this->sut->get_notification($notification->notification_id); + $notification = $this::$session->get_notification($notification->notification_id); $this->assertEquals($notification->observe_key, "/rest/transactions"); $this->assertEquals($notification->notify_uri, "http://figo.me/test"); $this->assertEquals($notification->state, "asd"); - $this->sut->remove_notification($notification); - $notification = $this->sut->get_notification($notification->notification_id); + $this::$session->remove_notification($notification); + $notification = $this::$session->get_notification($notification->notification_id); $this->assertNull($notification); } public function test_create_update_delete_payment() { - $added_payment = $this->sut->add_payment(new Payment($this->sut, array("account_id" => "A1.1", "type" => "Transfer", "account_number" => "4711951501", "bank_code" => "90090042", "name" => "figo", "purpose" => "Thanks for all the fish.", "amount" => 0.89))); - $this->assertEquals($added_payment->account_id, "A1.1"); + $accounts = $this::$session->get_accounts(); + $this->account_id = $accounts[0]->account_id; + $added_payment = $this::$session->add_payment(new Payment($this::$session, array("account_id" => $this->account_id, "type" => "Transfer", "account_number" => "4711951501", "bank_code" => "90090042", "name" => "figo", "purpose" => "Thanks for all the fish.", "amount" => 0.89))); + $this->assertEquals($added_payment->account_id, $this->account_id); $this->assertEquals($added_payment->bank_name, "Demobank"); $this->assertEquals($added_payment->amount, 0.89); $added_payment->amount = 2.39; - $modified_payment = $this->sut->modify_payment($added_payment); + $modified_payment = $this::$session->modify_payment($added_payment); $this->assertEquals($modified_payment->payment_id, $added_payment->payment_id); - $this->assertEquals($modified_payment->account_id, "A1.1"); + $this->assertEquals($modified_payment->account_id, $this->account_id); $this->assertEquals($modified_payment->bank_name, "Demobank"); $this->assertEquals($modified_payment->amount, 2.39); - $this->sut->remove_payment($modified_payment); - $retrieved_payment = $this->sut->get_payment($modified_payment->account_id, $modified_payment->payment_id); + $this::$session->remove_payment($modified_payment); + $retrieved_payment = $this::$session->get_payment($modified_payment->account_id, $modified_payment->payment_id); $this->assertNull($retrieved_payment); } - public function test_security() { - $security = $this->sut->get_security('A1.4', 'S1.1'); - $this->assertInstanceOf('figo\Security', $security); - $this->assertEquals(1, count($security)); - - $this->assertEquals('S1.1', $security->security_id); - - $options = array( - 'count' => 2, - ); - - $security = $this->sut->get_securities($options); - $this->assertInternalType('array', $security); - $this->assertInstanceOf('figo\Security', $security[0]); - $this->assertEquals(2, count($security)); - - $options = array( - 'count' => 1, - 'account_id' =>'A1.4' - ); - - $security = $this->sut->get_securities($options); - $this->assertInternalType('array', $security); - $this->assertInstanceOf('figo\Security', $security[0]); - - $this->assertEquals('A1.4', $security[0]->account_id); - } - - public function test_standing_order() { - $standing_order = $this->sut->get_standing_order('SO1.1'); - $this->assertInstanceOf('figo\StandingOrder', $standing_order); - $this->assertEquals(1, count($standing_order)); - $this->assertEquals(100, $standing_order->amount); - $this->assertEquals('SO1.1', $standing_order->standing_order_id); - - $standing_order = null; - $standing_order = $this->sut->get_standing_orders(true); - - $this->assertInternalType('array', $standing_order); - $this->assertInstanceOf('figo\StandingOrder', $standing_order[0]); - $this->assertEquals(100.00, $standing_order[0]->amount); - } - - public function test_setup_bank_account() { - $response = $this->sut->setup_bank_account( - "90090042", ["demo", "demo"], - ["country" => "de", "save_pin" => true] - ); - $this->assertTrue(isset($response["task_token"])); - } - -} - - -class ConnectionTest extends PHPUnit_Framework_TestCase { - - /** @var Connection */ - protected $sut; - - protected function setUp() { - $this->sut = new Connection( - getenv('FIGO_CLIENT_ID'), - getenv('FIGO_CLIENT_SECRET'), - "http://my-domain.org/redirect-url", - getenv('FIGO_API_ENDPOINT'), - explode(',', getenv('FIGO_SSL_FINGERPRINT')) - ); - } - - public function test_native_login() { - $response = $this->sut->native_client_login("demo@figo.me", "demo1234"); - $access_token = $response["access_token"]; - $session = new Session($access_token); - try { - $this->assertEquals([], $session->get_accounts()); - } finally { - $session->remove_user(); - } - - } - - public function test_credentials_login() - { - $response = $this->sut->credential_login('php.sdk.testing@figo.io', 'phpsdk'); - $this->assertNotEmpty($response); - $this->assertNotNull($response['access_token']); - } - - public function test_catalog_language_is_german_by_default() - { - $result = $this->sut->get_supported_payment_services(); - - $this->assertEquals('de', $result['banks'][0]['language']['current_language']); - } - - public function test_catalog_language_can_be_set_to_english() - { - $result = $this->sut->get_supported_payment_services(null, null, 'en'); - - $this->assertEquals('en', $result['banks'][0]['language']['current_language']); + public function test_get_catalog_in_english() { + $response = $this::$connection->get_supported_payment_services(null, null, "en"); + $this->assertEquals("en", $response["banks"][0]["language"]["current_language"]); } - public function test_catalog_throws_exception_on_unsupported_language() + public function test_get_catalog_unsupported_language() { $this->setExpectedException( - \figo\Exception::class, 'Not Acceptable: Unsupported language (Status: 406), ' + \figo\Exception::class, 'Code: 1000, Unsupported language' ); + $this::$connection->get_supported_payment_services(null, null, 'fr'); + } - $this->sut->get_supported_payment_services(null, null, 'fr'); + public function test_get_bank() + { + $accounts = $this::$session->get_accounts(); + $bank_id = $accounts[0]->bank_id; + $bank = $this::$session->get_bank($bank_id); + $this->assertNotNull($bank); } } ?>