Added selectable num of records on each listing page, fixed up Pagination Records UI, added new stripe library, further worked on stripe integration, fixed mispelling in client details

This commit is contained in:
johnny@pittpc.com
2021-02-10 11:21:38 -05:00
parent c748388b9a
commit 530d46a812
352 changed files with 16193 additions and 7090 deletions
@@ -0,0 +1,72 @@
<?php
namespace Stripe\Util;
/**
* CaseInsensitiveArray is an array-like class that ignores case for keys.
*
* It is used to store HTTP headers. Per RFC 2616, section 4.2:
* Each header field consists of a name followed by a colon (":") and the field value. Field names
* are case-insensitive.
*
* In the context of stripe-php, this is useful because the API will return headers with different
* case depending on whether HTTP/2 is used or not (with HTTP/2, headers are always in lowercase).
*/
class CaseInsensitiveArray implements \ArrayAccess, \Countable, \IteratorAggregate
{
private $container = [];
public function __construct($initial_array = [])
{
$this->container = \array_change_key_case($initial_array, \CASE_LOWER);
}
public function count()
{
return \count($this->container);
}
public function getIterator()
{
return new \ArrayIterator($this->container);
}
public function offsetSet($offset, $value)
{
$offset = static::maybeLowercase($offset);
if (null === $offset) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset)
{
$offset = static::maybeLowercase($offset);
return isset($this->container[$offset]);
}
public function offsetUnset($offset)
{
$offset = static::maybeLowercase($offset);
unset($this->container[$offset]);
}
public function offsetGet($offset)
{
$offset = static::maybeLowercase($offset);
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
private static function maybeLowercase($v)
{
if (\is_string($v)) {
return \strtolower($v);
}
return $v;
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace Stripe\Util;
/**
* A very basic implementation of LoggerInterface that has just enough
* functionality that it can be the default for this library.
*/
class DefaultLogger implements LoggerInterface
{
/** @var int */
public $messageType = 0;
/** @var null|string */
public $destination;
public function error($message, array $context = [])
{
if (\count($context) > 0) {
throw new \Stripe\Exception\BadMethodCallException('DefaultLogger does not currently implement context. Please implement if you need it.');
}
if (null === $this->destination) {
\error_log($message, $this->messageType);
} else {
\error_log($message, $this->messageType, $this->destination);
}
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
namespace Stripe\Util;
/**
* Describes a logger instance.
*
* This is a subset of the interface of the same name in the PSR-3 logger
* interface. We guarantee to keep it compatible, but we'd redefined it here so
* that we don't have to pull in the extra dependencies for users who don't want
* it.
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data, the only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named "exception".
*/
interface LoggerInterface
{
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
*/
public function error($message, array $context = []);
}
+99
View File
@@ -0,0 +1,99 @@
<?php
// File generated from our OpenAPI spec
namespace Stripe\Util;
class ObjectTypes
{
/**
* @var array Mapping from object types to resource classes
*/
const mapping = [
\Stripe\Account::OBJECT_NAME => \Stripe\Account::class,
\Stripe\AccountLink::OBJECT_NAME => \Stripe\AccountLink::class,
\Stripe\AlipayAccount::OBJECT_NAME => \Stripe\AlipayAccount::class,
\Stripe\ApplePayDomain::OBJECT_NAME => \Stripe\ApplePayDomain::class,
\Stripe\ApplicationFee::OBJECT_NAME => \Stripe\ApplicationFee::class,
\Stripe\ApplicationFeeRefund::OBJECT_NAME => \Stripe\ApplicationFeeRefund::class,
\Stripe\Balance::OBJECT_NAME => \Stripe\Balance::class,
\Stripe\BalanceTransaction::OBJECT_NAME => \Stripe\BalanceTransaction::class,
\Stripe\BankAccount::OBJECT_NAME => \Stripe\BankAccount::class,
\Stripe\BillingPortal\Session::OBJECT_NAME => \Stripe\BillingPortal\Session::class,
\Stripe\BitcoinReceiver::OBJECT_NAME => \Stripe\BitcoinReceiver::class,
\Stripe\BitcoinTransaction::OBJECT_NAME => \Stripe\BitcoinTransaction::class,
\Stripe\Capability::OBJECT_NAME => \Stripe\Capability::class,
\Stripe\Card::OBJECT_NAME => \Stripe\Card::class,
\Stripe\Charge::OBJECT_NAME => \Stripe\Charge::class,
\Stripe\Checkout\Session::OBJECT_NAME => \Stripe\Checkout\Session::class,
\Stripe\Collection::OBJECT_NAME => \Stripe\Collection::class,
\Stripe\CountrySpec::OBJECT_NAME => \Stripe\CountrySpec::class,
\Stripe\Coupon::OBJECT_NAME => \Stripe\Coupon::class,
\Stripe\CreditNote::OBJECT_NAME => \Stripe\CreditNote::class,
\Stripe\CreditNoteLineItem::OBJECT_NAME => \Stripe\CreditNoteLineItem::class,
\Stripe\Customer::OBJECT_NAME => \Stripe\Customer::class,
\Stripe\CustomerBalanceTransaction::OBJECT_NAME => \Stripe\CustomerBalanceTransaction::class,
\Stripe\Discount::OBJECT_NAME => \Stripe\Discount::class,
\Stripe\Dispute::OBJECT_NAME => \Stripe\Dispute::class,
\Stripe\EphemeralKey::OBJECT_NAME => \Stripe\EphemeralKey::class,
\Stripe\Event::OBJECT_NAME => \Stripe\Event::class,
\Stripe\ExchangeRate::OBJECT_NAME => \Stripe\ExchangeRate::class,
\Stripe\File::OBJECT_NAME => \Stripe\File::class,
\Stripe\File::OBJECT_NAME_ALT => \Stripe\File::class,
\Stripe\FileLink::OBJECT_NAME => \Stripe\FileLink::class,
\Stripe\Invoice::OBJECT_NAME => \Stripe\Invoice::class,
\Stripe\InvoiceItem::OBJECT_NAME => \Stripe\InvoiceItem::class,
\Stripe\InvoiceLineItem::OBJECT_NAME => \Stripe\InvoiceLineItem::class,
\Stripe\Issuing\Authorization::OBJECT_NAME => \Stripe\Issuing\Authorization::class,
\Stripe\Issuing\Card::OBJECT_NAME => \Stripe\Issuing\Card::class,
\Stripe\Issuing\CardDetails::OBJECT_NAME => \Stripe\Issuing\CardDetails::class,
\Stripe\Issuing\Cardholder::OBJECT_NAME => \Stripe\Issuing\Cardholder::class,
\Stripe\Issuing\Dispute::OBJECT_NAME => \Stripe\Issuing\Dispute::class,
\Stripe\Issuing\Transaction::OBJECT_NAME => \Stripe\Issuing\Transaction::class,
\Stripe\LineItem::OBJECT_NAME => \Stripe\LineItem::class,
\Stripe\LoginLink::OBJECT_NAME => \Stripe\LoginLink::class,
\Stripe\Mandate::OBJECT_NAME => \Stripe\Mandate::class,
\Stripe\Order::OBJECT_NAME => \Stripe\Order::class,
\Stripe\OrderItem::OBJECT_NAME => \Stripe\OrderItem::class,
\Stripe\OrderReturn::OBJECT_NAME => \Stripe\OrderReturn::class,
\Stripe\PaymentIntent::OBJECT_NAME => \Stripe\PaymentIntent::class,
\Stripe\PaymentMethod::OBJECT_NAME => \Stripe\PaymentMethod::class,
\Stripe\Payout::OBJECT_NAME => \Stripe\Payout::class,
\Stripe\Person::OBJECT_NAME => \Stripe\Person::class,
\Stripe\Plan::OBJECT_NAME => \Stripe\Plan::class,
\Stripe\Price::OBJECT_NAME => \Stripe\Price::class,
\Stripe\Product::OBJECT_NAME => \Stripe\Product::class,
\Stripe\PromotionCode::OBJECT_NAME => \Stripe\PromotionCode::class,
\Stripe\Radar\EarlyFraudWarning::OBJECT_NAME => \Stripe\Radar\EarlyFraudWarning::class,
\Stripe\Radar\ValueList::OBJECT_NAME => \Stripe\Radar\ValueList::class,
\Stripe\Radar\ValueListItem::OBJECT_NAME => \Stripe\Radar\ValueListItem::class,
\Stripe\Recipient::OBJECT_NAME => \Stripe\Recipient::class,
\Stripe\RecipientTransfer::OBJECT_NAME => \Stripe\RecipientTransfer::class,
\Stripe\Refund::OBJECT_NAME => \Stripe\Refund::class,
\Stripe\Reporting\ReportRun::OBJECT_NAME => \Stripe\Reporting\ReportRun::class,
\Stripe\Reporting\ReportType::OBJECT_NAME => \Stripe\Reporting\ReportType::class,
\Stripe\Review::OBJECT_NAME => \Stripe\Review::class,
\Stripe\SetupAttempt::OBJECT_NAME => \Stripe\SetupAttempt::class,
\Stripe\SetupIntent::OBJECT_NAME => \Stripe\SetupIntent::class,
\Stripe\Sigma\ScheduledQueryRun::OBJECT_NAME => \Stripe\Sigma\ScheduledQueryRun::class,
\Stripe\SKU::OBJECT_NAME => \Stripe\SKU::class,
\Stripe\Source::OBJECT_NAME => \Stripe\Source::class,
\Stripe\SourceTransaction::OBJECT_NAME => \Stripe\SourceTransaction::class,
\Stripe\Subscription::OBJECT_NAME => \Stripe\Subscription::class,
\Stripe\SubscriptionItem::OBJECT_NAME => \Stripe\SubscriptionItem::class,
\Stripe\SubscriptionSchedule::OBJECT_NAME => \Stripe\SubscriptionSchedule::class,
\Stripe\TaxId::OBJECT_NAME => \Stripe\TaxId::class,
\Stripe\TaxRate::OBJECT_NAME => \Stripe\TaxRate::class,
\Stripe\Terminal\ConnectionToken::OBJECT_NAME => \Stripe\Terminal\ConnectionToken::class,
\Stripe\Terminal\Location::OBJECT_NAME => \Stripe\Terminal\Location::class,
\Stripe\Terminal\Reader::OBJECT_NAME => \Stripe\Terminal\Reader::class,
\Stripe\ThreeDSecure::OBJECT_NAME => \Stripe\ThreeDSecure::class,
\Stripe\Token::OBJECT_NAME => \Stripe\Token::class,
\Stripe\Topup::OBJECT_NAME => \Stripe\Topup::class,
\Stripe\Transfer::OBJECT_NAME => \Stripe\Transfer::class,
\Stripe\TransferReversal::OBJECT_NAME => \Stripe\TransferReversal::class,
\Stripe\UsageRecord::OBJECT_NAME => \Stripe\UsageRecord::class,
\Stripe\UsageRecordSummary::OBJECT_NAME => \Stripe\UsageRecordSummary::class,
\Stripe\WebhookEndpoint::OBJECT_NAME => \Stripe\WebhookEndpoint::class,
];
}
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace Stripe\Util;
/**
* A basic random generator. This is in a separate class so we the generator
* can be injected as a dependency and replaced with a mock in tests.
*/
class RandomGenerator
{
/**
* Returns a random value between 0 and $max.
*
* @param float $max (optional)
*
* @return float
*/
public function randFloat($max = 1.0)
{
return \mt_rand() / \mt_getrandmax() * $max;
}
/**
* Returns a v4 UUID.
*
* @return string
*/
public function uuid()
{
$arr = \array_values(\unpack('N1a/n4b/N1c', \openssl_random_pseudo_bytes(16)));
$arr[2] = ($arr[2] & 0x0fff) | 0x4000;
$arr[3] = ($arr[3] & 0x3fff) | 0x8000;
return \vsprintf('%08x-%04x-%04x-%04x-%04x%08x', $arr);
}
}
+168
View File
@@ -0,0 +1,168 @@
<?php
namespace Stripe\Util;
class RequestOptions
{
/**
* @var array<string> a list of headers that should be persisted across requests
*/
public static $HEADERS_TO_PERSIST = [
'Stripe-Account',
'Stripe-Version',
];
/** @var array<string, string> */
public $headers;
/** @var null|string */
public $apiKey;
/** @var null|string */
public $apiBase;
/**
* @param null|string $key
* @param array<string, string> $headers
* @param null|string $base
*/
public function __construct($key = null, $headers = [], $base = null)
{
$this->apiKey = $key;
$this->headers = $headers;
$this->apiBase = $base;
}
/**
* @return array<string, string>
*/
public function __debugInfo()
{
return [
'apiKey' => $this->redactedApiKey(),
'headers' => $this->headers,
'apiBase' => $this->apiBase,
];
}
/**
* Unpacks an options array and merges it into the existing RequestOptions
* object.
*
* @param null|array|RequestOptions|string $options a key => value array
* @param bool $strict when true, forbid string form and arbitrary keys in array form
*
* @return RequestOptions
*/
public function merge($options, $strict = false)
{
$other_options = self::parse($options, $strict);
if (null === $other_options->apiKey) {
$other_options->apiKey = $this->apiKey;
}
if (null === $other_options->apiBase) {
$other_options->apiBase = $this->apiBase;
}
$other_options->headers = \array_merge($this->headers, $other_options->headers);
return $other_options;
}
/**
* Discards all headers that we don't want to persist across requests.
*/
public function discardNonPersistentHeaders()
{
foreach ($this->headers as $k => $v) {
if (!\in_array($k, self::$HEADERS_TO_PERSIST, true)) {
unset($this->headers[$k]);
}
}
}
/**
* Unpacks an options array into an RequestOptions object.
*
* @param null|array|RequestOptions|string $options a key => value array
* @param bool $strict when true, forbid string form and arbitrary keys in array form
*
* @throws \Stripe\Exception\InvalidArgumentException
*
* @return RequestOptions
*/
public static function parse($options, $strict = false)
{
if ($options instanceof self) {
return $options;
}
if (null === $options) {
return new RequestOptions(null, [], null);
}
if (\is_string($options)) {
if ($strict) {
$message = 'Do not pass a string for request options. If you want to set the '
. 'API key, pass an array like ["api_key" => <apiKey>] instead.';
throw new \Stripe\Exception\InvalidArgumentException($message);
}
return new RequestOptions($options, [], null);
}
if (\is_array($options)) {
$headers = [];
$key = null;
$base = null;
if (\array_key_exists('api_key', $options)) {
$key = $options['api_key'];
unset($options['api_key']);
}
if (\array_key_exists('idempotency_key', $options)) {
$headers['Idempotency-Key'] = $options['idempotency_key'];
unset($options['idempotency_key']);
}
if (\array_key_exists('stripe_account', $options)) {
$headers['Stripe-Account'] = $options['stripe_account'];
unset($options['stripe_account']);
}
if (\array_key_exists('stripe_version', $options)) {
$headers['Stripe-Version'] = $options['stripe_version'];
unset($options['stripe_version']);
}
if (\array_key_exists('api_base', $options)) {
$base = $options['api_base'];
unset($options['api_base']);
}
if ($strict && !empty($options)) {
$message = 'Got unexpected keys in options array: ' . \implode(', ', \array_keys($options));
throw new \Stripe\Exception\InvalidArgumentException($message);
}
return new RequestOptions($key, $headers, $base);
}
$message = 'The second argument to Stripe API method calls is an '
. 'optional per-request apiKey, which must be a string, or '
. 'per-request options, which must be an array. (HINT: you can set '
. 'a global apiKey by "Stripe::setApiKey(<apiKey>)")';
throw new \Stripe\Exception\InvalidArgumentException($message);
}
private function redactedApiKey()
{
$pieces = \explode('_', $this->apiKey, 3);
$last = \array_pop($pieces);
$redactedLast = \strlen($last) > 4
? (\str_repeat('*', \strlen($last) - 4) . \substr($last, -4))
: $last;
$pieces[] = $redactedLast;
return \implode('_', $pieces);
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace Stripe\Util;
use ArrayIterator;
use IteratorAggregate;
class Set implements IteratorAggregate
{
private $_elts;
public function __construct($members = [])
{
$this->_elts = [];
foreach ($members as $item) {
$this->_elts[$item] = true;
}
}
public function includes($elt)
{
return isset($this->_elts[$elt]);
}
public function add($elt)
{
$this->_elts[$elt] = true;
}
public function discard($elt)
{
unset($this->_elts[$elt]);
}
public function toArray()
{
return \array_keys($this->_elts);
}
public function getIterator()
{
return new ArrayIterator($this->toArray());
}
}
+265
View File
@@ -0,0 +1,265 @@
<?php
namespace Stripe\Util;
use Stripe\StripeObject;
abstract class Util
{
private static $isMbstringAvailable = null;
private static $isHashEqualsAvailable = null;
/**
* Whether the provided array (or other) is a list rather than a dictionary.
* A list is defined as an array for which all the keys are consecutive
* integers starting at 0. Empty arrays are considered to be lists.
*
* @param array|mixed $array
*
* @return bool true if the given object is a list
*/
public static function isList($array)
{
if (!\is_array($array)) {
return false;
}
if ([] === $array) {
return true;
}
if (\array_keys($array) !== \range(0, \count($array) - 1)) {
return false;
}
return true;
}
/**
* Converts a response from the Stripe API to the corresponding PHP object.
*
* @param array $resp the response from the Stripe API
* @param array $opts
*
* @return array|StripeObject
*/
public static function convertToStripeObject($resp, $opts)
{
$types = \Stripe\Util\ObjectTypes::mapping;
if (self::isList($resp)) {
$mapped = [];
foreach ($resp as $i) {
$mapped[] = self::convertToStripeObject($i, $opts);
}
return $mapped;
}
if (\is_array($resp)) {
if (isset($resp['object']) && \is_string($resp['object']) && isset($types[$resp['object']])) {
$class = $types[$resp['object']];
} else {
$class = \Stripe\StripeObject::class;
}
return $class::constructFrom($resp, $opts);
}
return $resp;
}
/**
* @param mixed|string $value a string to UTF8-encode
*
* @return mixed|string the UTF8-encoded string, or the object passed in if
* it wasn't a string
*/
public static function utf8($value)
{
if (null === self::$isMbstringAvailable) {
self::$isMbstringAvailable = \function_exists('mb_detect_encoding');
if (!self::$isMbstringAvailable) {
\trigger_error('It looks like the mbstring extension is not enabled. ' .
'UTF-8 strings will not properly be encoded. Ask your system ' .
'administrator to enable the mbstring extension, or write to ' .
'support@stripe.com if you have any questions.', \E_USER_WARNING);
}
}
if (\is_string($value) && self::$isMbstringAvailable && 'UTF-8' !== \mb_detect_encoding($value, 'UTF-8', true)) {
return \utf8_encode($value);
}
return $value;
}
/**
* Compares two strings for equality. The time taken is independent of the
* number of characters that match.
*
* @param string $a one of the strings to compare
* @param string $b the other string to compare
*
* @return bool true if the strings are equal, false otherwise
*/
public static function secureCompare($a, $b)
{
if (null === self::$isHashEqualsAvailable) {
self::$isHashEqualsAvailable = \function_exists('hash_equals');
}
if (self::$isHashEqualsAvailable) {
return \hash_equals($a, $b);
}
if (\strlen($a) !== \strlen($b)) {
return false;
}
$result = 0;
for ($i = 0; $i < \strlen($a); ++$i) {
$result |= \ord($a[$i]) ^ \ord($b[$i]);
}
return 0 === $result;
}
/**
* Recursively goes through an array of parameters. If a parameter is an instance of
* ApiResource, then it is replaced by the resource's ID.
* Also clears out null values.
*
* @param mixed $h
*
* @return mixed
*/
public static function objectsToIds($h)
{
if ($h instanceof \Stripe\ApiResource) {
return $h->id;
}
if (static::isList($h)) {
$results = [];
foreach ($h as $v) {
$results[] = static::objectsToIds($v);
}
return $results;
}
if (\is_array($h)) {
$results = [];
foreach ($h as $k => $v) {
if (null === $v) {
continue;
}
$results[$k] = static::objectsToIds($v);
}
return $results;
}
return $h;
}
/**
* @param array $params
*
* @return string
*/
public static function encodeParameters($params)
{
$flattenedParams = self::flattenParams($params);
$pieces = [];
foreach ($flattenedParams as $param) {
list($k, $v) = $param;
$pieces[] = self::urlEncode($k) . '=' . self::urlEncode($v);
}
return \implode('&', $pieces);
}
/**
* @param array $params
* @param null|string $parentKey
*
* @return array
*/
public static function flattenParams($params, $parentKey = null)
{
$result = [];
foreach ($params as $key => $value) {
$calculatedKey = $parentKey ? "{$parentKey}[{$key}]" : $key;
if (self::isList($value)) {
$result = \array_merge($result, self::flattenParamsList($value, $calculatedKey));
} elseif (\is_array($value)) {
$result = \array_merge($result, self::flattenParams($value, $calculatedKey));
} else {
\array_push($result, [$calculatedKey, $value]);
}
}
return $result;
}
/**
* @param array $value
* @param string $calculatedKey
*
* @return array
*/
public static function flattenParamsList($value, $calculatedKey)
{
$result = [];
foreach ($value as $i => $elem) {
if (self::isList($elem)) {
$result = \array_merge($result, self::flattenParamsList($elem, $calculatedKey));
} elseif (\is_array($elem)) {
$result = \array_merge($result, self::flattenParams($elem, "{$calculatedKey}[{$i}]"));
} else {
\array_push($result, ["{$calculatedKey}[{$i}]", $elem]);
}
}
return $result;
}
/**
* @param string $key a string to URL-encode
*
* @return string the URL-encoded string
*/
public static function urlEncode($key)
{
$s = \urlencode((string) $key);
// Don't use strict form encoding by changing the square bracket control
// characters back to their literals. This is fine by the server, and
// makes these parameter strings easier to read.
$s = \str_replace('%5B', '[', $s);
return \str_replace('%5D', ']', $s);
}
public static function normalizeId($id)
{
if (\is_array($id)) {
$params = $id;
$id = $params['id'];
unset($params['id']);
} else {
$params = [];
}
return [$id, $params];
}
/**
* Returns UNIX timestamp in milliseconds.
*
* @return int current time in millis
*/
public static function currentTimeMillis()
{
return (int) \round(\microtime(true) * 1000);
}
}