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

[WIP] Guzzle 5 #14

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 3.0.0

* ZfrStripe now uses Guzzle v5 (instead of v3). Usage of ZfrStripe does not change, except that Guzzle 5 is
substantially faster. This change has introduced a few breaking changes (those are documented in UPGRADING document)

# 2.8.1

* Add the new `tax_percent` property to subscriptions.
Expand Down
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ ZfrStripe is a modern PHP library based on Guzzle for [Stripe payment system](ht
## Dependencies

* PHP 5.4+
* [Guzzle](http://www.guzzlephp.org): >= 3.6
* [Guzzle](http://www.guzzlephp.org): >= 5.0

## Installation

Installation of ZfrStripe is only officially supported using Composer:

```sh
php composer.phar require zfr/zfr-stripe:2.*
php composer.phar require zfr/zfr-stripe:3.*
```

## Tutorial
Expand All @@ -30,11 +30,11 @@ $client = new StripeClient('my-api-key');
> You can change the API key for the client using the `setApiKey` method. This is useful if you are using Stripe
Connect and make both your own API calls and API calls on behalf of your users.

The currently latest supported version of the API is **2014-12-22**. You can (and should) also explicitly specify the version
The currently latest supported version of the API is **2015-04-07**. You can (and should) also explicitly specify the version
of the client using the second parameter:

```php
$client = new StripeClient('my-api-key', '2014-12-22');
$client = new StripeClient('my-api-key', '2015-04-07');
```

### Versioning
Expand All @@ -49,7 +49,8 @@ However, each new minor version (2.1.0 to 2.2.0 for instance) will update the St

Currently, the following Stripe API versions are accepted by ZfrStripe: `2014-03-28`, `2014-05-19`, `2014-06-13`,
`2014-06-17`, `2014-07-22`, `2014-07-26`, `2014-08-04`, `2014-08-20`, `2014-09-08`, `2014-10-07`, `2014-11-05`,
`2014-11-20`, `2014-12-08`, `2014-12-17`, `2014-12-22`. I will try to update the library as soon as new version are released.
`2014-11-20`, `2014-12-08`, `2014-12-17`, `2014-12-22`, `2015-01-11`, `2015-01-26`, `2015-02-10`, `2015-02-18`,
`2015-03-24`, `2015-04-07`. I will try to update the library as soon as new version are released.

> If you need support for older versions, please use branch v1 of ZfrStripe.

Expand Down Expand Up @@ -130,18 +131,17 @@ foreach ($iterator as $user) {
}
```

By default, ZfrStripe retrieves 100 elements per API call (which is the maximum allowed by Stripe API). You may want
to lower this limit by using the `setPageSize` method. You can also set a upper bound of how many results you want
to retrieve by using the `setLimit` method.
By default, ZfrStripe will implicitly add the limit parameter to 100 (the maximum page size allowed by Stripe API). You
may want to lower this limit by explicitly passing the `limit` parameter. You can limit the maximum number of elements
you want to retrive (in total) by calling the `setMaxResults` method on the iterator.

Finally, you can still use API parameters when using an iterator. For instance, this will retrieve all the events
With iterators, you can still use any API parameters. For instance, this will retrieve all the events
that have the event `customer.subscription.updated`, doing a new API call each 50 elements (this means that only
up to 50 elements are stored in memory), setting a limit of maximum 500 elements to retrieve:

```php
$iterator = $client->getEventsIterator(array('type' => 'customer.subscription.updated'));
$iterator->setPageSize(50);
$iterator->setLimit(500);
$iterator->MaxResults(500);

foreach ($iterator as $event) {
// Do something
Expand All @@ -159,7 +159,7 @@ foreach ($iterator as $invoices) {
```

ZfrStripe takes care of fetching the last item in the batch, extracting the id, and continuing doing requests
until no more data is available!
until no more data is available (or more results than "maxResults" have been fetched)!

#### Undocumented features

Expand Down
40 changes: 40 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# From 2.x to 3.x

ZfrStripe 3 upgraded Guzzle from v3 to v5. In this version, iterators have been removed and must be now implemented
in user-land. ZfrStripe therefore implements a lightweight iterator that replaces previous Guzzle iterator. As a
consequence, a few things have changed.

The `setPageSize` method has been removed, in favour of explicitly using the standard `limit` parameter from Stripe.
This makes the client more coherent.

Before:

```php
$iterator = $stripeClient->getCustomersIterator();
$iterator->setPageSize(50);
```

After:

```php
$iterator = $stripeClient->getCustomersIterator(['limit' => 50]);
```

The `setLimit` (that was used to limit the **total** number of results) was confusing because it had the same name
as Stripe `limit` parameter. This method has been removed in favour of a new `setMaxResults` method. For instance,
to create an iterator that fetch a maximum number of 200 elements, with a limit of 50 elements per API call.

Before:

```php
$iterator = $stripeClient->getCustomersIterator();
$iterator->setPageSize(50);
$iterator->setLimit(200);
```

After:

```php
$iterator = $stripeClient->getCustomersIterator(['limit' => 50]);
$iterator->setMaxResults(200);
```
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
],
"require": {
"php": ">=5.4",
"guzzle/guzzle": ">=3.6,<=3.9"
"guzzlehttp/guzzle-services": "0.5.*"
},
"require-dev": {
"phpunit/phpunit": "~3.7"
"phpunit/phpunit": "~4.1"
},
"autoload": {
"psr-4": {
Expand Down
161 changes: 145 additions & 16 deletions src/Client/Iterator/StripeCommandsCursorIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@

namespace ZfrStripe\Client\Iterator;

use Guzzle\Service\Command\CommandInterface;
use Guzzle\Service\Resource\ResourceIterator;
use GuzzleHttp\Command\CommandInterface;
use GuzzleHttp\Command\ServiceClientInterface;
use Iterator;

/**
* Basic iterator that is used to iterate over all Stripe commands
Expand All @@ -29,37 +30,165 @@
* @author Michaël Gallego <mic.gallego@gmail.com>
* @licence MIT
*/
class StripeCommandsCursorIterator extends ResourceIterator
class StripeCommandsCursorIterator implements Iterator
{
/**
* @param CommandInterface $command
* @param array $data
* @var ServiceClientInterface
*/
public function __construct(CommandInterface $command, array $data = [])
private $client;

/**
* @var CommandInterface
*/
private $command;

/**
* @var int
*/
private $requestCount = 0;

/**
* @var string|null
*/
private $nextToken;

/**
* @var array
*/
private $result = [];

/**
* @var int|null
*/
private $maxResults = null;

/**
* @var int
*/
private $iterationCount = 0;

/**
* @param ServiceClientInterface $client
* @param CommandInterface $command
*/
public function __construct(ServiceClientInterface $client, CommandInterface $command)
{
$this->client = $client;
$this->command = $command;

// If there is no explicit limit set, we use the maximum allowed by Stripe (100)
if (!isset($command['limit'])) {
$command['limit'] = 100;
}
}

/**
* @param int $maxResults
*/
public function setMaxResults($maxResults)
{
$this->maxResults = (int) $maxResults;
}

/**
* @return int
*/
public function getMaxResults()
{
return $this->maxResults;
}

/**
* @return array
*/
public function toArray()
{
parent::__construct($command, $data);
return iterator_to_array($this, false);
}

/**
* @return array
*/
public function getNext()
{
$this->result = [];
$countLoaded = $this->requestCount * $this->command['limit'];

if ((!$this->requestCount || $this->nextToken)
&& ($this->maxResults === null || $countLoaded < $this->maxResults)
) {
$this->loadNextResult();
}

return $this->result;
}

/**
* {@inheritDoc}
*/
public function current()
{
return current($this->result);
}

/**
* {@inheritDoc}
*/
public function next()
{
next($this->result);
$this->iterationCount++;
}

$this->pageSize = 100; // This is the maximum allowed by Stripe
/**
* {@inheritDoc}
*/
public function key()
{
return key($this->result);
}

/**
* {@inheritDoc}
*/
protected function sendRequest()
public function valid()
{
$this->command['limit'] = $this->pageSize;
if (null !== key($this->result)) {
return null !== $this->maxResults ? ($this->iterationCount < $this->maxResults) : true;
}

return !empty($this->getNext());
}

/**
* {@inheritDoc}
*/
public function rewind()
{
$this->requestCount = 0;
$this->iterationCount = 0;
$this->result = [];
$this->nextToken = null;
}

/**
* @return void
*/
private function loadNextResult()
{
if ($this->nextToken) {
$this->command['starting_after'] = $this->nextToken;
} else {
unset($this->command['starting_after']);
}

$result = $this->command->execute();
$data = $result['data'];
$lastItem = end($data);
$response = $this->client->execute($this->command);

// This avoid to do any additional request
$this->nextToken = $result['has_more'] ? $lastItem['id'] : false;
$this->result = $response['data'];
$this->requestCount++;

return $data;
if ($response['has_more']) {
$this->nextToken = end($response['data'])['id'];
}
}
}
Loading