-
Notifications
You must be signed in to change notification settings - Fork 850
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
[WIP] Ensure that card
is only treated as a nested updatable attribute on Source objects
#396
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I understand the approach, I don't think this is the best direction. We're keeping a whitelist (which is bad in itself) but making it easier to mess up/mix.
I understand why this works but I also think the root cause is not worth this fix. No one can save a card object from a token. This is not a supported operation. It might work because the card id in the Token is the same as the one on the Charge though I don't think we guarantee this anywhere.
'metadata', | ||
'owner', | ||
'payout_schedule', | ||
'personal_address', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This lives under legal_entity
on the Account
object and legal_entity
is not a real class/object in the SDK (nor the API). This means you can't define a custom getNestedUpdatableAttributes
and make it work for some of those params. Would the plan be to "leave" it on StripeObject
directly? If so, won't most people pushing PR just default to putting it here anyway? Seems hard to realize there are edge-cases when you do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The attributes defined here don't have to be top-level attributes in a given object, they can themselves be nested under other attributes (else the current code would not work either). So my intent was to move all of the identity verification attributes under Account
, but as said above we can also keep the attributes in StripeObject
by default and only override the global whitelist when needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be bullish in moving these under something like Account
now that class-specific rules are supported. It's always seemed pretty janky to me that things like 0, 1, 2, 3, 4
and additional_owners
sit at the top level.
static $nestedUpdatableAttributes = null; | ||
if ($nestedUpdatableAttributes === null) { | ||
$nestedUpdatableAttributes = StripeObject::getNestedUpdatableAttributes(); | ||
$nestedUpdatableAttributes->add('card'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I worry that this will make it even harder to not miss edge-case. We already "break" the API often by forgetting to add those new API params to the whitelist. Now we need to add those but to potentially multiple objects now instead of just one canonical (though hidden) place in the library
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What this PR does is give the option to override the global whitelist in each class. If we're afraid that splitting up the whitelist will make it harder to maintain, we can simply keep the PR in its current form, i.e. keep the global whitelist on StripeObject
and keep the one special case of card
under Source
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand but it feels wrong/confusing.
3cd874b
to
9c981a0
Compare
I'm not familiar with this binding and my php is pretty rusty, is there someone better who could review this? |
@brandur-stripe Can you take a look at this and share your thoughts? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work tackling this one OB!
This is probably a feeling that every one of us is getting, but it seems that these "updatable attribute" semantics in PHP are turning out to be a pretty abhorrent abstraction.
That said, I can't think of a better way to fix this without a major overhaul and this PR will end up making things slightly better if it gives us the ability to offload some attributes from StripeObject
to Account
, so +1!
static $permanentAttributes = null; | ||
if ($permanentAttributes === null) { | ||
$permanentAttributes = new Util\Set(array('_opts', 'id')); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh man. I was going to say that it would be nice to just move this up to a statically initialized expression so we don't have to check the null
everytime, but just reading through the manual it seems like this only became supported in 5.6 for any non-trivial (i.e. not an integer or string assignment) expression :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. I amended the commit so you can't see it, but my first submission used static initializations 😭
'metadata', | ||
'owner', | ||
'payout_schedule', | ||
'personal_address', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be bullish in moving these under something like Account
now that class-specific rules are supported. It's always seemed pretty janky to me that things like 0, 1, 2, 3, 4
and additional_owners
sit at the top level.
* @return Util\Set Attributes that are nested but still updatable from | ||
* the parent class's URL (e.g. metadata). | ||
*/ | ||
public static function getNestedUpdatableAttributes() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add a comment somewhere in here that gives a breakdown similar to the one in this PR's description? I feel like this is a pretty difficult-to-understand complexity of the PHP library and I worry that the reasons we have card
in here will be forgotten pretty quickly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
9c981a0
to
3461f16
Compare
So I swore I posted an update on this issue, but it apparently got lost during last week's madness. My approach does not work as well as I had hoped. What I said here is incorrect:
This only works for top-level attributes. E.g. for We could merge the PR as-is in order to fix the |
Closing this one in favor of #404. |
r? @deontologician-stripe (dev-platform run, feel free to reassign)
cc @stripe/api-libraries @arcanedev-maroc
This fixes the issue described by @arcanedev-maroc here.
Basically, in #393 I added
card
to the list of nested updatable attributes so that users can update the expiry date on card sources:This worked, but had the side-effect of turning all nested
card
hashes into\Stripe\AttachedObject
. That's fine for sources since thecard
hash is just a hash, but not for token objects since thecard
hash nested in token objects is an actual card object, and so the instance should be a\Stripe\Card
(even though I have trouble imagining a practical case where that would be an issue -- there's no reason I can think of to manipulate a card object via token rather than via a customer/recipient/account).This PR changes the way the
$nestedUpdatableAttributes
works so that each class can define its own nested updatable attributes.StripeObject
now uses late static bindings so that derived classes can override thegetNestedUpdatableAttributes()
static function (which replaces the$nestedUpdatableAttributes
static variable) to define its own list of nested updatable attributes.