-
Notifications
You must be signed in to change notification settings - Fork 843
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
Service factories #892
Service factories #892
Conversation
The changes do make sense to me but I don't have a well-formed opinion around the architecture of the client classes. Will defer to someone like @brandur-stripe instead. Can you show a bit more example on how you would make multiple calls, how you'd pass custom options like the API version or the |
8ca640d
to
b918855
Compare
7de6166
to
a54bb7a
Compare
b918855
to
bb26e09
Compare
a54bb7a
to
b90b600
Compare
This approach seems good to me. I'd love to see a doc with all of the benefits to moving from the class/static method approach to the instance of client approach. \Stripe\Stripe::setApiKey('sk_test_123');
\Stripe\Customer::create([
'description' => 'x',
]); to $client = new \Stripe\StripeClient("sk_test_123");
$client->customer->create([
'description' => 'x',
]); Do we intend on doing state management inside of the client? Some sort of caching? Do we plan on continuing to support this and the static method approach? |
The This is generally a better design than the existing methods on the model classes because:
While the above is true for basically all languages, for PHP specifically it's been requested for a long time (over 5 years now!) by some users: #124.
Yes, at least initially. We would update the documentation and mark the old model methods as deprecated though, and hopefully remove them entirely at some point in the future. (*): not 100% true yet, at the moment |
Thanks for the added context, @ob-stripe! Those points all make sense and I agree it makes it much easier to work with multiple clients and for testing. I don't have a strong opinion on the structure of the code. |
Hey @ob-stripe, sorry about the late review here! I'm strongly in favor of the service idea — IMO they're a huge win compared to setting globals everywhere because they expose a more powerful API (because it becomes possible to have multiple co-existing clients with separate configurations), and they're often a boon for purposes of testing/stubbing/etc.
Good idea. More inheritance is never good per se, but the reasoning here seems sound. It might be worth adding a comment to clarify that The one question I had is: if we're codegen'ing anyway, would it make sense to have explicit getters for all the various service types instead of magic Anyway, great job here! So good to see these huge fixes randomly fly in, haha. |
Thanks Brandur!
Very good question. The reason I went with this approach is largely stylistic: for PHP, I think exposing (magic) properties is preferable to exposing getters, e.g. this: $card = $stripe->issuing->cards->retrieve('ic_123'); is prettier than this: $card = $stripe->issuing()->cards()->retrieve('ic_123'); Admittedly this is very subjective! We could get rid of the magic and use regular attributes, but we'd also have to get rid of the lazy initialization. This might not be so bad: there are not that many services (55 at the moment) and the cost would be paid when the |
Ah I see! Okay that makes sense. I'll add a minor note that language-specific LSP implementations are probably the way that the developer world is moving right now, and optimistically, one day PHP will have a good one too. That said, there are way too many unknowns around that right now (e.g. |
bb26e09
to
9e1c9a0
Compare
b90b600
to
0fe0bb6
Compare
0fe0bb6
to
9753191
Compare
FWIW that sounds like the tradeoff I'd make, static analyzability (and readability) is probably worth the startup cost, unless we can show that's material |
This PR adds "service factories", i.e. classes that help initialize and expose instances of service classes. The intent is to alleviate the need for users to create the service instances themselves. Instead, they simply create an instance of the client, and the client then exposes properties for all services:
Here's how it works:
AbstractServiceFactory
is the base abstract class for service factory. Using the__get()
magic method, it exposes properties for services using a mapping of property names to service classes defined in concrete factories. The service instances are lazily initialized the first time the property is accessed.CoreServiceFactory
is a concrete child that exposes services for API resources in the root namespace, as well as service factories for namespaces. This class will be codegen'd.IssuingServiceFactory
is a concrete child that exposes services for API resources in the issuing namespace. This class (and other similar classes for namespaced resources) will be codegen'd.StripeClient
is renamed toBaseStripeClient
StripeClient
class is added that derives fromBaseStripeClient
and adds a__get()
magic method to expose services through aCoreServiceFactory
instanceBaseStripeClient
andStripeClient
is thatBaseStripeClient
contains manually written infrastructure code, andStripeClient
will need to be codegen'd in order to have the@property
PHPDoc tags that will make autocompletion work for services in PHPStorm and other IDEs.@brandur-stripe @rattrayalex-stripe @remi-stripe @richardm-stripe Thoughts on this approach?