2013-01-23 21:45:32 -06:00
|
|
|
Guzzle Upgrade Guide
|
|
|
|
====================
|
|
|
|
|
2013-03-03 16:41:45 -08:00
|
|
|
3.2 to 3.3
|
|
|
|
----------
|
|
|
|
|
|
|
|
### Response::getEtag() quote stripping removed
|
|
|
|
|
|
|
|
`Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header
|
|
|
|
|
|
|
|
### Removed `Guzzle\Http\Utils`
|
|
|
|
|
|
|
|
The `Guzzle\Http\Utils` class was removed. This class was only used for testing.
|
|
|
|
|
|
|
|
### Stream wrapper and type
|
|
|
|
|
|
|
|
`Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to lowercase.
|
|
|
|
|
|
|
|
### curl.emit_io became emit_io
|
|
|
|
|
|
|
|
Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the
|
|
|
|
'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
|
|
|
|
|
2013-02-12 22:55:52 -08:00
|
|
|
3.1 to 3.2
|
|
|
|
----------
|
|
|
|
|
|
|
|
### CurlMulti is no longer reused globally
|
|
|
|
|
|
|
|
Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added
|
|
|
|
to a single client can pollute requests dispatched from other clients.
|
|
|
|
|
|
|
|
If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the
|
|
|
|
ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is
|
|
|
|
created.
|
|
|
|
|
|
|
|
```php
|
|
|
|
$multi = new Guzzle\Http\Curl\CurlMulti();
|
|
|
|
$builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json');
|
|
|
|
$builder->addListener('service_builder.create_client', function ($event) use ($multi) {
|
|
|
|
$event['client']->setCurlMulti($multi);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
### No default path
|
|
|
|
|
|
|
|
URLs no longer have a default path value of '/' if no path was specified.
|
|
|
|
|
|
|
|
Before:
|
|
|
|
|
|
|
|
```php
|
|
|
|
$request = $client->get('http://www.foo.com');
|
|
|
|
echo $request->getUrl();
|
|
|
|
// >> http://www.foo.com/
|
|
|
|
```
|
|
|
|
|
|
|
|
After:
|
|
|
|
|
|
|
|
```php
|
|
|
|
$request = $client->get('http://www.foo.com');
|
|
|
|
echo $request->getUrl();
|
|
|
|
// >> http://www.foo.com
|
|
|
|
```
|
|
|
|
|
|
|
|
### Less verbose BadResponseException
|
|
|
|
|
|
|
|
The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and
|
|
|
|
response information. You can, however, get access to the request and response object by calling `getRequest()` or
|
|
|
|
`getResponse()` on the exception object.
|
|
|
|
|
2013-02-13 23:28:44 -08:00
|
|
|
|
|
|
|
### Query parameter aggregation
|
|
|
|
|
|
|
|
Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a
|
|
|
|
setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is
|
|
|
|
responsible for handling the aggregation of multi-valued query string variables into a flattened hash.
|
|
|
|
|
2013-01-23 21:45:32 -06:00
|
|
|
2.8 to 3.x
|
|
|
|
----------
|
|
|
|
|
|
|
|
### Guzzle\Service\Inspector
|
|
|
|
|
|
|
|
Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig`
|
|
|
|
|
|
|
|
**Before**
|
|
|
|
|
|
|
|
```php
|
|
|
|
use Guzzle\Service\Inspector;
|
|
|
|
|
|
|
|
class YourClient extends \Guzzle\Service\Client
|
|
|
|
{
|
|
|
|
public static function factory($config = array())
|
|
|
|
{
|
|
|
|
$default = array();
|
|
|
|
$required = array('base_url', 'username', 'api_key');
|
|
|
|
$config = Inspector::fromConfig($config, $default, $required);
|
|
|
|
|
|
|
|
$client = new self(
|
|
|
|
$config->get('base_url'),
|
|
|
|
$config->get('username'),
|
|
|
|
$config->get('api_key')
|
|
|
|
);
|
|
|
|
$client->setConfig($config);
|
|
|
|
|
|
|
|
$client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
|
|
|
|
|
|
|
|
return $client;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
**After**
|
|
|
|
|
|
|
|
```php
|
|
|
|
use Guzzle\Common\Collection;
|
|
|
|
|
|
|
|
class YourClient extends \Guzzle\Service\Client
|
|
|
|
{
|
|
|
|
public static function factory($config = array())
|
|
|
|
{
|
|
|
|
$default = array();
|
|
|
|
$required = array('base_url', 'username', 'api_key');
|
|
|
|
$config = Collection::fromConfig($config, $default, $required);
|
|
|
|
|
|
|
|
$client = new self(
|
|
|
|
$config->get('base_url'),
|
|
|
|
$config->get('username'),
|
|
|
|
$config->get('api_key')
|
|
|
|
);
|
|
|
|
$client->setConfig($config);
|
|
|
|
|
|
|
|
$client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
|
|
|
|
|
|
|
|
return $client;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Convert XML Service Descriptions to JSON
|
|
|
|
|
|
|
|
**Before**
|
|
|
|
|
|
|
|
```xml
|
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
<client>
|
|
|
|
<commands>
|
|
|
|
<!-- Groups -->
|
|
|
|
<command name="list_groups" method="GET" uri="groups.json">
|
|
|
|
<doc>Get a list of groups</doc>
|
|
|
|
</command>
|
|
|
|
<command name="search_groups" method="GET" uri='search.json?query="{{query}} type:group"'>
|
|
|
|
<doc>Uses a search query to get a list of groups</doc>
|
|
|
|
<param name="query" type="string" required="true" />
|
|
|
|
</command>
|
|
|
|
<command name="create_group" method="POST" uri="groups.json">
|
|
|
|
<doc>Create a group</doc>
|
|
|
|
<param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/>
|
|
|
|
<param name="Content-Type" location="header" static="application/json"/>
|
|
|
|
</command>
|
|
|
|
<command name="delete_group" method="DELETE" uri="groups/{{id}}.json">
|
|
|
|
<doc>Delete a group by ID</doc>
|
|
|
|
<param name="id" type="integer" required="true"/>
|
|
|
|
</command>
|
|
|
|
<command name="get_group" method="GET" uri="groups/{{id}}.json">
|
|
|
|
<param name="id" type="integer" required="true"/>
|
|
|
|
</command>
|
|
|
|
<command name="update_group" method="PUT" uri="groups/{{id}}.json">
|
|
|
|
<doc>Update a group</doc>
|
|
|
|
<param name="id" type="integer" required="true"/>
|
|
|
|
<param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/>
|
|
|
|
<param name="Content-Type" location="header" static="application/json"/>
|
|
|
|
</command>
|
|
|
|
</commands>
|
|
|
|
</client>
|
|
|
|
```
|
|
|
|
|
|
|
|
**After**
|
|
|
|
|
|
|
|
```json
|
|
|
|
{
|
|
|
|
"name": "Zendesk REST API v2",
|
|
|
|
"apiVersion": "2012-12-31",
|
|
|
|
"description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users",
|
|
|
|
"operations": {
|
|
|
|
"list_groups": {
|
|
|
|
"httpMethod":"GET",
|
|
|
|
"uri": "groups.json",
|
|
|
|
"summary": "Get a list of groups"
|
|
|
|
},
|
|
|
|
"search_groups":{
|
|
|
|
"httpMethod":"GET",
|
|
|
|
"uri": "search.json?query=\"{query} type:group\"",
|
|
|
|
"summary": "Uses a search query to get a list of groups",
|
|
|
|
"parameters":{
|
|
|
|
"query":{
|
|
|
|
"location": "uri",
|
|
|
|
"description":"Zendesk Search Query",
|
|
|
|
"type": "string",
|
|
|
|
"required": true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"create_group": {
|
|
|
|
"httpMethod":"POST",
|
|
|
|
"uri": "groups.json",
|
|
|
|
"summary": "Create a group",
|
|
|
|
"parameters":{
|
|
|
|
"data": {
|
|
|
|
"type": "array",
|
|
|
|
"location": "body",
|
|
|
|
"description":"Group JSON",
|
|
|
|
"filters": "json_encode",
|
|
|
|
"required": true
|
|
|
|
},
|
|
|
|
"Content-Type":{
|
|
|
|
"type": "string",
|
|
|
|
"location":"header",
|
|
|
|
"static": "application/json"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"delete_group": {
|
|
|
|
"httpMethod":"DELETE",
|
|
|
|
"uri": "groups/{id}.json",
|
|
|
|
"summary": "Delete a group",
|
|
|
|
"parameters":{
|
|
|
|
"id":{
|
|
|
|
"location": "uri",
|
|
|
|
"description":"Group to delete by ID",
|
|
|
|
"type": "integer",
|
|
|
|
"required": true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"get_group": {
|
|
|
|
"httpMethod":"GET",
|
|
|
|
"uri": "groups/{id}.json",
|
|
|
|
"summary": "Get a ticket",
|
|
|
|
"parameters":{
|
|
|
|
"id":{
|
|
|
|
"location": "uri",
|
|
|
|
"description":"Group to get by ID",
|
|
|
|
"type": "integer",
|
|
|
|
"required": true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"update_group": {
|
|
|
|
"httpMethod":"PUT",
|
|
|
|
"uri": "groups/{id}.json",
|
|
|
|
"summary": "Update a group",
|
|
|
|
"parameters":{
|
|
|
|
"id": {
|
|
|
|
"location": "uri",
|
|
|
|
"description":"Group to update by ID",
|
|
|
|
"type": "integer",
|
|
|
|
"required": true
|
|
|
|
},
|
|
|
|
"data": {
|
|
|
|
"type": "array",
|
|
|
|
"location": "body",
|
|
|
|
"description":"Group JSON",
|
|
|
|
"filters": "json_encode",
|
|
|
|
"required": true
|
|
|
|
},
|
|
|
|
"Content-Type":{
|
|
|
|
"type": "string",
|
|
|
|
"location":"header",
|
|
|
|
"static": "application/json"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Guzzle\Service\Description\ServiceDescription
|
|
|
|
|
|
|
|
Commands are now called Operations
|
|
|
|
|
|
|
|
**Before**
|
|
|
|
|
|
|
|
```php
|
|
|
|
use Guzzle\Service\Description\ServiceDescription;
|
|
|
|
|
|
|
|
$sd = new ServiceDescription();
|
|
|
|
$sd->getCommands(); // @returns ApiCommandInterface[]
|
|
|
|
$sd->hasCommand($name);
|
|
|
|
$sd->getCommand($name); // @returns ApiCommandInterface|null
|
|
|
|
$sd->addCommand($command); // @param ApiCommandInterface $command
|
|
|
|
```
|
|
|
|
|
|
|
|
**After**
|
|
|
|
|
|
|
|
```php
|
|
|
|
use Guzzle\Service\Description\ServiceDescription;
|
|
|
|
|
|
|
|
$sd = new ServiceDescription();
|
|
|
|
$sd->getOperations(); // @returns OperationInterface[]
|
|
|
|
$sd->hasOperation($name);
|
|
|
|
$sd->getOperation($name); // @returns OperationInterface|null
|
|
|
|
$sd->addOperation($operation); // @param OperationInterface $operation
|
|
|
|
```
|
|
|
|
|
|
|
|
### Guzzle\Common\Inflection\Inflector
|
|
|
|
|
|
|
|
Namespace is now `Guzzle\Inflection\Inflector`
|
|
|
|
|
|
|
|
### Guzzle\Http\Plugin
|
|
|
|
|
|
|
|
Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below.
|
|
|
|
|
|
|
|
### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log
|
|
|
|
|
|
|
|
Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively.
|
|
|
|
|
|
|
|
**Before**
|
|
|
|
|
|
|
|
```php
|
|
|
|
use Guzzle\Common\Log\ClosureLogAdapter;
|
|
|
|
use Guzzle\Http\Plugin\LogPlugin;
|
|
|
|
|
|
|
|
/** @var \Guzzle\Http\Client */
|
|
|
|
$client;
|
|
|
|
|
|
|
|
// $verbosity is an integer indicating desired message verbosity level
|
|
|
|
$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE);
|
|
|
|
```
|
|
|
|
|
|
|
|
**After**
|
|
|
|
|
|
|
|
```php
|
|
|
|
use Guzzle\Log\ClosureLogAdapter;
|
|
|
|
use Guzzle\Log\MessageFormatter;
|
|
|
|
use Guzzle\Plugin\Log\LogPlugin;
|
|
|
|
|
|
|
|
/** @var \Guzzle\Http\Client */
|
|
|
|
$client;
|
|
|
|
|
|
|
|
// $format is a string indicating desired message format -- @see MessageFormatter
|
|
|
|
$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT);
|
|
|
|
```
|
|
|
|
|
|
|
|
### Guzzle\Http\Plugin\CurlAuthPlugin
|
|
|
|
|
|
|
|
Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`.
|
|
|
|
|
|
|
|
### Guzzle\Http\Plugin\ExponentialBackoffPlugin
|
|
|
|
|
|
|
|
Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes.
|
|
|
|
|
|
|
|
**Before**
|
|
|
|
|
|
|
|
```php
|
|
|
|
use Guzzle\Http\Plugin\ExponentialBackoffPlugin;
|
|
|
|
|
|
|
|
$backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge(
|
|
|
|
ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429)
|
|
|
|
));
|
|
|
|
|
|
|
|
$client->addSubscriber($backoffPlugin);
|
|
|
|
```
|
|
|
|
|
|
|
|
**After**
|
|
|
|
|
|
|
|
```php
|
|
|
|
use Guzzle\Plugin\Backoff\BackoffPlugin;
|
|
|
|
use Guzzle\Plugin\Backoff\HttpBackoffStrategy;
|
|
|
|
|
|
|
|
// Use convenient factory method instead -- see implementation for ideas of what
|
|
|
|
// you can do with chaining backoff strategies
|
|
|
|
$backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge(
|
|
|
|
HttpBackoffStrategy::getDefaultFailureCodes(), array(429)
|
|
|
|
));
|
|
|
|
$client->addSubscriber($backoffPlugin);
|
2013-01-23 21:51:55 -06:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Known Issues
|
|
|
|
|
2013-02-12 22:55:52 -08:00
|
|
|
#### [BUG] Accept-Encoding header behavior changed unintentionally.
|
2013-01-23 21:53:25 -06:00
|
|
|
|
|
|
|
(See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e)
|
2013-01-23 21:51:55 -06:00
|
|
|
|
|
|
|
In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to
|
|
|
|
properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen.
|
2013-01-23 21:53:25 -06:00
|
|
|
See issue #217 for a workaround, or use a version containing the fix.
|