Skip to content

Commit

Permalink
Merge pull request #771 from stripe/integration-services
Browse files Browse the repository at this point in the history
Introduces a new client/services API, where multiple Stripe clients can be initialized, and all methods can be invoked via that client.
  • Loading branch information
richardm-stripe authored May 14, 2020
2 parents dccb135 + 0b17d45 commit 962f1ca
Show file tree
Hide file tree
Showing 137 changed files with 11,290 additions and 25 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ If you use Composer, these dependencies should be handled automatically. If you
Simple usage looks like:

```php
\Stripe\Stripe::setApiKey('sk_test_BQokikJOvBiI2HlWgH4olfQ2');
$customer = \Stripe\Customer::create([
$stripe = new \Stripe\StripeClient('sk_test_BQokikJOvBiI2HlWgH4olfQ2');
$customer = $stripe->customers->create([
'description' => 'example customer',
'email' => '[email protected]',
'payment_method' => 'pm_card_visa',
Expand Down Expand Up @@ -125,7 +125,7 @@ end up there instead of `error_log`:
You can access the data from the last API response on any object via `getLastResponse()`.

```php
$customer = \Stripe\Customer::create([
$customer = $stripe->customers->create([
'description' => 'example customer',
]);
echo $customer->getLastResponse()->headers['Request-Id'];
Expand All @@ -149,12 +149,12 @@ one that uses [Stripe Connect][connect], it's also possible to set a
per-request key and/or account:

```php
$customers = \Stripe\Customer::all([],[
$customers = $stripe->customers->all([],[
'api_key' => 'sk_test_...',
'stripe_account' => 'acct_...'
]);

\Stripe\Customer::retrieve("cus_123456789", [
$stripe->customers->retrieve('cus_123456789', [], [
'api_key' => 'sk_test_...',
'stripe_account' => 'acct_...'
]);
Expand Down
76 changes: 76 additions & 0 deletions init.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@
require __DIR__ . '/lib/ApiRequestor.php';
require __DIR__ . '/lib/ApiResource.php';
require __DIR__ . '/lib/SingletonApiResource.php';
require __DIR__ . '/lib/Service/AbstractService.php';
require __DIR__ . '/lib/Service/AbstractServiceFactory.php';

// StripeClient
require __DIR__ . '/lib/StripeClientInterface.php';
require __DIR__ . '/lib/BaseStripeClient.php';
require __DIR__ . '/lib/StripeClient.php';

// Stripe API Resources
require __DIR__ . '/lib/Account.php';
Expand Down Expand Up @@ -146,6 +153,75 @@
require __DIR__ . '/lib/UsageRecordSummary.php';
require __DIR__ . '/lib/WebhookEndpoint.php';

// Services
require __DIR__ . '/lib/Service/AccountService.php';
require __DIR__ . '/lib/Service/AccountLinkService.php';
require __DIR__ . '/lib/Service/ApplePayDomainService.php';
require __DIR__ . '/lib/Service/ApplicationFeeService.php';
require __DIR__ . '/lib/Service/BalanceService.php';
require __DIR__ . '/lib/Service/BalanceTransactionService.php';
require __DIR__ . '/lib/Service/BillingPortal/SessionService.php';
require __DIR__ . '/lib/Service/ChargeService.php';
require __DIR__ . '/lib/Service/Checkout/SessionService.php';
require __DIR__ . '/lib/Service/CountrySpecService.php';
require __DIR__ . '/lib/Service/CouponService.php';
require __DIR__ . '/lib/Service/CreditNoteService.php';
require __DIR__ . '/lib/Service/CustomerService.php';
require __DIR__ . '/lib/Service/DisputeService.php';
require __DIR__ . '/lib/Service/EphemeralKeyService.php';
require __DIR__ . '/lib/Service/EventService.php';
require __DIR__ . '/lib/Service/ExchangeRateService.php';
require __DIR__ . '/lib/Service/FileService.php';
require __DIR__ . '/lib/Service/FileLinkService.php';
require __DIR__ . '/lib/Service/InvoiceService.php';
require __DIR__ . '/lib/Service/InvoiceItemService.php';
require __DIR__ . '/lib/Service/Issuing/AuthorizationService.php';
require __DIR__ . '/lib/Service/Issuing/CardService.php';
require __DIR__ . '/lib/Service/Issuing/CardholderService.php';
require __DIR__ . '/lib/Service/Issuing/DisputeService.php';
require __DIR__ . '/lib/Service/Issuing/TransactionService.php';
require __DIR__ . '/lib/Service/MandateService.php';
require __DIR__ . '/lib/Service/OrderService.php';
require __DIR__ . '/lib/Service/OrderReturnService.php';
require __DIR__ . '/lib/Service/PaymentIntentService.php';
require __DIR__ . '/lib/Service/PaymentMethodService.php';
require __DIR__ . '/lib/Service/PayoutService.php';
require __DIR__ . '/lib/Service/PlanService.php';
require __DIR__ . '/lib/Service/PriceService.php';
require __DIR__ . '/lib/Service/ProductService.php';
require __DIR__ . '/lib/Service/Radar/EarlyFraudWarningService.php';
require __DIR__ . '/lib/Service/Radar/ValueListService.php';
require __DIR__ . '/lib/Service/Radar/ValueListItemService.php';
require __DIR__ . '/lib/Service/RefundService.php';
require __DIR__ . '/lib/Service/Reporting/ReportRunService.php';
require __DIR__ . '/lib/Service/Reporting/ReportTypeService.php';
require __DIR__ . '/lib/Service/ReviewService.php';
require __DIR__ . '/lib/Service/SetupIntentService.php';
require __DIR__ . '/lib/Service/Sigma/ScheduledQueryRunService.php';
require __DIR__ . '/lib/Service/SkuService.php';
require __DIR__ . '/lib/Service/SourceService.php';
require __DIR__ . '/lib/Service/SubscriptionService.php';
require __DIR__ . '/lib/Service/SubscriptionItemService.php';
require __DIR__ . '/lib/Service/SubscriptionScheduleService.php';
require __DIR__ . '/lib/Service/TaxRateService.php';
require __DIR__ . '/lib/Service/Terminal/ConnectionTokenService.php';
require __DIR__ . '/lib/Service/Terminal/LocationService.php';
require __DIR__ . '/lib/Service/Terminal/ReaderService.php';
require __DIR__ . '/lib/Service/TokenService.php';
require __DIR__ . '/lib/Service/TopupService.php';
require __DIR__ . '/lib/Service/TransferService.php';
require __DIR__ . '/lib/Service/WebhookEndpointService.php';

// Service factories
require __DIR__ . '/lib/Service/CoreServiceFactory.php';
require __DIR__ . '/lib/Service/BillingPortal/BillingPortalServiceFactory.php';
require __DIR__ . '/lib/Service/Checkout/CheckoutServiceFactory.php';
require __DIR__ . '/lib/Service/Issuing/IssuingServiceFactory.php';
require __DIR__ . '/lib/Service/Radar/RadarServiceFactory.php';
require __DIR__ . '/lib/Service/Reporting/ReportingServiceFactory.php';
require __DIR__ . '/lib/Service/Sigma/SigmaServiceFactory.php';
require __DIR__ . '/lib/Service/Terminal/TerminalServiceFactory.php';

// OAuth
require __DIR__ . '/lib/OAuth.php';
require __DIR__ . '/lib/OAuthErrorObject.php';
Expand Down
243 changes: 243 additions & 0 deletions lib/BaseStripeClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
<?php

namespace Stripe;

class BaseStripeClient implements StripeClientInterface
{
/** @var string default base URL for Stripe's API */
const DEFAULT_API_BASE = 'https://api.stripe.com';

/** @var string default base URL for Stripe's OAuth API */
const DEFAULT_CONNECT_BASE = 'https://connect.stripe.com';

/** @var string default base URL for Stripe's Files API */
const DEFAULT_FILES_BASE = 'https://files.stripe.com';

/** @var array<string, mixed> */
private $config;

/** @var \Stripe\Util\RequestOptions */
private $defaultOpts;

/**
* Initializes a new instance of the {@link BaseStripeClient} class.
*
* The constructor takes a single argument. The argument can be a string, in which case it
* should be the API key. It can also be an array with various configuration settings.
*
* Configuration settings include the following options:
*
* - api_key (null|string): the Stripe API key, to be used in regular API requests.
* - client_id (null|string): the Stripe client ID, to be used in OAuth requests.
* - stripe_account (null|string): a Stripe account ID. If set, all requests sent by the client
* will automatically use the {@code Stripe-Account} header with that account ID.
* - stripe_version (null|string): a Stripe API verion. If set, all requests sent by the client
* will include the {@code Stripe-Version} header with that API version.
*
* The following configuration settings are also available, though setting these should rarely be necessary
* (only useful if you want to send requests to a mock server like stripe-mock):
*
* - api_base (string): the base URL for regular API requests. Defaults to
* {@link DEFAULT_API_BASE}.
* - connect_base (string): the base URL for OAuth requests. Defaults to
* {@link DEFAULT_CONNECT_BASE}.
* - files_base (string): the base URL for file creation requests. Defaults to
* {@link DEFAULT_FILES_BASE}.
*
* @param array<string, mixed>|string $config the API key as a string, or an array containing
* the client configuration settings
*/
public function __construct($config = [])
{
if (\is_string($config)) {
$config = ['api_key' => $config];
} elseif (!\is_array($config)) {
throw new \Stripe\Exception\InvalidArgumentException('$config must be a string or an array');
}

$config = \array_merge($this->getDefaultConfig(), $config);
$this->validateConfig($config);

$this->config = $config;

$this->defaultOpts = \Stripe\Util\RequestOptions::parse([
'stripe_account' => $config['stripe_account'],
'stripe_version' => $config['stripe_version'],
]);
}

/**
* Gets the API key used by the client to send requests.
*
* @return null|string the API key used by the client to send requests
*/
public function getApiKey()
{
return $this->config['api_key'];
}

/**
* Gets the client ID used by the client in OAuth requests.
*
* @return null|string the client ID used by the client in OAuth requests
*/
public function getClientId()
{
return $this->config['client_id'];
}

/**
* Gets the base URL for Stripe's API.
*
* @return string the base URL for Stripe's API
*/
public function getApiBase()
{
return $this->config['api_base'];
}

/**
* Gets the base URL for Stripe's OAuth API.
*
* @return string the base URL for Stripe's OAuth API
*/
public function getConnectBase()
{
return $this->config['connect_base'];
}

/**
* Gets the base URL for Stripe's Files API.
*
* @return string the base URL for Stripe's Files API
*/
public function getFilesBase()
{
return $this->config['files_base'];
}

/**
* Sends a request to Stripe's API.
*
* @param string $method the HTTP method
* @param string $path the path of the request
* @param array $params the parameters of the request
* @param array|\Stripe\Util\RequestOptions $opts the special modifiers of the request
*
* @return \Stripe\StripeObject the object returned by Stripe's API
*/
public function request($method, $path, $params, $opts)
{
$opts = $this->defaultOpts->merge($opts, true);
$baseUrl = $opts->apiBase ?: $this->getApiBase();
$requestor = new \Stripe\ApiRequestor($this->apiKeyForRequest($opts), $baseUrl);
list($response, $opts->apiKey) = $requestor->request($method, $path, $params, $opts->headers);
$opts->discardNonPersistentHeaders();
$obj = \Stripe\Util\Util::convertToStripeObject($response->json, $opts);
$obj->setLastResponse($response);

return $obj;
}

/**
* @param \Stripe\Util\RequestOptions $opts
*
* @throws \Stripe\Exception\AuthenticationException
*
* @return string
*/
private function apiKeyForRequest($opts)
{
$apiKey = $opts->apiKey ?: $this->getApiKey();

if (null === $apiKey) {
$msg = 'No API key provided. Set your API key when constructing the '
. 'StripeClient instance, or provide it on a per-request basis '
. 'using the `api_key` key in the $opts argument.';

throw new \Stripe\Exception\AuthenticationException($msg);
}

return $apiKey;
}

/**
* TODO: replace this with a private constant when we drop support for PHP < 5.
*
* @return array<string, mixed>
*/
private function getDefaultConfig()
{
return [
'api_key' => null,
'client_id' => null,
'stripe_account' => null,
'stripe_version' => null,
'api_base' => self::DEFAULT_API_BASE,
'connect_base' => self::DEFAULT_CONNECT_BASE,
'files_base' => self::DEFAULT_FILES_BASE,
];
}

/**
* @param array<string, mixed> $config
*
* @throws \Stripe\Exception\InvalidArgumentException
*/
private function validateConfig($config)
{
// api_key
if (null !== $config['api_key'] && !\is_string($config['api_key'])) {
throw new \Stripe\Exception\InvalidArgumentException('api_key must be null or a string');
}

if (null !== $config['api_key'] && ('' === $config['api_key'])) {
$msg = 'api_key cannot be the empty string';

throw new \Stripe\Exception\InvalidArgumentException($msg);
}

if (null !== $config['api_key'] && (\preg_match('/\s/', $config['api_key']))) {
$msg = 'api_key cannot contain whitespace';

throw new \Stripe\Exception\InvalidArgumentException($msg);
}

// client_id
if (null !== $config['client_id'] && !\is_string($config['client_id'])) {
throw new \Stripe\Exception\InvalidArgumentException('client_id must be null or a string');
}

// stripe_account
if (null !== $config['stripe_account'] && !\is_string($config['stripe_account'])) {
throw new \Stripe\Exception\InvalidArgumentException('stripe_account must be null or a string');
}

// stripe_version
if (null !== $config['stripe_version'] && !\is_string($config['stripe_version'])) {
throw new \Stripe\Exception\InvalidArgumentException('stripe_version must be null or a string');
}

// api_base
if (!\is_string($config['api_base'])) {
throw new \Stripe\Exception\InvalidArgumentException('api_base must be a string');
}

// connect_base
if (!\is_string($config['connect_base'])) {
throw new \Stripe\Exception\InvalidArgumentException('connect_base must be a string');
}

// files_base
if (!\is_string($config['files_base'])) {
throw new \Stripe\Exception\InvalidArgumentException('files_base must be a string');
}

// check absence of extra keys
$validConfigKeys = \array_keys($this->getDefaultConfig());
$extraConfigKeys = \array_diff(\array_keys($config), \array_keys($this->getDefaultConfig()));
if (!empty($extraConfigKeys)) {
throw new \Stripe\Exception\InvalidArgumentException('Found unknown key(s) in configuration array: ' . \implode(',', $extraConfigKeys));
}
}
}
1 change: 0 additions & 1 deletion lib/Issuing/Transaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
* @property string $merchant_currency The currency with which the merchant is taking payment.
* @property \Stripe\StripeObject $merchant_data
* @property \Stripe\StripeObject $metadata Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format.
* @property null|\Stripe\StripeObject $purchase_details Additional purchase information that is optionally provided by the merchant.
* @property string $type The nature of the transaction.
*/
class Transaction extends \Stripe\ApiResource
Expand Down
5 changes: 3 additions & 2 deletions lib/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
* Products describe the specific goods or services you offer to your customers.
* For example, you might offer a Standard and Premium version of your goods or
* service; each version would be a separate Product. They can be used in
* conjunction with <a href="https://stripe.com/docs/api#prices">Prices</a> to
* configure pricing in Checkout and Subscriptions.
* conjunction with <a href="https://stripe.com/docs/api#skus">SKUs</a> and <a
* href="https://stripe.com/docs/api#plans">Plans</a> to configure pricing in
* Checkout and Subscriptions.
*
* Related guides: <a
* href="https://stripe.com/docs/billing/subscriptions/set-up-subscription">Set up
Expand Down
Loading

0 comments on commit 962f1ca

Please sign in to comment.