mantis-matrix-integration – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 [here](https://github.com/guzzle/guzzle/compare/6.5.4..master). |
||
53 | |||
54 | 5.0 to 6.0 |
||
55 | ---------- |
||
56 | |||
57 | Guzzle now uses [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 [`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 | [`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 [RingPHP](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 | [Fluent interfaces were removed](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. |