src
7 months ago
CHANGELOG.md
7 months ago
LICENSE
2 years ago
README.md
7 months ago
UPGRADING.md
7 months ago
composer.json
7 months ago
package-lock.json
7 months ago
UPGRADING.md
1254 lines
| 1 | Guzzle Upgrade Guide |
| 2 | ==================== |
| 3 | |
| 4 | 6.0 to 7.0 |
| 5 | ---------- |
| 6 | |
| 7 | In order to take advantage of the new features of PHP, Guzzle dropped the support |
| 8 | of PHP 5. The minimum supported PHP version is now PHP 7.2. Type hints and return |
| 9 | types for functions and methods have been added wherever possible. |
| 10 | |
| 11 | Please 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 | |
| 40 | All internal native functions calls of Guzzle are now prefixed with a slash. This |
| 41 | change makes it impossible for method overloading by other libraries or applications. |
| 42 | Example: |
| 43 | |
| 44 | ```php |
| 45 | // Before: |
| 46 | curl_version(); |
| 47 | |
| 48 | // After: |
| 49 | \curl_version(); |
| 50 | ``` |
| 51 | |
| 52 | For the full diff you can check [](https://github.com/guzzle/guzzle/compare/6.5.4..masterhere](https://github.com/guzzle/guzzle/compare/6.5.4..master](https://github.com/guzzle/guzzle/compare/6.5.4..master). |
| 53 | |
| 54 | 5.0 to 6.0 |
| 55 | ---------- |
| 56 | |
| 57 | Guzzle now uses [](https://www.php-fig.org/psr/psr-7/PSR-7](https://www.php-fig.org/psr/psr-7/](https://www.php-fig.org/psr/psr-7/) for HTTP messages. |
| 58 | Due to the fact that these messages are immutable, this prompted a refactoring |
| 59 | of Guzzle to use a middleware based system rather than an event system. Any |
| 60 | HTTP message interaction (e.g., `GuzzleHttp\Message\Request`) need to be |
| 61 | updated to work with the new immutable PSR-7 request and response objects. Any |
| 62 | event listeners or subscribers need to be updated to become middleware |
| 63 | functions 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 | |
| 143 | The change to PSR-7 unfortunately required significant refactoring to Guzzle |
| 144 | due to the fact that PSR-7 messages are immutable. Guzzle 5 relied on an event |
| 145 | system from plugins. The event system relied on mutability of HTTP messages and |
| 146 | side effects in order to work. With immutable messages, you have to change your |
| 147 | workflow to become more about either returning a value (e.g., functional |
| 148 | middlewares) or setting a value on an object. Guzzle v6 has chosen the |
| 149 | functional middleware approach. |
| 150 | |
| 151 | Instead of using the event system to listen for things like the `before` event, |
| 152 | you now create a stack based middleware function that intercepts a request on |
| 153 | the way in and the promise of the response on the way out. This is a much |
| 154 | simpler and more predictable approach than the event system and works nicely |
| 155 | with PSR-7 middleware. Due to the use of promises, the middleware system is |
| 156 | also asynchronous. |
| 157 | |
| 158 | v5: |
| 159 | |
| 160 | ```php |
| 161 | use 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 | |
| 170 | v6: |
| 171 | |
| 172 | In v6, you can modify the request before it is sent using the `mapRequest` |
| 173 | middleware. The idiomatic way in v6 to modify the request/response lifecycle is |
| 174 | to setup a handler middleware stack up front and inject the handler into a |
| 175 | client. |
| 176 | |
| 177 | ```php |
| 178 | use 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 | |
| 192 | This version added the [](https://docs.guzzlephp.org/en/latest/request-options.html#form_params`form_params`](https://docs.guzzlephp.org/en/latest/request-options.html#form_params](https://docs.guzzlephp.org/en/latest/request-options.html#form_params) |
| 193 | and `multipart` request options. `form_params` is an associative array of |
| 194 | strings or array of strings and is used to serialize an |
| 195 | `application/x-www-form-urlencoded` POST request. The |
| 196 | [](https://docs.guzzlephp.org/en/latest/request-options.html#multipart`multipart`](https://docs.guzzlephp.org/en/latest/request-options.html#multipart](https://docs.guzzlephp.org/en/latest/request-options.html#multipart) |
| 197 | option 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 |
| 200 | POST files to a multipart/form-data request. |
| 201 | |
| 202 | The `body` option no longer accepts an array to send POST requests. Please use |
| 203 | `multipart` or `form_params` instead. |
| 204 | |
| 205 | The `base_url` option has been renamed to `base_uri`. |
| 206 | |
| 207 | 4.x to 5.0 |
| 208 | ---------- |
| 209 | |
| 210 | ## Rewritten Adapter Layer |
| 211 | |
| 212 | Guzzle now uses [](https://ringphp.readthedocs.org/en/latestRingPHP](https://ringphp.readthedocs.org/en/latest](https://ringphp.readthedocs.org/en/latest) to send |
| 213 | HTTP requests. The `adapter` option in a `GuzzleHttp\Client` constructor |
| 214 | is still supported, but it has now been renamed to `handler`. Instead of |
| 215 | passing a `GuzzleHttp\Adapter\AdapterInterface`, you must now pass a PHP |
| 216 | `callable` that follows the RingPHP specification. |
| 217 | |
| 218 | ## Removed Fluent Interfaces |
| 219 | |
| 220 | [](https://ocramius.github.io/blog/fluent-interfaces-are-evil/Fluent interfaces were removed](https://ocramius.github.io/blog/fluent-interfaces-are-evil/](https://ocramius.github.io/blog/fluent-interfaces-are-evil/) |
| 221 | from 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 | |
| 231 | Removed "functions.php", so that Guzzle is truly PSR-4 compliant. The following |
| 232 | functions 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 | |
| 240 | The "procedural" global client has been removed with no replacement (e.g., |
| 241 | `GuzzleHttp\get()`, `GuzzleHttp\post()`, etc.). Use a `GuzzleHttp\Client` |
| 242 | object as a replacement. |
| 243 | |
| 244 | ## `throwImmediately` has been removed |
| 245 | |
| 246 | The concept of "throwImmediately" has been removed from exceptions and error |
| 247 | events. This control mechanism was used to stop a transfer of concurrent |
| 248 | requests from completing. This can now be handled by throwing the exception or |
| 249 | by cancelling a pool of requests or each outstanding future request |
| 250 | individually. |
| 251 | |
| 252 | ## headers event has been removed |
| 253 | |
| 254 | Removed the "headers" event. This event was only useful for changing the |
| 255 | body a response once the headers of the response were known. You can implement |
| 256 | a similar behavior in a number of ways. One example might be to use a |
| 257 | FnStream that has access to the transaction being sent. For example, when the |
| 258 | first byte is written, you could check if the response headers match your |
| 259 | expectations, and if so, change the actual stream body that is being |
| 260 | written to. |
| 261 | |
| 262 | ## Updates to HTTP Messages |
| 263 | |
| 264 | Removed the `asArray` parameter from |
| 265 | `GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header |
| 266 | value as an array, then use the newly added `getHeaderAsArray()` method of |
| 267 | `MessageInterface`. This change makes the Guzzle interfaces compatible with |
| 268 | the PSR-7 interfaces. |
| 269 | |
| 270 | 3.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 | |
| 285 | Changes per Guzzle 3.x namespace are described below. |
| 286 | |
| 287 | ## Batch |
| 288 | |
| 289 | The `Guzzle\Batch` namespace has been removed. This is best left to |
| 290 | third-parties to implement on top of Guzzle's core HTTP library. |
| 291 | |
| 292 | ## Cache |
| 293 | |
| 294 | The `Guzzle\Cache` namespace has been removed. (Todo: No suitable replacement |
| 295 | has 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 | |
| 316 | Guzzle 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 | |
| 351 | Use 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 | |
| 382 | Calling methods like `get()`, `post()`, `head()`, etc. no longer create and |
| 383 | return a request, but rather creates a request, sends the request, and returns |
| 384 | the 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 | |
| 425 | Messages no longer have references to their counterparts (i.e., a request no |
| 426 | longer has a reference to it's response, and a response no loger has a |
| 427 | reference to its request). This association is now managed through a |
| 428 | `GuzzleHttp\Adapter\TransactionInterface` object. You can get references to |
| 429 | these transaction objects using request events that are emitted over the |
| 430 | lifecycle 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 | |
| 495 | Streaming requests can now be created by a client directly, returning a |
| 496 | `GuzzleHttp\Message\ResponseInterface` object that contains a body stream |
| 497 | referencing an open PHP HTTP stream. |
| 498 | |
| 499 | ```php |
| 500 | // 3.0 |
| 501 | use 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 | |
| 515 | The `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 | |
| 530 | EntityBody 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 |
| 534 | longer 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 | |
| 546 | Requests previously submitted a large number of requests. The number of events |
| 547 | emitted over the lifecycle of a request has been significantly reduced to make |
| 548 | it easier to understand how to extend the behavior of a request. All events |
| 549 | emitted during the lifecycle of a request now emit a custom |
| 550 | `GuzzleHttp\Event\EventInterface` object that contains context providing |
| 551 | methods and a way in which to modify the transaction at that specific point in |
| 552 | time (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 |
| 571 | request have been received before the body of the response is downloaded. This |
| 572 | event emits a `GuzzleHttp\Event\HeadersEvent`. |
| 573 | |
| 574 | You can intercept a request and inject a response using the `intercept()` event |
| 575 | of a `GuzzleHttp\Event\BeforeEvent`, `GuzzleHttp\Event\CompleteEvent`, and |
| 576 | `GuzzleHttp\Event\ErrorEvent` event. |
| 577 | |
| 578 | See: https://docs.guzzlephp.org/en/latest/events.html |
| 579 | |
| 580 | ## Inflection |
| 581 | |
| 582 | The `Guzzle\Inflection` namespace has been removed. This is not a core concern |
| 583 | of Guzzle. |
| 584 | |
| 585 | ## Iterator |
| 586 | |
| 587 | The `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 | |
| 597 | For a replacement of these iterators, see https://github.com/nikic/iter |
| 598 | |
| 599 | ## Log |
| 600 | |
| 601 | The 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 |
| 604 | moved to `GuzzleHttp\Subscriber\Log\Formatter`. |
| 605 | |
| 606 | ## Parser |
| 607 | |
| 608 | The `Guzzle\Parser` namespace has been removed. This was previously used to |
| 609 | make it possible to plug in custom parsers for cookies, messages, URI |
| 610 | templates, and URLs; however, this level of complexity is not needed in Guzzle |
| 611 | so 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 | |
| 628 | The `Guzzle\Plugin` namespace has been renamed to `GuzzleHttp\Subscriber`. |
| 629 | Several 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 | |
| 641 | The following plugins have been removed (third-parties are free to re-implement |
| 642 | these 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 | |
| 650 | The following plugins are not part of the core Guzzle package, but are provided |
| 651 | in 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 | |
| 669 | The 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 | |
| 679 | Stream have moved to a separate package available at |
| 680 | https://github.com/guzzle/streams. |
| 681 | |
| 682 | `Guzzle\Stream\StreamInterface` has been given a large update to cleanly take |
| 683 | on the responsibilities of `Guzzle\Http\EntityBody` and |
| 684 | `Guzzle\Http\EntityBodyInterface` now that they have been removed. The number |
| 685 | of methods implemented by the `StreamInterface` has been drastically reduced to |
| 686 | allow 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 |
| 709 | that contain additional metadata accessible via `getMetadata()`. |
| 710 | `GuzzleHttp\Stream\StreamInterface::getMetadata` and |
| 711 | `GuzzleHttp\Stream\StreamInterface::setMetadata` have been removed. |
| 712 | |
| 713 | ## StreamRequestFactory |
| 714 | |
| 715 | The entire concept of the StreamRequestFactory has been removed. The way this |
| 716 | was used in Guzzle 3 broke the actual interface of sending streaming requests |
| 717 | (instead of getting back a Response, you got a StreamInterface). Streaming |
| 718 | PHP requests are now implemented through the `GuzzleHttp\Adapter\StreamAdapter`. |
| 719 | |
| 720 | 3.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 | |
| 731 | The 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 | |
| 746 | 3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational |
| 747 | request methods. When paired with a client's configuration settings, these options allow you to specify default settings |
| 748 | for various aspects of a request. Because these options make other previous configuration options redundant, several |
| 749 | configuration 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 | |
| 772 | Additions 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 | |
| 786 | The following methods were removed from interfaces. All of these methods are still available in the concrete classes |
| 787 | that 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 | |
| 818 | 3.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 | |
| 831 | If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the |
| 832 | HeaderInterface (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 | |
| 870 | 3.3 to 3.4 |
| 871 | ---------- |
| 872 | |
| 873 | Base URLs of a client now follow the rules of https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2 when merging URLs. |
| 874 | |
| 875 | 3.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 | |
| 884 | The `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 | |
| 892 | Emitting 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 | |
| 895 | 3.1 to 3.2 |
| 896 | ---------- |
| 897 | |
| 898 | ### CurlMulti is no longer reused globally |
| 899 | |
| 900 | Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added |
| 901 | to a single client can pollute requests dispatched from other clients. |
| 902 | |
| 903 | If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the |
| 904 | ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is |
| 905 | created. |
| 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 | |
| 918 | URLs no longer have a default path value of '/' if no path was specified. |
| 919 | |
| 920 | Before: |
| 921 | |
| 922 | ```php |
| 923 | $request = $client->get('http://www.foo.com'); |
| 924 | echo $request->getUrl(); |
| 925 | // >> http://www.foo.com/ |
| 926 | ``` |
| 927 | |
| 928 | After: |
| 929 | |
| 930 | ```php |
| 931 | $request = $client->get('http://www.foo.com'); |
| 932 | echo $request->getUrl(); |
| 933 | // >> http://www.foo.com |
| 934 | ``` |
| 935 | |
| 936 | ### Less verbose BadResponseException |
| 937 | |
| 938 | The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and |
| 939 | response 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 | |
| 944 | Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a |
| 945 | setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is |
| 946 | responsible for handling the aggregation of multi-valued query string variables into a flattened hash. |
| 947 | |
| 948 | 2.8 to 3.x |
| 949 | ---------- |
| 950 | |
| 951 | ### Guzzle\Service\Inspector |
| 952 | |
| 953 | Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig` |
| 954 | |
| 955 | **Before** |
| 956 | |
| 957 | ```php |
| 958 | use Guzzle\Service\Inspector; |
| 959 | |
| 960 | class 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 |
| 984 | use Guzzle\Common\Collection; |
| 985 | |
| 986 | class 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 | |
| 1146 | Commands are now called Operations |
| 1147 | |
| 1148 | **Before** |
| 1149 | |
| 1150 | ```php |
| 1151 | use 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 |
| 1163 | use 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 | |
| 1174 | Namespace is now `Guzzle\Inflection\Inflector` |
| 1175 | |
| 1176 | ### Guzzle\Http\Plugin |
| 1177 | |
| 1178 | Namespace 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 | |
| 1182 | Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively. |
| 1183 | |
| 1184 | **Before** |
| 1185 | |
| 1186 | ```php |
| 1187 | use Guzzle\Common\Log\ClosureLogAdapter; |
| 1188 | use 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 |
| 1200 | use Guzzle\Log\ClosureLogAdapter; |
| 1201 | use Guzzle\Log\MessageFormatter; |
| 1202 | use 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 | |
| 1213 | Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`. |
| 1214 | |
| 1215 | ### Guzzle\Http\Plugin\ExponentialBackoffPlugin |
| 1216 | |
| 1217 | Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes. |
| 1218 | |
| 1219 | **Before** |
| 1220 | |
| 1221 | ```php |
| 1222 | use 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 |
| 1234 | use Guzzle\Plugin\Backoff\BackoffPlugin; |
| 1235 | use 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 | |
| 1251 | In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to |
| 1252 | properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen. |
| 1253 | See issue #217 for a workaround, or use a version containing the fix. |
| 1254 |