Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add capability api #99

Closed
wants to merge 23 commits into from
Closed

Add capability api #99

wants to merge 23 commits into from

Conversation

jonrandy
Copy link
Contributor

@jonrandy jonrandy commented Dec 3, 2018

Adds initial functionality for using the Capability API. Quite basic right now, probably needs to be expanded upon

Example usage:

<?php

require_once 'lib/Omise.php';

define('OMISE_PUBLIC_KEY', 'pkey_xxxxxxxxxxxxx');
define('OMISE_SECRET_KEY', 'skey_xxxxxxxxxxxxx');



$capabilities = OmiseCapabilities::retrieve();

print_r($capabilities);


$instalmentBackends = $capabilities->getBackends(
	$capabilities->makeBackendFilterType('installment'),
	$capabilities->makeBackendFilterCurrency('THB'),
	$capabilities->makeBackendFilterChargeAmount(749999)
);


foreach ($instalmentBackends as $backend) {
	print_r($backend);
}

@jonrandy
Copy link
Contributor Author

jonrandy commented Dec 3, 2018

Just occurred to me that although this is mergeable, it may not work, as master moved on quite a lot with your changes @guzzilar ? Can you confirm? If so, I'll bring the changes from master in and get it working again

@guzzilar
Copy link
Contributor

guzzilar commented Dec 4, 2018

@jonrandy you can try merge or rebase the code and test it on your local machine as well.
Also, can you provide some example code in the pull request's description? Like, how to execute, test, and also for the output result.

@guzzilar
Copy link
Contributor

guzzilar commented Dec 4, 2018

@jonrandy ah sorry, I think I misunderstood. Anyway, checked the code. So far it should be ok.
The changes in v2.10.0 won't effect to any current implementation. All code should still look & execute in the same way.

*
* @return array
*/
public function getBackends() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not convinced about naming convetion... get Backends..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't blame me - it's what they're called in the Capability API response (and probably elsewhere) - I'm just following the naming convention

$res,
function($v, $k) use (&$res) {
$id = array_keys($v)[0];
$res[$k][$id]['_id'] = $id;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy Is there any reason to have _id here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To differentiate it from the 'real' bits of the API - I added it for convenience

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy ic, not sure but does it necessary or is going to be used at any place in the future-pr(s)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already in use - proved extremely useful in Magento extension

@@ -0,0 +1,139 @@
<?php

class OmiseCapabilities extends OmiseApiResource
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy For the naming, OmiseCapability would be more consistency with the rest classes' name.

Copy link
Contributor Author

@jonrandy jonrandy Dec 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this when I made it. The object returned has details of all the capabilities of the system, not a single capability. I think this (the pluralised name) makes more sense in the current naming scheme. Calling it by the singular would be confusing and inconsistent IMO

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are many different capabilities listed..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Precisely

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy @jacstn Isn't it based on the API response body?
In this case, API returns

{
  "object": "capability",
  "location": "/capability",
  "banks": [],
  "payment_backends": []
}

The Capability is a single object, but many different items that are listed are payment_backends and others.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I discussed with Shunichi back in mid-December, he agrees with the naming and is going to rename the object in the API, as well as the endpoint

*
* @return function
*/
public function backendSupportsChargeAmount($amount) {
Copy link
Contributor

@guzzilar guzzilar Dec 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy I have a feeling that this will cause a confusion in case if someone using this filter with card backend-type (or other types).

$capability->getBackends(
    $capability->backendTypeIs('card'),
    $capability->backendSupportsChargeAmount(3000)
);

What do you think about this case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, sorry seems I misunderstood.. let me test a bit more..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every backend has a min/max charge amount. So the filter makes sense for all

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also 3000 to const ?

*
* @return function
*/
public function backendSupportsChargeAmount($amount) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also while backendTypeIs, backendSupportsChargeAmount, backendSupportsCurrency sound tempting but it's hard to differentiate between its filter methods and normal method.
How about we prefix it with filter?

$capability->getBackends(
    $capability->filterBackendType('card'),
    $capability->filterBackendSupportsChargeAmount(3000)
);

--
Actually not sure which one would be ideal, it could look like 👇 as well.

$capability->getBackends([
    'filters' => [
        'type'                 => 'card',
        'supportsChargeAmount' => 3000
    ]
]);

🤔 hmm, what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing it with the functions easily allows people to add their own filters if required without touching the omise-php code or requesting a change (they simply pass in their own filter function). I have no strong opinions on the name change for the filter building methods

Copy link
Contributor Author

@jonrandy jonrandy Dec 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makeFilter might be a better prefix since those functions don't actually filter anything, rather they build a function that will do the filtering. Or even makeBackendFilterXxxxx where Xxxxxx is the filter type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed a change with the above naming change

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add 3000 to const @jonrandy ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3000 does not appear in the code - the above is an example

Copy link
Contributor Author

@jonrandy jonrandy Dec 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guzzilar Actually, what about this?

$capabilities->getBackends(
    $capabilities->backendFilter['type']('card'),
    $capabilities->backendFilter['currency']('THB')
    $capabilities->backendFilter['amount'](3000)
);

I think it reads a bit nicer and still allows the user to pass in their own filter functions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what PHP version supports this construction though... checking

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works on 5.4 and above :)

@guzzilar
Copy link
Contributor

guzzilar commented Dec 4, 2018

@jonrandy The implementation looks neat! Just need your help to provide some test cases for this implementation. :)

Thanks!

Copy link
Contributor

@guzzilar guzzilar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy @jacstn Hi, I finished review.
There are some part that need to apply code styling (those brackets { }, space between string, naming convention - no _ prefix for private method).

You can try merge or rebase master branch.
I've added PHP Code Sniffer already. After merge, can run ./vendor/bin/phpcs to see the result.

@@ -0,0 +1,139 @@
<?php

class OmiseCapabilities extends OmiseApiResource
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy @jacstn Isn't it based on the API response body?
In this case, API returns

{
  "object": "capability",
  "location": "/capability",
  "banks": [],
  "payment_backends": []
}

The Capability is a single object, but many different items that are listed are payment_backends and others.

{
const ENDPOINT = 'capability';

const FILTERS = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy please use array() instead. (for PHP v5.3...) (let's announce of dropping support on this later :D )

Copy link
Contributor Author

@jonrandy jonrandy Jan 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since some of my other code already needs 5.4 (as mentioned above), which I assumed was ok was we are already recommending 5.6 on the readme and hence almost certainly dropping lower PHP versions soon

Copy link
Contributor

@guzzilar guzzilar Jan 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I didn't see that. Then probably we need to reconsider to go with a PHP v5.3-friendly approach instead.

We can say that we drop support on v5.3 and give users some times to migrate but not to break the current code please (by breaking, I mean, user that using Omise-PHP's current version on PHP v5.3 and want to upgrade to this version).

*
* @return boolean
*/
protected function isValidAPIResponse($array)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy Capability API is now returned "object": "capability" already, we don't need this alternative way anymore right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was certainly necessary before, but maybe things have changed. I will test again

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, no longer needed - removing

@@ -0,0 +1,36 @@
<?php require_once dirname(__FILE__).'/TestConfig.php';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacstn @jonrandy can you add more test to cover those below cases?

$capabilities->backendFilter['currency']('THB')
$capabilities->makeBackendFilterCurrency('THB')
$capabilities->getBackends()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm satisfied they work

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but still need test cases 😄

*
* @return function
*/
private static function _fixArgs($argArray) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy can we have a better name for this one? fixArgs sounds a bit ambiguous..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_sanitiseArgs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have gone with _argsToVariadic

$this->assertArrayHasKey('payment_backends', $capabilities);
$this->assertInternalType('array', $capabilities['payment_backends']);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is also this comment but somehow it doesn't show on Slack..
Let me repost here:

@jonrandy @jacstn Hi, I finished review.
There are some part that need to apply code styling (those brackets { }, space between string, naming convention - no _ prefix for private method).

You can try merge or rebase master branch.
I've added PHP Code Sniffer already. After merge, can run ./vendor/bin/phpcs to see the result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strongly disagree on no underscore prefixes for private and protected methods. It makes the code way easier to read

Copy link
Contributor

@guzzilar guzzilar Jan 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't find it as an obstacle, guess it depends on individual style for this one.
So I'll just follow PSR-2 and the current code style for now.

@guzzilar guzzilar force-pushed the add-capability-api branch from b0ea3c0 to 4775d36 Compare January 7, 2019 05:05
$res[$k][$id]['_id'] = $id;
}
);
$res = array_map(function($a) { return (object)reset($a); }, $res);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy I'm combining these array_walk and array_map to

$backends = array_map(
    function($backend) {
        $id = array_keys($backend)[0];
        $backend[$id]['_id'] = $id;
        return (object)reset($backend);
    }, 
    $backends);

return !empty($filter) ? array_values(array_filter($backends, $filter)) : $backends;

Do you have any concern from the above code? (I tested, the result seems to be the same)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as it gives the same result. I don't see that the array_values call is needed though - who cares about the indexes? Wasteful additional processing

@guzzilar guzzilar force-pushed the add-capability-api branch from 86ba196 to 9f4cf0e Compare January 7, 2019 09:10
function ($backend) {
$id = array_keys($backend)[0];
$backend[$id]['_id'] = $id;
return (object)reset($backend);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonrandy is there any reason you want to cast it to Object?

Just I found it's a bit off that the following code won't give the same result (it suppose to).

$capabbilities = OmiseCapabilities::retrieve();
print_r($capabbilities['payment_backends']);

and

$capabbilities = OmiseCapabilities::retrieve();
print_r($capabbilities->getBackends());

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it off? the getBackends returns backend objects created from the arrays in the JSON. Objects are nice to deal with in the code

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just slight of feeling that it should be the same value & structure (especially that _id attribute can be found only when call getBackends())

For casting to Object < ok

@jonrandy
Copy link
Contributor Author

jonrandy commented Jan 7, 2019

As you are editing now @guzzilar , I guess I need to be added as a reviewer. Struggling to work out how to do that though

@jonrandy jonrandy self-assigned this Jan 7, 2019
@guzzilar
Copy link
Contributor

guzzilar commented Jan 7, 2019

@jonrandy Don't think it's possible for adding yourself as a reviewer in your own PR..

@jonrandy
Copy link
Contributor Author

jonrandy commented Jan 7, 2019

Hmmmm.... do we need a new PR then? Or how is the review process going to work? Seems like we possibly should have merged this before you started adding to it?

@guzzilar
Copy link
Contributor

guzzilar commented Jan 7, 2019

@jonrandy if you don't mind, can comment in the code (just you technically cannot approved or rejected. I can click approved on behalf of you lol).

Or I can reopen PR if you prefer.
Let me know :)

@jonrandy
Copy link
Contributor Author

jonrandy commented Jan 7, 2019

I guess a new PR is better

@guzzilar
Copy link
Contributor

guzzilar commented Jan 7, 2019

@jonrandy Ok, I'm closing this PR then

@guzzilar guzzilar closed this Jan 7, 2019
@jacstn
Copy link
Contributor

jacstn commented Jan 7, 2019

we can verbally agree on changes.. you can alway do comments.. not sure if new pr is necessary than... :) @guzzilar @jonrandy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants