1Guzzle Upgrade Guide 2==================== 3 46.0 to 7.0 5---------- 6 7In order to take advantage of the new features of PHP, Guzzle dropped the support 8of PHP 5. The minimum supported PHP version is now PHP 7.2. Type hints and return 9types for functions and methods have been added wherever possible. 10 11Please make sure: 12- You are calling a function or a method with the correct type. 13- If you extend a class of Guzzle; update all signatures on methods you override. 14 15#### Other backwards compatibility breaking changes 16 17- Class `GuzzleHttp\UriTemplate` is removed. 18- Class `GuzzleHttp\Exception\SeekException` is removed. 19- Classes `GuzzleHttp\Exception\BadResponseException`, `GuzzleHttp\Exception\ClientException`, 20 `GuzzleHttp\Exception\ServerException` can no longer be initialized with an empty 21 Response as argument. 22- Class `GuzzleHttp\Exception\ConnectException` now extends `GuzzleHttp\Exception\TransferException` 23 instead of `GuzzleHttp\Exception\RequestException`. 24- Function `GuzzleHttp\Exception\ConnectException::getResponse()` is removed. 25- Function `GuzzleHttp\Exception\ConnectException::hasResponse()` is removed. 26- Constant `GuzzleHttp\ClientInterface::VERSION` is removed. Added `GuzzleHttp\ClientInterface::MAJOR_VERSION` instead. 27- Function `GuzzleHttp\Exception\RequestException::getResponseBodySummary` is removed. 28 Use `\GuzzleHttp\Psr7\get_message_body_summary` as an alternative. 29- Function `GuzzleHttp\Cookie\CookieJar::getCookieValue` is removed. 30- Request option `exceptions` is removed. Please use `http_errors`. 31- Request option `save_to` is removed. Please use `sink`. 32- Pool option `pool_size` is removed. Please use `concurrency`. 33- We now look for environment variables in the `$_SERVER` super global, due to thread safety issues with `getenv`. We continue to fallback to `getenv` in CLI environments, for maximum compatibility. 34- The `get`, `head`, `put`, `post`, `patch`, `delete`, `getAsync`, `headAsync`, `putAsync`, `postAsync`, `patchAsync`, and `deleteAsync` methods are now implemented as genuine methods on `GuzzleHttp\Client`, with strong typing. The original `__call` implementation remains unchanged for now, for maximum backwards compatibility, but won't be invoked under normal operation. 35- The `log` middleware will log the errors with level `error` instead of `notice` 36- Support for international domain names (IDN) is now disabled by default, and enabling it requires installing ext-intl, linked against a modern version of the C library (ICU 4.6 or higher). 37 38#### Native functions calls 39 40All internal native functions calls of Guzzle are now prefixed with a slash. This 41change makes it impossible for method overloading by other libraries or applications. 42Example: 43 44```php 45// Before: 46curl_version(); 47 48// After: 49\curl_version(); 50``` 51 52For the full diff you can check [here](https://github.com/guzzle/guzzle/compare/6.5.4..master). 53 545.0 to 6.0 55---------- 56 57Guzzle now uses [PSR-7](https://www.php-fig.org/psr/psr-7/) for HTTP messages. 58Due to the fact that these messages are immutable, this prompted a refactoring 59of Guzzle to use a middleware based system rather than an event system. Any 60HTTP message interaction (e.g., `GuzzleHttp\Message\Request`) need to be 61updated to work with the new immutable PSR-7 request and response objects. Any 62event listeners or subscribers need to be updated to become middleware 63functions that wrap handlers (or are injected into a 64`GuzzleHttp\HandlerStack`). 65 66- Removed `GuzzleHttp\BatchResults` 67- Removed `GuzzleHttp\Collection` 68- Removed `GuzzleHttp\HasDataTrait` 69- Removed `GuzzleHttp\ToArrayInterface` 70- The `guzzlehttp/streams` dependency has been removed. Stream functionality 71 is now present in the `GuzzleHttp\Psr7` namespace provided by the 72 `guzzlehttp/psr7` package. 73- Guzzle no longer uses ReactPHP promises and now uses the 74 `guzzlehttp/promises` library. We use a custom promise library for three 75 significant reasons: 76 1. React promises (at the time of writing this) are recursive. Promise 77 chaining and promise resolution will eventually blow the stack. Guzzle 78 promises are not recursive as they use a sort of trampolining technique. 79 Note: there has been movement in the React project to modify promises to 80 no longer utilize recursion. 81 2. Guzzle needs to have the ability to synchronously block on a promise to 82 wait for a result. Guzzle promises allows this functionality (and does 83 not require the use of recursion). 84 3. Because we need to be able to wait on a result, doing so using React 85 promises requires wrapping react promises with RingPHP futures. This 86 overhead is no longer needed, reducing stack sizes, reducing complexity, 87 and improving performance. 88- `GuzzleHttp\Mimetypes` has been moved to a function in 89 `GuzzleHttp\Psr7\mimetype_from_extension` and 90 `GuzzleHttp\Psr7\mimetype_from_filename`. 91- `GuzzleHttp\Query` and `GuzzleHttp\QueryParser` have been removed. Query 92 strings must now be passed into request objects as strings, or provided to 93 the `query` request option when creating requests with clients. The `query` 94 option uses PHP's `http_build_query` to convert an array to a string. If you 95 need a different serialization technique, you will need to pass the query 96 string in as a string. There are a couple helper functions that will make 97 working with query strings easier: `GuzzleHttp\Psr7\parse_query` and 98 `GuzzleHttp\Psr7\build_query`. 99- Guzzle no longer has a dependency on RingPHP. Due to the use of a middleware 100 system based on PSR-7, using RingPHP and it's middleware system as well adds 101 more complexity than the benefits it provides. All HTTP handlers that were 102 present in RingPHP have been modified to work directly with PSR-7 messages 103 and placed in the `GuzzleHttp\Handler` namespace. This significantly reduces 104 complexity in Guzzle, removes a dependency, and improves performance. RingPHP 105 will be maintained for Guzzle 5 support, but will no longer be a part of 106 Guzzle 6. 107- As Guzzle now uses a middleware based systems the event system and RingPHP 108 integration has been removed. Note: while the event system has been removed, 109 it is possible to add your own type of event system that is powered by the 110 middleware system. 111 - Removed the `Event` namespace. 112 - Removed the `Subscriber` namespace. 113 - Removed `Transaction` class 114 - Removed `RequestFsm` 115 - Removed `RingBridge` 116 - `GuzzleHttp\Subscriber\Cookie` is now provided by 117 `GuzzleHttp\Middleware::cookies` 118 - `GuzzleHttp\Subscriber\HttpError` is now provided by 119 `GuzzleHttp\Middleware::httpError` 120 - `GuzzleHttp\Subscriber\History` is now provided by 121 `GuzzleHttp\Middleware::history` 122 - `GuzzleHttp\Subscriber\Mock` is now provided by 123 `GuzzleHttp\Handler\MockHandler` 124 - `GuzzleHttp\Subscriber\Prepare` is now provided by 125 `GuzzleHttp\PrepareBodyMiddleware` 126 - `GuzzleHttp\Subscriber\Redirect` is now provided by 127 `GuzzleHttp\RedirectMiddleware` 128- Guzzle now uses `Psr\Http\Message\UriInterface` (implements in 129 `GuzzleHttp\Psr7\Uri`) for URI support. `GuzzleHttp\Url` is now gone. 130- Static functions in `GuzzleHttp\Utils` have been moved to namespaced 131 functions under the `GuzzleHttp` namespace. This requires either a Composer 132 based autoloader or you to include functions.php. 133- `GuzzleHttp\ClientInterface::getDefaultOption` has been renamed to 134 `GuzzleHttp\ClientInterface::getConfig`. 135- `GuzzleHttp\ClientInterface::setDefaultOption` has been removed. 136- The `json` and `xml` methods of response objects has been removed. With the 137 migration to strictly adhering to PSR-7 as the interface for Guzzle messages, 138 adding methods to message interfaces would actually require Guzzle messages 139 to extend from PSR-7 messages rather then work with them directly. 140 141## Migrating to middleware 142 143The change to PSR-7 unfortunately required significant refactoring to Guzzle 144due to the fact that PSR-7 messages are immutable. Guzzle 5 relied on an event 145system from plugins. The event system relied on mutability of HTTP messages and 146side effects in order to work. With immutable messages, you have to change your 147workflow to become more about either returning a value (e.g., functional 148middlewares) or setting a value on an object. Guzzle v6 has chosen the 149functional middleware approach. 150 151Instead of using the event system to listen for things like the `before` event, 152you now create a stack based middleware function that intercepts a request on 153the way in and the promise of the response on the way out. This is a much 154simpler and more predictable approach than the event system and works nicely 155with PSR-7 middleware. Due to the use of promises, the middleware system is 156also asynchronous. 157 158v5: 159 160```php 161use GuzzleHttp\Event\BeforeEvent; 162$client = new GuzzleHttp\Client(); 163// Get the emitter and listen to the before event. 164$client->getEmitter()->on('before', function (BeforeEvent $e) { 165 // Guzzle v5 events relied on mutation 166 $e->getRequest()->setHeader('X-Foo', 'Bar'); 167}); 168``` 169 170v6: 171 172In v6, you can modify the request before it is sent using the `mapRequest` 173middleware. The idiomatic way in v6 to modify the request/response lifecycle is 174to setup a handler middleware stack up front and inject the handler into a 175client. 176 177```php 178use GuzzleHttp\Middleware; 179// Create a handler stack that has all of the default middlewares attached 180$handler = GuzzleHttp\HandlerStack::create(); 181// Push the handler onto the handler stack 182$handler->push(Middleware::mapRequest(function (RequestInterface $request) { 183 // Notice that we have to return a request object 184 return $request->withHeader('X-Foo', 'Bar'); 185})); 186// Inject the handler into the client 187$client = new GuzzleHttp\Client(['handler' => $handler]); 188``` 189 190## POST Requests 191 192This version added the [`form_params`](https://docs.guzzlephp.org/en/latest/request-options.html#form_params) 193and `multipart` request options. `form_params` is an associative array of 194strings or array of strings and is used to serialize an 195`application/x-www-form-urlencoded` POST request. The 196[`multipart`](https://docs.guzzlephp.org/en/latest/request-options.html#multipart) 197option is now used to send a multipart/form-data POST request. 198 199`GuzzleHttp\Post\PostFile` has been removed. Use the `multipart` option to add 200POST files to a multipart/form-data request. 201 202The `body` option no longer accepts an array to send POST requests. Please use 203`multipart` or `form_params` instead. 204 205The `base_url` option has been renamed to `base_uri`. 206 2074.x to 5.0 208---------- 209 210## Rewritten Adapter Layer 211 212Guzzle now uses [RingPHP](https://ringphp.readthedocs.org/en/latest) to send 213HTTP requests. The `adapter` option in a `GuzzleHttp\Client` constructor 214is still supported, but it has now been renamed to `handler`. Instead of 215passing a `GuzzleHttp\Adapter\AdapterInterface`, you must now pass a PHP 216`callable` that follows the RingPHP specification. 217 218## Removed Fluent Interfaces 219 220[Fluent interfaces were removed](https://ocramius.github.io/blog/fluent-interfaces-are-evil/) 221from the following classes: 222 223- `GuzzleHttp\Collection` 224- `GuzzleHttp\Url` 225- `GuzzleHttp\Query` 226- `GuzzleHttp\Post\PostBody` 227- `GuzzleHttp\Cookie\SetCookie` 228 229## Removed functions.php 230 231Removed "functions.php", so that Guzzle is truly PSR-4 compliant. The following 232functions can be used as replacements. 233 234- `GuzzleHttp\json_decode` -> `GuzzleHttp\Utils::jsonDecode` 235- `GuzzleHttp\get_path` -> `GuzzleHttp\Utils::getPath` 236- `GuzzleHttp\Utils::setPath` -> `GuzzleHttp\set_path` 237- `GuzzleHttp\Pool::batch` -> `GuzzleHttp\batch`. This function is, however, 238 deprecated in favor of using `GuzzleHttp\Pool::batch()`. 239 240The "procedural" global client has been removed with no replacement (e.g., 241`GuzzleHttp\get()`, `GuzzleHttp\post()`, etc.). Use a `GuzzleHttp\Client` 242object as a replacement. 243 244## `throwImmediately` has been removed 245 246The concept of "throwImmediately" has been removed from exceptions and error 247events. This control mechanism was used to stop a transfer of concurrent 248requests from completing. This can now be handled by throwing the exception or 249by cancelling a pool of requests or each outstanding future request 250individually. 251 252## headers event has been removed 253 254Removed the "headers" event. This event was only useful for changing the 255body a response once the headers of the response were known. You can implement 256a similar behavior in a number of ways. One example might be to use a 257FnStream that has access to the transaction being sent. For example, when the 258first byte is written, you could check if the response headers match your 259expectations, and if so, change the actual stream body that is being 260written to. 261 262## Updates to HTTP Messages 263 264Removed the `asArray` parameter from 265`GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header 266value as an array, then use the newly added `getHeaderAsArray()` method of 267`MessageInterface`. This change makes the Guzzle interfaces compatible with 268the PSR-7 interfaces. 269 2703.x to 4.0 271---------- 272 273## Overarching changes: 274 275- Now requires PHP 5.4 or greater. 276- No longer requires cURL to send requests. 277- Guzzle no longer wraps every exception it throws. Only exceptions that are 278 recoverable are now wrapped by Guzzle. 279- Various namespaces have been removed or renamed. 280- No longer requiring the Symfony EventDispatcher. A custom event dispatcher 281 based on the Symfony EventDispatcher is 282 now utilized in `GuzzleHttp\Event\EmitterInterface` (resulting in significant 283 speed and functionality improvements). 284 285Changes per Guzzle 3.x namespace are described below. 286 287## Batch 288 289The `Guzzle\Batch` namespace has been removed. This is best left to 290third-parties to implement on top of Guzzle's core HTTP library. 291 292## Cache 293 294The `Guzzle\Cache` namespace has been removed. (Todo: No suitable replacement 295has been implemented yet, but hoping to utilize a PSR cache interface). 296 297## Common 298 299- Removed all of the wrapped exceptions. It's better to use the standard PHP 300 library for unrecoverable exceptions. 301- `FromConfigInterface` has been removed. 302- `Guzzle\Common\Version` has been removed. The VERSION constant can be found 303 at `GuzzleHttp\ClientInterface::VERSION`. 304 305### Collection 306 307- `getAll` has been removed. Use `toArray` to convert a collection to an array. 308- `inject` has been removed. 309- `keySearch` has been removed. 310- `getPath` no longer supports wildcard expressions. Use something better like 311 JMESPath for this. 312- `setPath` now supports appending to an existing array via the `[]` notation. 313 314### Events 315 316Guzzle no longer requires Symfony's EventDispatcher component. Guzzle now uses 317`GuzzleHttp\Event\Emitter`. 318 319- `Symfony\Component\EventDispatcher\EventDispatcherInterface` is replaced by 320 `GuzzleHttp\Event\EmitterInterface`. 321- `Symfony\Component\EventDispatcher\EventDispatcher` is replaced by 322 `GuzzleHttp\Event\Emitter`. 323- `Symfony\Component\EventDispatcher\Event` is replaced by 324 `GuzzleHttp\Event\Event`, and Guzzle now has an EventInterface in 325 `GuzzleHttp\Event\EventInterface`. 326- `AbstractHasDispatcher` has moved to a trait, `HasEmitterTrait`, and 327 `HasDispatcherInterface` has moved to `HasEmitterInterface`. Retrieving the 328 event emitter of a request, client, etc. now uses the `getEmitter` method 329 rather than the `getDispatcher` method. 330 331#### Emitter 332 333- Use the `once()` method to add a listener that automatically removes itself 334 the first time it is invoked. 335- Use the `listeners()` method to retrieve a list of event listeners rather than 336 the `getListeners()` method. 337- Use `emit()` instead of `dispatch()` to emit an event from an emitter. 338- Use `attach()` instead of `addSubscriber()` and `detach()` instead of 339 `removeSubscriber()`. 340 341```php 342$mock = new Mock(); 343// 3.x 344$request->getEventDispatcher()->addSubscriber($mock); 345$request->getEventDispatcher()->removeSubscriber($mock); 346// 4.x 347$request->getEmitter()->attach($mock); 348$request->getEmitter()->detach($mock); 349``` 350 351Use the `on()` method to add a listener rather than the `addListener()` method. 352 353```php 354// 3.x 355$request->getEventDispatcher()->addListener('foo', function (Event $event) { /* ... */ } ); 356// 4.x 357$request->getEmitter()->on('foo', function (Event $event, $name) { /* ... */ } ); 358``` 359 360## Http 361 362### General changes 363 364- The cacert.pem certificate has been moved to `src/cacert.pem`. 365- Added the concept of adapters that are used to transfer requests over the 366 wire. 367- Simplified the event system. 368- Sending requests in parallel is still possible, but batching is no longer a 369 concept of the HTTP layer. Instead, you must use the `complete` and `error` 370 events to asynchronously manage parallel request transfers. 371- `Guzzle\Http\Url` has moved to `GuzzleHttp\Url`. 372- `Guzzle\Http\QueryString` has moved to `GuzzleHttp\Query`. 373- QueryAggregators have been rewritten so that they are simply callable 374 functions. 375- `GuzzleHttp\StaticClient` has been removed. Use the functions provided in 376 `functions.php` for an easy to use static client instance. 377- Exceptions in `GuzzleHttp\Exception` have been updated to all extend from 378 `GuzzleHttp\Exception\TransferException`. 379 380### Client 381 382Calling methods like `get()`, `post()`, `head()`, etc. no longer create and 383return a request, but rather creates a request, sends the request, and returns 384the response. 385 386```php 387// 3.0 388$request = $client->get('/'); 389$response = $request->send(); 390 391// 4.0 392$response = $client->get('/'); 393 394// or, to mirror the previous behavior 395$request = $client->createRequest('GET', '/'); 396$response = $client->send($request); 397``` 398 399`GuzzleHttp\ClientInterface` has changed. 400 401- The `send` method no longer accepts more than one request. Use `sendAll` to 402 send multiple requests in parallel. 403- `setUserAgent()` has been removed. Use a default request option instead. You 404 could, for example, do something like: 405 `$client->setConfig('defaults/headers/User-Agent', 'Foo/Bar ' . $client::getDefaultUserAgent())`. 406- `setSslVerification()` has been removed. Use default request options instead, 407 like `$client->setConfig('defaults/verify', true)`. 408 409`GuzzleHttp\Client` has changed. 410 411- The constructor now accepts only an associative array. You can include a 412 `base_url` string or array to use a URI template as the base URL of a client. 413 You can also specify a `defaults` key that is an associative array of default 414 request options. You can pass an `adapter` to use a custom adapter, 415 `batch_adapter` to use a custom adapter for sending requests in parallel, or 416 a `message_factory` to change the factory used to create HTTP requests and 417 responses. 418- The client no longer emits a `client.create_request` event. 419- Creating requests with a client no longer automatically utilize a URI 420 template. You must pass an array into a creational method (e.g., 421 `createRequest`, `get`, `put`, etc.) in order to expand a URI template. 422 423### Messages 424 425Messages no longer have references to their counterparts (i.e., a request no 426longer has a reference to it's response, and a response no loger has a 427reference to its request). This association is now managed through a 428`GuzzleHttp\Adapter\TransactionInterface` object. You can get references to 429these transaction objects using request events that are emitted over the 430lifecycle of a request. 431 432#### Requests with a body 433 434- `GuzzleHttp\Message\EntityEnclosingRequest` and 435 `GuzzleHttp\Message\EntityEnclosingRequestInterface` have been removed. The 436 separation between requests that contain a body and requests that do not 437 contain a body has been removed, and now `GuzzleHttp\Message\RequestInterface` 438 handles both use cases. 439- Any method that previously accepts a `GuzzleHttp\Response` object now accept a 440 `GuzzleHttp\Message\ResponseInterface`. 441- `GuzzleHttp\Message\RequestFactoryInterface` has been renamed to 442 `GuzzleHttp\Message\MessageFactoryInterface`. This interface is used to create 443 both requests and responses and is implemented in 444 `GuzzleHttp\Message\MessageFactory`. 445- POST field and file methods have been removed from the request object. You 446 must now use the methods made available to `GuzzleHttp\Post\PostBodyInterface` 447 to control the format of a POST body. Requests that are created using a 448 standard `GuzzleHttp\Message\MessageFactoryInterface` will automatically use 449 a `GuzzleHttp\Post\PostBody` body if the body was passed as an array or if 450 the method is POST and no body is provided. 451 452```php 453$request = $client->createRequest('POST', '/'); 454$request->getBody()->setField('foo', 'bar'); 455$request->getBody()->addFile(new PostFile('file_key', fopen('/path/to/content', 'r'))); 456``` 457 458#### Headers 459 460- `GuzzleHttp\Message\Header` has been removed. Header values are now simply 461 represented by an array of values or as a string. Header values are returned 462 as a string by default when retrieving a header value from a message. You can 463 pass an optional argument of `true` to retrieve a header value as an array 464 of strings instead of a single concatenated string. 465- `GuzzleHttp\PostFile` and `GuzzleHttp\PostFileInterface` have been moved to 466 `GuzzleHttp\Post`. This interface has been simplified and now allows the 467 addition of arbitrary headers. 468- Custom headers like `GuzzleHttp\Message\Header\Link` have been removed. Most 469 of the custom headers are now handled separately in specific 470 subscribers/plugins, and `GuzzleHttp\Message\HeaderValues::parseParams()` has 471 been updated to properly handle headers that contain parameters (like the 472 `Link` header). 473 474#### Responses 475 476- `GuzzleHttp\Message\Response::getInfo()` and 477 `GuzzleHttp\Message\Response::setInfo()` have been removed. Use the event 478 system to retrieve this type of information. 479- `GuzzleHttp\Message\Response::getRawHeaders()` has been removed. 480- `GuzzleHttp\Message\Response::getMessage()` has been removed. 481- `GuzzleHttp\Message\Response::calculateAge()` and other cache specific 482 methods have moved to the CacheSubscriber. 483- Header specific helper functions like `getContentMd5()` have been removed. 484 Just use `getHeader('Content-MD5')` instead. 485- `GuzzleHttp\Message\Response::setRequest()` and 486 `GuzzleHttp\Message\Response::getRequest()` have been removed. Use the event 487 system to work with request and response objects as a transaction. 488- `GuzzleHttp\Message\Response::getRedirectCount()` has been removed. Use the 489 Redirect subscriber instead. 490- `GuzzleHttp\Message\Response::isSuccessful()` and other related methods have 491 been removed. Use `getStatusCode()` instead. 492 493#### Streaming responses 494 495Streaming requests can now be created by a client directly, returning a 496`GuzzleHttp\Message\ResponseInterface` object that contains a body stream 497referencing an open PHP HTTP stream. 498 499```php 500// 3.0 501use Guzzle\Stream\PhpStreamRequestFactory; 502$request = $client->get('/'); 503$factory = new PhpStreamRequestFactory(); 504$stream = $factory->fromRequest($request); 505$data = $stream->read(1024); 506 507// 4.0 508$response = $client->get('/', ['stream' => true]); 509// Read some data off of the stream in the response body 510$data = $response->getBody()->read(1024); 511``` 512 513#### Redirects 514 515The `configureRedirects()` method has been removed in favor of a 516`allow_redirects` request option. 517 518```php 519// Standard redirects with a default of a max of 5 redirects 520$request = $client->createRequest('GET', '/', ['allow_redirects' => true]); 521 522// Strict redirects with a custom number of redirects 523$request = $client->createRequest('GET', '/', [ 524 'allow_redirects' => ['max' => 5, 'strict' => true] 525]); 526``` 527 528#### EntityBody 529 530EntityBody interfaces and classes have been removed or moved to 531`GuzzleHttp\Stream`. All classes and interfaces that once required 532`GuzzleHttp\EntityBodyInterface` now require 533`GuzzleHttp\Stream\StreamInterface`. Creating a new body for a request no 534longer uses `GuzzleHttp\EntityBody::factory` but now uses 535`GuzzleHttp\Stream\Stream::factory` or even better: 536`GuzzleHttp\Stream\create()`. 537 538- `Guzzle\Http\EntityBodyInterface` is now `GuzzleHttp\Stream\StreamInterface` 539- `Guzzle\Http\EntityBody` is now `GuzzleHttp\Stream\Stream` 540- `Guzzle\Http\CachingEntityBody` is now `GuzzleHttp\Stream\CachingStream` 541- `Guzzle\Http\ReadLimitEntityBody` is now `GuzzleHttp\Stream\LimitStream` 542- `Guzzle\Http\IoEmittyinEntityBody` has been removed. 543 544#### Request lifecycle events 545 546Requests previously submitted a large number of requests. The number of events 547emitted over the lifecycle of a request has been significantly reduced to make 548it easier to understand how to extend the behavior of a request. All events 549emitted during the lifecycle of a request now emit a custom 550`GuzzleHttp\Event\EventInterface` object that contains context providing 551methods and a way in which to modify the transaction at that specific point in 552time (e.g., intercept the request and set a response on the transaction). 553 554- `request.before_send` has been renamed to `before` and now emits a 555 `GuzzleHttp\Event\BeforeEvent` 556- `request.complete` has been renamed to `complete` and now emits a 557 `GuzzleHttp\Event\CompleteEvent`. 558- `request.sent` has been removed. Use `complete`. 559- `request.success` has been removed. Use `complete`. 560- `error` is now an event that emits a `GuzzleHttp\Event\ErrorEvent`. 561- `request.exception` has been removed. Use `error`. 562- `request.receive.status_line` has been removed. 563- `curl.callback.progress` has been removed. Use a custom `StreamInterface` to 564 maintain a status update. 565- `curl.callback.write` has been removed. Use a custom `StreamInterface` to 566 intercept writes. 567- `curl.callback.read` has been removed. Use a custom `StreamInterface` to 568 intercept reads. 569 570`headers` is a new event that is emitted after the response headers of a 571request have been received before the body of the response is downloaded. This 572event emits a `GuzzleHttp\Event\HeadersEvent`. 573 574You can intercept a request and inject a response using the `intercept()` event 575of a `GuzzleHttp\Event\BeforeEvent`, `GuzzleHttp\Event\CompleteEvent`, and 576`GuzzleHttp\Event\ErrorEvent` event. 577 578See: https://docs.guzzlephp.org/en/latest/events.html 579 580## Inflection 581 582The `Guzzle\Inflection` namespace has been removed. This is not a core concern 583of Guzzle. 584 585## Iterator 586 587The `Guzzle\Iterator` namespace has been removed. 588 589- `Guzzle\Iterator\AppendIterator`, `Guzzle\Iterator\ChunkedIterator`, and 590 `Guzzle\Iterator\MethodProxyIterator` are nice, but not a core requirement of 591 Guzzle itself. 592- `Guzzle\Iterator\FilterIterator` is no longer needed because an equivalent 593 class is shipped with PHP 5.4. 594- `Guzzle\Iterator\MapIterator` is not really needed when using PHP 5.5 because 595 it's easier to just wrap an iterator in a generator that maps values. 596 597For a replacement of these iterators, see https://github.com/nikic/iter 598 599## Log 600 601The LogPlugin has moved to https://github.com/guzzle/log-subscriber. The 602`Guzzle\Log` namespace has been removed. Guzzle now relies on 603`Psr\Log\LoggerInterface` for all logging. The MessageFormatter class has been 604moved to `GuzzleHttp\Subscriber\Log\Formatter`. 605 606## Parser 607 608The `Guzzle\Parser` namespace has been removed. This was previously used to 609make it possible to plug in custom parsers for cookies, messages, URI 610templates, and URLs; however, this level of complexity is not needed in Guzzle 611so it has been removed. 612 613- Cookie: Cookie parsing logic has been moved to 614 `GuzzleHttp\Cookie\SetCookie::fromString`. 615- Message: Message parsing logic for both requests and responses has been moved 616 to `GuzzleHttp\Message\MessageFactory::fromMessage`. Message parsing is only 617 used in debugging or deserializing messages, so it doesn't make sense for 618 Guzzle as a library to add this level of complexity to parsing messages. 619- UriTemplate: URI template parsing has been moved to 620 `GuzzleHttp\UriTemplate`. The Guzzle library will automatically use the PECL 621 URI template library if it is installed. 622- Url: URL parsing is now performed in `GuzzleHttp\Url::fromString` (previously 623 it was `Guzzle\Http\Url::factory()`). If custom URL parsing is necessary, 624 then developers are free to subclass `GuzzleHttp\Url`. 625 626## Plugin 627 628The `Guzzle\Plugin` namespace has been renamed to `GuzzleHttp\Subscriber`. 629Several plugins are shipping with the core Guzzle library under this namespace. 630 631- `GuzzleHttp\Subscriber\Cookie`: Replaces the old CookiePlugin. Cookie jar 632 code has moved to `GuzzleHttp\Cookie`. 633- `GuzzleHttp\Subscriber\History`: Replaces the old HistoryPlugin. 634- `GuzzleHttp\Subscriber\HttpError`: Throws errors when a bad HTTP response is 635 received. 636- `GuzzleHttp\Subscriber\Mock`: Replaces the old MockPlugin. 637- `GuzzleHttp\Subscriber\Prepare`: Prepares the body of a request just before 638 sending. This subscriber is attached to all requests by default. 639- `GuzzleHttp\Subscriber\Redirect`: Replaces the RedirectPlugin. 640 641The following plugins have been removed (third-parties are free to re-implement 642these if needed): 643 644- `GuzzleHttp\Plugin\Async` has been removed. 645- `GuzzleHttp\Plugin\CurlAuth` has been removed. 646- `GuzzleHttp\Plugin\ErrorResponse\ErrorResponsePlugin` has been removed. This 647 functionality should instead be implemented with event listeners that occur 648 after normal response parsing occurs in the guzzle/command package. 649 650The following plugins are not part of the core Guzzle package, but are provided 651in separate repositories: 652 653- `Guzzle\Http\Plugin\BackoffPlugin` has been rewritten to be much simpler 654 to build custom retry policies using simple functions rather than various 655 chained classes. See: https://github.com/guzzle/retry-subscriber 656- `Guzzle\Http\Plugin\Cache\CachePlugin` has moved to 657 https://github.com/guzzle/cache-subscriber 658- `Guzzle\Http\Plugin\Log\LogPlugin` has moved to 659 https://github.com/guzzle/log-subscriber 660- `Guzzle\Http\Plugin\Md5\Md5Plugin` has moved to 661 https://github.com/guzzle/message-integrity-subscriber 662- `Guzzle\Http\Plugin\Mock\MockPlugin` has moved to 663 `GuzzleHttp\Subscriber\MockSubscriber`. 664- `Guzzle\Http\Plugin\Oauth\OauthPlugin` has moved to 665 https://github.com/guzzle/oauth-subscriber 666 667## Service 668 669The service description layer of Guzzle has moved into two separate packages: 670 671- https://github.com/guzzle/command Provides a high level abstraction over web 672 services by representing web service operations using commands. 673- https://github.com/guzzle/guzzle-services Provides an implementation of 674 guzzle/command that provides request serialization and response parsing using 675 Guzzle service descriptions. 676 677## Stream 678 679Stream have moved to a separate package available at 680https://github.com/guzzle/streams. 681 682`Guzzle\Stream\StreamInterface` has been given a large update to cleanly take 683on the responsibilities of `Guzzle\Http\EntityBody` and 684`Guzzle\Http\EntityBodyInterface` now that they have been removed. The number 685of methods implemented by the `StreamInterface` has been drastically reduced to 686allow developers to more easily extend and decorate stream behavior. 687 688## Removed methods from StreamInterface 689 690- `getStream` and `setStream` have been removed to better encapsulate streams. 691- `getMetadata` and `setMetadata` have been removed in favor of 692 `GuzzleHttp\Stream\MetadataStreamInterface`. 693- `getWrapper`, `getWrapperData`, `getStreamType`, and `getUri` have all been 694 removed. This data is accessible when 695 using streams that implement `GuzzleHttp\Stream\MetadataStreamInterface`. 696- `rewind` has been removed. Use `seek(0)` for a similar behavior. 697 698## Renamed methods 699 700- `detachStream` has been renamed to `detach`. 701- `feof` has been renamed to `eof`. 702- `ftell` has been renamed to `tell`. 703- `readLine` has moved from an instance method to a static class method of 704 `GuzzleHttp\Stream\Stream`. 705 706## Metadata streams 707 708`GuzzleHttp\Stream\MetadataStreamInterface` has been added to denote streams 709that contain additional metadata accessible via `getMetadata()`. 710`GuzzleHttp\Stream\StreamInterface::getMetadata` and 711`GuzzleHttp\Stream\StreamInterface::setMetadata` have been removed. 712 713## StreamRequestFactory 714 715The entire concept of the StreamRequestFactory has been removed. The way this 716was used in Guzzle 3 broke the actual interface of sending streaming requests 717(instead of getting back a Response, you got a StreamInterface). Streaming 718PHP requests are now implemented through the `GuzzleHttp\Adapter\StreamAdapter`. 719 7203.6 to 3.7 721---------- 722 723### Deprecations 724 725- You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.: 726 727```php 728\Guzzle\Common\Version::$emitWarnings = true; 729``` 730 731The following APIs and options have been marked as deprecated: 732 733- Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead. 734- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. 735- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. 736- Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead. 737- Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead. 738- Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated 739- Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client. 740- Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8. 741- Marked `Guzzle\Common\Collection::inject()` as deprecated. 742- Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use 743 `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or 744 `$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` 745 7463.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational 747request methods. When paired with a client's configuration settings, these options allow you to specify default settings 748for various aspects of a request. Because these options make other previous configuration options redundant, several 749configuration options and methods of a client and AbstractCommand have been deprecated. 750 751- Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`. 752- Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`. 753- Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')` 754- Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0 755 756 $command = $client->getCommand('foo', array( 757 'command.headers' => array('Test' => '123'), 758 'command.response_body' => '/path/to/file' 759 )); 760 761 // Should be changed to: 762 763 $command = $client->getCommand('foo', array( 764 'command.request_options' => array( 765 'headers' => array('Test' => '123'), 766 'save_as' => '/path/to/file' 767 ) 768 )); 769 770### Interface changes 771 772Additions and changes (you will need to update any implementations or subclasses you may have created): 773 774- Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`: 775 createRequest, head, delete, put, patch, post, options, prepareRequest 776- Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()` 777- Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface` 778- Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to 779 `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a 780 resource, string, or EntityBody into the $options parameter to specify the download location of the response. 781- Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a 782 default `array()` 783- Added `Guzzle\Stream\StreamInterface::isRepeatable` 784- Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods. 785 786The following methods were removed from interfaces. All of these methods are still available in the concrete classes 787that implement them, but you should update your code to use alternative methods: 788 789- Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use 790 `$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or 791 `$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or 792 `$client->setDefaultOption('headers/{header_name}', 'value')`. or 793 `$client->setDefaultOption('headers', array('header_name' => 'value'))`. 794- Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`. 795- Removed `Guzzle\Http\ClientInterface::expandTemplate()`. This is an implementation detail. 796- Removed `Guzzle\Http\ClientInterface::setRequestFactory()`. This is an implementation detail. 797- Removed `Guzzle\Http\ClientInterface::getCurlMulti()`. This is a very specific implementation detail. 798- Removed `Guzzle\Http\Message\RequestInterface::canCache`. Use the CachePlugin. 799- Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`. Use the HistoryPlugin. 800- Removed `Guzzle\Http\Message\RequestInterface::isRedirect`. Use the HistoryPlugin. 801 802### Cache plugin breaking changes 803 804- CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a 805 CacheStorageInterface. These two objects and interface will be removed in a future version. 806- Always setting X-cache headers on cached responses 807- Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin 808- `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface 809 $request, Response $response);` 810- `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);` 811- `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);` 812- Added `CacheStorageInterface::purge($url)` 813- `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin 814 $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache, 815 CanCacheStrategyInterface $canCache = null)` 816- Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)` 817 8183.5 to 3.6 819---------- 820 821* Mixed casing of headers are now forced to be a single consistent casing across all values for that header. 822* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution 823* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader(). 824 For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader(). 825 Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request. 826* Specific header implementations can be created for complex headers. When a message creates a header, it uses a 827 HeaderFactory which can map specific headers to specific header classes. There is now a Link header and 828 CacheControl header implementation. 829* Moved getLinks() from Response to just be used on a Link header object. 830 831If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the 832HeaderInterface (e.g. toArray(), getAll(), etc.). 833 834### Interface changes 835 836* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate 837* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti() 838* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in 839 Guzzle\Http\Curl\RequestMediator 840* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string. 841* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface 842* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders() 843 844### Removed deprecated functions 845 846* Removed Guzzle\Parser\ParserRegister::get(). Use getParser() 847* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser(). 848 849### Deprecations 850 851* The ability to case-insensitively search for header values 852* Guzzle\Http\Message\Header::hasExactHeader 853* Guzzle\Http\Message\Header::raw. Use getAll() 854* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object 855 instead. 856 857### Other changes 858 859* All response header helper functions return a string rather than mixing Header objects and strings inconsistently 860* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle 861 directly via interfaces 862* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist 863 but are a no-op until removed. 864* Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a 865 `Guzzle\Service\Command\ArrayCommandInterface`. 866* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response 867 on a request while the request is still being transferred 868* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess 869 8703.3 to 3.4 871---------- 872 873Base URLs of a client now follow the rules of https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2 when merging URLs. 874 8753.2 to 3.3 876---------- 877 878### Response::getEtag() quote stripping removed 879 880`Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header 881 882### Removed `Guzzle\Http\Utils` 883 884The `Guzzle\Http\Utils` class was removed. This class was only used for testing. 885 886### Stream wrapper and type 887 888`Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getStreamType()` are no longer converted to lowercase. 889 890### curl.emit_io became emit_io 891 892Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the 893'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io' 894 8953.1 to 3.2 896---------- 897 898### CurlMulti is no longer reused globally 899 900Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added 901to a single client can pollute requests dispatched from other clients. 902 903If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the 904ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is 905created. 906 907```php 908$multi = new Guzzle\Http\Curl\CurlMulti(); 909$builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json'); 910$builder->addListener('service_builder.create_client', function ($event) use ($multi) { 911 $event['client']->setCurlMulti($multi); 912} 913}); 914``` 915 916### No default path 917 918URLs no longer have a default path value of '/' if no path was specified. 919 920Before: 921 922```php 923$request = $client->get('http://www.foo.com'); 924echo $request->getUrl(); 925// >> http://www.foo.com/ 926``` 927 928After: 929 930```php 931$request = $client->get('http://www.foo.com'); 932echo $request->getUrl(); 933// >> http://www.foo.com 934``` 935 936### Less verbose BadResponseException 937 938The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and 939response information. You can, however, get access to the request and response object by calling `getRequest()` or 940`getResponse()` on the exception object. 941 942### Query parameter aggregation 943 944Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a 945setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is 946responsible for handling the aggregation of multi-valued query string variables into a flattened hash. 947 9482.8 to 3.x 949---------- 950 951### Guzzle\Service\Inspector 952 953Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig` 954 955**Before** 956 957```php 958use Guzzle\Service\Inspector; 959 960class YourClient extends \Guzzle\Service\Client 961{ 962 public static function factory($config = array()) 963 { 964 $default = array(); 965 $required = array('base_url', 'username', 'api_key'); 966 $config = Inspector::fromConfig($config, $default, $required); 967 968 $client = new self( 969 $config->get('base_url'), 970 $config->get('username'), 971 $config->get('api_key') 972 ); 973 $client->setConfig($config); 974 975 $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json')); 976 977 return $client; 978 } 979``` 980 981**After** 982 983```php 984use Guzzle\Common\Collection; 985 986class YourClient extends \Guzzle\Service\Client 987{ 988 public static function factory($config = array()) 989 { 990 $default = array(); 991 $required = array('base_url', 'username', 'api_key'); 992 $config = Collection::fromConfig($config, $default, $required); 993 994 $client = new self( 995 $config->get('base_url'), 996 $config->get('username'), 997 $config->get('api_key') 998 ); 999 $client->setConfig($config); 1000 1001 $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json')); 1002 1003 return $client; 1004 } 1005``` 1006 1007### Convert XML Service Descriptions to JSON 1008 1009**Before** 1010 1011```xml 1012<?xml version="1.0" encoding="UTF-8"?> 1013<client> 1014 <commands> 1015 <!-- Groups --> 1016 <command name="list_groups" method="GET" uri="groups.json"> 1017 <doc>Get a list of groups</doc> 1018 </command> 1019 <command name="search_groups" method="GET" uri='search.json?query="{{query}} type:group"'> 1020 <doc>Uses a search query to get a list of groups</doc> 1021 <param name="query" type="string" required="true" /> 1022 </command> 1023 <command name="create_group" method="POST" uri="groups.json"> 1024 <doc>Create a group</doc> 1025 <param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/> 1026 <param name="Content-Type" location="header" static="application/json"/> 1027 </command> 1028 <command name="delete_group" method="DELETE" uri="groups/{{id}}.json"> 1029 <doc>Delete a group by ID</doc> 1030 <param name="id" type="integer" required="true"/> 1031 </command> 1032 <command name="get_group" method="GET" uri="groups/{{id}}.json"> 1033 <param name="id" type="integer" required="true"/> 1034 </command> 1035 <command name="update_group" method="PUT" uri="groups/{{id}}.json"> 1036 <doc>Update a group</doc> 1037 <param name="id" type="integer" required="true"/> 1038 <param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/> 1039 <param name="Content-Type" location="header" static="application/json"/> 1040 </command> 1041 </commands> 1042</client> 1043``` 1044 1045**After** 1046 1047```json 1048{ 1049 "name": "Zendesk REST API v2", 1050 "apiVersion": "2012-12-31", 1051 "description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users", 1052 "operations": { 1053 "list_groups": { 1054 "httpMethod":"GET", 1055 "uri": "groups.json", 1056 "summary": "Get a list of groups" 1057 }, 1058 "search_groups":{ 1059 "httpMethod":"GET", 1060 "uri": "search.json?query=\"{query} type:group\"", 1061 "summary": "Uses a search query to get a list of groups", 1062 "parameters":{ 1063 "query":{ 1064 "location": "uri", 1065 "description":"Zendesk Search Query", 1066 "type": "string", 1067 "required": true 1068 } 1069 } 1070 }, 1071 "create_group": { 1072 "httpMethod":"POST", 1073 "uri": "groups.json", 1074 "summary": "Create a group", 1075 "parameters":{ 1076 "data": { 1077 "type": "array", 1078 "location": "body", 1079 "description":"Group JSON", 1080 "filters": "json_encode", 1081 "required": true 1082 }, 1083 "Content-Type":{ 1084 "type": "string", 1085 "location":"header", 1086 "static": "application/json" 1087 } 1088 } 1089 }, 1090 "delete_group": { 1091 "httpMethod":"DELETE", 1092 "uri": "groups/{id}.json", 1093 "summary": "Delete a group", 1094 "parameters":{ 1095 "id":{ 1096 "location": "uri", 1097 "description":"Group to delete by ID", 1098 "type": "integer", 1099 "required": true 1100 } 1101 } 1102 }, 1103 "get_group": { 1104 "httpMethod":"GET", 1105 "uri": "groups/{id}.json", 1106 "summary": "Get a ticket", 1107 "parameters":{ 1108 "id":{ 1109 "location": "uri", 1110 "description":"Group to get by ID", 1111 "type": "integer", 1112 "required": true 1113 } 1114 } 1115 }, 1116 "update_group": { 1117 "httpMethod":"PUT", 1118 "uri": "groups/{id}.json", 1119 "summary": "Update a group", 1120 "parameters":{ 1121 "id": { 1122 "location": "uri", 1123 "description":"Group to update by ID", 1124 "type": "integer", 1125 "required": true 1126 }, 1127 "data": { 1128 "type": "array", 1129 "location": "body", 1130 "description":"Group JSON", 1131 "filters": "json_encode", 1132 "required": true 1133 }, 1134 "Content-Type":{ 1135 "type": "string", 1136 "location":"header", 1137 "static": "application/json" 1138 } 1139 } 1140 } 1141} 1142``` 1143 1144### Guzzle\Service\Description\ServiceDescription 1145 1146Commands are now called Operations 1147 1148**Before** 1149 1150```php 1151use Guzzle\Service\Description\ServiceDescription; 1152 1153$sd = new ServiceDescription(); 1154$sd->getCommands(); // @returns ApiCommandInterface[] 1155$sd->hasCommand($name); 1156$sd->getCommand($name); // @returns ApiCommandInterface|null 1157$sd->addCommand($command); // @param ApiCommandInterface $command 1158``` 1159 1160**After** 1161 1162```php 1163use Guzzle\Service\Description\ServiceDescription; 1164 1165$sd = new ServiceDescription(); 1166$sd->getOperations(); // @returns OperationInterface[] 1167$sd->hasOperation($name); 1168$sd->getOperation($name); // @returns OperationInterface|null 1169$sd->addOperation($operation); // @param OperationInterface $operation 1170``` 1171 1172### Guzzle\Common\Inflection\Inflector 1173 1174Namespace is now `Guzzle\Inflection\Inflector` 1175 1176### Guzzle\Http\Plugin 1177 1178Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below. 1179 1180### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log 1181 1182Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively. 1183 1184**Before** 1185 1186```php 1187use Guzzle\Common\Log\ClosureLogAdapter; 1188use Guzzle\Http\Plugin\LogPlugin; 1189 1190/** @var \Guzzle\Http\Client */ 1191$client; 1192 1193// $verbosity is an integer indicating desired message verbosity level 1194$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE); 1195``` 1196 1197**After** 1198 1199```php 1200use Guzzle\Log\ClosureLogAdapter; 1201use Guzzle\Log\MessageFormatter; 1202use Guzzle\Plugin\Log\LogPlugin; 1203 1204/** @var \Guzzle\Http\Client */ 1205$client; 1206 1207// $format is a string indicating desired message format -- @see MessageFormatter 1208$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT); 1209``` 1210 1211### Guzzle\Http\Plugin\CurlAuthPlugin 1212 1213Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`. 1214 1215### Guzzle\Http\Plugin\ExponentialBackoffPlugin 1216 1217Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes. 1218 1219**Before** 1220 1221```php 1222use Guzzle\Http\Plugin\ExponentialBackoffPlugin; 1223 1224$backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge( 1225 ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429) 1226 )); 1227 1228$client->addSubscriber($backoffPlugin); 1229``` 1230 1231**After** 1232 1233```php 1234use Guzzle\Plugin\Backoff\BackoffPlugin; 1235use Guzzle\Plugin\Backoff\HttpBackoffStrategy; 1236 1237// Use convenient factory method instead -- see implementation for ideas of what 1238// you can do with chaining backoff strategies 1239$backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge( 1240 HttpBackoffStrategy::getDefaultFailureCodes(), array(429) 1241 )); 1242$client->addSubscriber($backoffPlugin); 1243``` 1244 1245### Known Issues 1246 1247#### [BUG] Accept-Encoding header behavior changed unintentionally. 1248 1249(See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e) 1250 1251In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to 1252properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen. 1253See issue #217 for a workaround, or use a version containing the fix. 1254