From edfb9f48e1f7a72d19204819045edf20ccf88dd2 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Mon, 8 Dec 2025 18:31:32 -0500 Subject: [PATCH 1/2] request-context --- src/Illuminate/Http/Client/PendingRequest.php | 49 ++++++++++++++++--- src/Illuminate/Http/Client/Request.php | 30 ++++++++++++ tests/Integration/Http/HttpClientTest.php | 22 +++++++++ 3 files changed, 94 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index dcab5cb387c1..f09e8086946e 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -209,6 +209,13 @@ class PendingRequest */ protected $request; + /** + * The context to track with the request. + * + * @var array + */ + protected $requestContext = []; + /** * The Guzzle request options that are mergeable via array_merge_recursive. * @@ -439,6 +446,19 @@ public function withHeader($name, $value) return $this->withHeaders([$name => $value]); } + /** + * Set context to store with the request. + * + * @param array $context + * @return $this + */ + public function withRequestContext($context) + { + $this->requestContext = array_merge_recursive($this->requestContext, $context); + + return $this; + } + /** * Replace the given headers on the request. * @@ -1123,7 +1143,10 @@ protected function makePromise(string $method, string $url, array $options = [], if ($e instanceof ConnectException || ($e instanceof RequestException && ! $e->hasResponse())) { $exception = new ConnectionException($e->getMessage(), 0, $e); - $this->dispatchConnectionFailedEvent(new Request($e->getRequest()), $exception); + $this->dispatchConnectionFailedEvent( + (new Request($e->getRequest()))->setRequestContext($this->requestContext), + $exception + ); return $exception; } @@ -1399,7 +1422,9 @@ public function buildRecorderHandler() return $promise->then(function ($response) use ($request, $options) { $this->factory?->recordRequestResponsePair( - (new Request($request))->withData($options['laravel_data']), + (new Request($request)) + ->withData($options['laravel_data']) + ->setRequestContext($this->requestContext), $this->newResponse($response) ); @@ -1420,7 +1445,12 @@ public function buildStubHandler() return function ($request, $options) use ($handler) { $response = ($this->stubCallbacks ?? new Collection) ->map - ->__invoke((new Request($request))->withData($options['laravel_data']), $options) + ->__invoke( + (new Request($request)) + ->withData($options['laravel_data']) + ->setRequestContext($this->requestContext), + $options + ) ->filter() ->first(); @@ -1479,7 +1509,12 @@ public function runBeforeSendingCallbacks($request, array $options) return tap($request, function (&$request) use ($options) { $this->beforeSendingCallbacks->each(function ($callback) use (&$request, $options) { $callbackResult = call_user_func( - $callback, (new Request($request))->withData($options['laravel_data']), $options, $this + $callback, + (new Request($request)) + ->withData($options['laravel_data']) + ->setRequestContext($this->requestContext), + $options, + $this ); if ($callbackResult instanceof RequestInterface) { @@ -1683,7 +1718,7 @@ protected function marshalConnectionException(ConnectException $e) { $exception = new ConnectionException($e->getMessage(), 0, $e); - $request = new Request($e->getRequest()); + $request = (new Request($e->getRequest()))->setRequestContext($this->requestContext); $this->factory?->recordRequestResponsePair( $request, null @@ -1704,7 +1739,7 @@ protected function marshalRequestExceptionWithoutResponse(RequestException $e) { $exception = new ConnectionException($e->getMessage(), 0, $e); - $request = new Request($e->getRequest()); + $request = (new Request($e->getRequest()))->setRequestContext($this->requestContext); $this->factory?->recordRequestResponsePair( $request, null @@ -1726,7 +1761,7 @@ protected function marshalRequestExceptionWithResponse(RequestException $e) $response = $this->populateResponse($this->newResponse($e->getResponse())); $this->factory?->recordRequestResponsePair( - new Request($e->getRequest()), + (new Request($e->getRequest()))->setRequestContext($this->requestContext), $response ); diff --git a/src/Illuminate/Http/Client/Request.php b/src/Illuminate/Http/Client/Request.php index 7e6891221864..3c8346a6fdfe 100644 --- a/src/Illuminate/Http/Client/Request.php +++ b/src/Illuminate/Http/Client/Request.php @@ -26,6 +26,13 @@ class Request implements ArrayAccess */ protected $data; + /** + * The contextual data passed when building the PendingRequest. + * + * @var array + */ + protected $requestContext = []; + /** * Create a new request instance. * @@ -244,6 +251,29 @@ public function withData(array $data) return $this; } + /** + * Set the request's context data. + * + * @param array $context + * @return $this + */ + public function setRequestContext($context) + { + $this->requestContext = $context; + + return $this; + } + + /** + * Get the contextual data from the request. + * + * @return array + */ + public function requestContext() + { + return $this->requestContext; + } + /** * Get the underlying PSR compliant request instance. * diff --git a/tests/Integration/Http/HttpClientTest.php b/tests/Integration/Http/HttpClientTest.php index 7ff6719b6535..8ef64d2b9c6d 100644 --- a/tests/Integration/Http/HttpClientTest.php +++ b/tests/Integration/Http/HttpClientTest.php @@ -4,6 +4,7 @@ use Illuminate\Http\Client\Events\RequestSending; use Illuminate\Http\Client\Pool; +use Illuminate\Http\Client\Request; use Illuminate\Http\Client\Response; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Event; @@ -87,4 +88,25 @@ public function testForwardsCallsToPromise() $this->assertEquals('faked response', $myFakedResponse); $this->assertEquals('stub', $r); } + + public function testCanSetRequestContext() + { + Http::fake([ + '*' => fn (Request $request) => match($request->requestContext()['name'] ?? null) { + 'first' => Http::response('first response'), + 'second' => Http::response('second response'), + default => Http::response('unnamed') + } + ]); + + $response1 = Http::withRequestContext(['name' => 'first'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); + $response2 = Http::withRequestContext(['name' => 'second'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); + $response3 = Http::get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); + $response4 = Http::withRequestContext(['name' => 'fourth'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); + + $this->assertEquals('first response', $response1->body()); + $this->assertEquals('second response', $response2->body()); + $this->assertEquals('unnamed', $response3->body()); + $this->assertEquals('unnamed', $response4->body()); + } } From 284ffd3805a96999f545dd2654ff199f65ea8da5 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 9 Dec 2025 09:22:08 -0600 Subject: [PATCH 2/2] formatting --- src/Illuminate/Http/Client/PendingRequest.php | 54 +++++++++---------- src/Illuminate/Http/Client/Request.php | 26 ++++----- tests/Integration/Http/HttpClientTest.php | 10 ++-- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index f09e8086946e..034d0213de44 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -195,6 +195,13 @@ class PendingRequest */ protected $async = false; + /** + * The attributes to track with the request. + * + * @var array + */ + protected $attributes = []; + /** * The pending request promise. * @@ -209,13 +216,6 @@ class PendingRequest */ protected $request; - /** - * The context to track with the request. - * - * @var array - */ - protected $requestContext = []; - /** * The Guzzle request options that are mergeable via array_merge_recursive. * @@ -446,19 +446,6 @@ public function withHeader($name, $value) return $this->withHeaders([$name => $value]); } - /** - * Set context to store with the request. - * - * @param array $context - * @return $this - */ - public function withRequestContext($context) - { - $this->requestContext = array_merge_recursive($this->requestContext, $context); - - return $this; - } - /** * Replace the given headers on the request. * @@ -720,6 +707,19 @@ public function withResponseMiddleware(callable $middleware) return $this; } + /** + * Set arbitrary attributes to store with the request. + * + * @param array $attributes + * @return $this + */ + public function withAttributes($attributes) + { + $this->attributes = array_merge_recursive($this->attributes, $attributes); + + return $this; + } + /** * Add a new "before sending" callback to the request. * @@ -1144,7 +1144,7 @@ protected function makePromise(string $method, string $url, array $options = [], $exception = new ConnectionException($e->getMessage(), 0, $e); $this->dispatchConnectionFailedEvent( - (new Request($e->getRequest()))->setRequestContext($this->requestContext), + (new Request($e->getRequest()))->setRequestAttributes($this->attributes), $exception ); @@ -1424,7 +1424,7 @@ public function buildRecorderHandler() $this->factory?->recordRequestResponsePair( (new Request($request)) ->withData($options['laravel_data']) - ->setRequestContext($this->requestContext), + ->setRequestAttributes($this->attributes), $this->newResponse($response) ); @@ -1448,7 +1448,7 @@ public function buildStubHandler() ->__invoke( (new Request($request)) ->withData($options['laravel_data']) - ->setRequestContext($this->requestContext), + ->setRequestAttributes($this->attributes), $options ) ->filter() @@ -1512,7 +1512,7 @@ public function runBeforeSendingCallbacks($request, array $options) $callback, (new Request($request)) ->withData($options['laravel_data']) - ->setRequestContext($this->requestContext), + ->setRequestAttributes($this->attributes), $options, $this ); @@ -1718,7 +1718,7 @@ protected function marshalConnectionException(ConnectException $e) { $exception = new ConnectionException($e->getMessage(), 0, $e); - $request = (new Request($e->getRequest()))->setRequestContext($this->requestContext); + $request = (new Request($e->getRequest()))->setRequestAttributes($this->attributes); $this->factory?->recordRequestResponsePair( $request, null @@ -1739,7 +1739,7 @@ protected function marshalRequestExceptionWithoutResponse(RequestException $e) { $exception = new ConnectionException($e->getMessage(), 0, $e); - $request = (new Request($e->getRequest()))->setRequestContext($this->requestContext); + $request = (new Request($e->getRequest()))->setRequestAttributes($this->attributes); $this->factory?->recordRequestResponsePair( $request, null @@ -1761,7 +1761,7 @@ protected function marshalRequestExceptionWithResponse(RequestException $e) $response = $this->populateResponse($this->newResponse($e->getResponse())); $this->factory?->recordRequestResponsePair( - (new Request($e->getRequest()))->setRequestContext($this->requestContext), + (new Request($e->getRequest()))->setRequestAttributes($this->attributes), $response ); diff --git a/src/Illuminate/Http/Client/Request.php b/src/Illuminate/Http/Client/Request.php index 3c8346a6fdfe..4878af66a4ac 100644 --- a/src/Illuminate/Http/Client/Request.php +++ b/src/Illuminate/Http/Client/Request.php @@ -27,11 +27,11 @@ class Request implements ArrayAccess protected $data; /** - * The contextual data passed when building the PendingRequest. + * The attribute data passed when building the PendingRequest. * * @var array */ - protected $requestContext = []; + protected $attributes = []; /** * Create a new request instance. @@ -252,26 +252,26 @@ public function withData(array $data) } /** - * Set the request's context data. + * Get the attribute data from the request. * - * @param array $context - * @return $this + * @return array */ - public function setRequestContext($context) + public function attributes() { - $this->requestContext = $context; - - return $this; + return $this->attributes; } /** - * Get the contextual data from the request. + * Set the request's attribute data. * - * @return array + * @param array $attributes + * @return $this */ - public function requestContext() + public function setRequestAttributes($attributes) { - return $this->requestContext; + $this->attributes = $attributes; + + return $this; } /** diff --git a/tests/Integration/Http/HttpClientTest.php b/tests/Integration/Http/HttpClientTest.php index 8ef64d2b9c6d..e9781e38e394 100644 --- a/tests/Integration/Http/HttpClientTest.php +++ b/tests/Integration/Http/HttpClientTest.php @@ -89,20 +89,20 @@ public function testForwardsCallsToPromise() $this->assertEquals('stub', $r); } - public function testCanSetRequestContext() + public function testCanSetRequestAttributes() { Http::fake([ - '*' => fn (Request $request) => match($request->requestContext()['name'] ?? null) { + '*' => fn (Request $request) => match($request->attributes()['name'] ?? null) { 'first' => Http::response('first response'), 'second' => Http::response('second response'), default => Http::response('unnamed') } ]); - $response1 = Http::withRequestContext(['name' => 'first'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); - $response2 = Http::withRequestContext(['name' => 'second'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); + $response1 = Http::withAttributes(['name' => 'first'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); + $response2 = Http::withAttributes(['name' => 'second'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); $response3 = Http::get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); - $response4 = Http::withRequestContext(['name' => 'fourth'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); + $response4 = Http::withAttributes(['name' => 'fourth'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json'); $this->assertEquals('first response', $response1->body()); $this->assertEquals('second response', $response2->body());