Skip to content

Commit a98b935

Browse files
[12.x] PendingRequest@withRequestContext() (#58054)
* request-context * formatting --------- Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent 9bb886f commit a98b935

File tree

3 files changed

+94
-7
lines changed

3 files changed

+94
-7
lines changed

src/Illuminate/Http/Client/PendingRequest.php

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,13 @@ class PendingRequest
197197
*/
198198
protected $async = false;
199199

200+
/**
201+
* The attributes to track with the request.
202+
*
203+
* @var array<array-key, mixed>
204+
*/
205+
protected $attributes = [];
206+
200207
/**
201208
* The pending request promise.
202209
*
@@ -702,6 +709,19 @@ public function withResponseMiddleware(callable $middleware)
702709
return $this;
703710
}
704711

712+
/**
713+
* Set arbitrary attributes to store with the request.
714+
*
715+
* @param array<array-key, mixed> $attributes
716+
* @return $this
717+
*/
718+
public function withAttributes($attributes)
719+
{
720+
$this->attributes = array_merge_recursive($this->attributes, $attributes);
721+
722+
return $this;
723+
}
724+
705725
/**
706726
* Add a new "before sending" callback to the request.
707727
*
@@ -1140,7 +1160,10 @@ protected function makePromise(string $method, string $url, array $options = [],
11401160
if ($e instanceof ConnectException || ($e instanceof RequestException && ! $e->hasResponse())) {
11411161
$exception = new ConnectionException($e->getMessage(), 0, $e);
11421162

1143-
$this->dispatchConnectionFailedEvent(new Request($e->getRequest()), $exception);
1163+
$this->dispatchConnectionFailedEvent(
1164+
(new Request($e->getRequest()))->setRequestAttributes($this->attributes),
1165+
$exception
1166+
);
11441167

11451168
return $exception;
11461169
}
@@ -1416,7 +1439,9 @@ public function buildRecorderHandler()
14161439

14171440
return $promise->then(function ($response) use ($request, $options) {
14181441
$this->factory?->recordRequestResponsePair(
1419-
(new Request($request))->withData($options['laravel_data']),
1442+
(new Request($request))
1443+
->withData($options['laravel_data'])
1444+
->setRequestAttributes($this->attributes),
14201445
$this->newResponse($response)
14211446
);
14221447

@@ -1437,7 +1462,12 @@ public function buildStubHandler()
14371462
return function ($request, $options) use ($handler) {
14381463
$response = ($this->stubCallbacks ?? new Collection)
14391464
->map
1440-
->__invoke((new Request($request))->withData($options['laravel_data']), $options)
1465+
->__invoke(
1466+
(new Request($request))
1467+
->withData($options['laravel_data'])
1468+
->setRequestAttributes($this->attributes),
1469+
$options
1470+
)
14411471
->filter()
14421472
->first();
14431473

@@ -1496,7 +1526,12 @@ public function runBeforeSendingCallbacks($request, array $options)
14961526
return tap($request, function (&$request) use ($options) {
14971527
$this->beforeSendingCallbacks->each(function ($callback) use (&$request, $options) {
14981528
$callbackResult = call_user_func(
1499-
$callback, (new Request($request))->withData($options['laravel_data']), $options, $this
1529+
$callback,
1530+
(new Request($request))
1531+
->withData($options['laravel_data'])
1532+
->setRequestAttributes($this->attributes),
1533+
$options,
1534+
$this
15001535
);
15011536

15021537
if ($callbackResult instanceof RequestInterface) {
@@ -1700,7 +1735,7 @@ protected function marshalConnectionException(ConnectException $e)
17001735
{
17011736
$exception = new ConnectionException($e->getMessage(), 0, $e);
17021737

1703-
$request = new Request($e->getRequest());
1738+
$request = (new Request($e->getRequest()))->setRequestAttributes($this->attributes);
17041739

17051740
$this->factory?->recordRequestResponsePair(
17061741
$request, null
@@ -1721,7 +1756,7 @@ protected function marshalRequestExceptionWithoutResponse(RequestException $e)
17211756
{
17221757
$exception = new ConnectionException($e->getMessage(), 0, $e);
17231758

1724-
$request = new Request($e->getRequest());
1759+
$request = (new Request($e->getRequest()))->setRequestAttributes($this->attributes);
17251760

17261761
$this->factory?->recordRequestResponsePair(
17271762
$request, null
@@ -1743,7 +1778,7 @@ protected function marshalRequestExceptionWithResponse(RequestException $e)
17431778
$response = $this->populateResponse($this->newResponse($e->getResponse()));
17441779

17451780
$this->factory?->recordRequestResponsePair(
1746-
new Request($e->getRequest()),
1781+
(new Request($e->getRequest()))->setRequestAttributes($this->attributes),
17471782
$response
17481783
);
17491784

src/Illuminate/Http/Client/Request.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ class Request implements ArrayAccess
2626
*/
2727
protected $data;
2828

29+
/**
30+
* The attribute data passed when building the PendingRequest.
31+
*
32+
* @var array<array-key, mixed>
33+
*/
34+
protected $attributes = [];
35+
2936
/**
3037
* Create a new request instance.
3138
*
@@ -244,6 +251,29 @@ public function withData(array $data)
244251
return $this;
245252
}
246253

254+
/**
255+
* Get the attribute data from the request.
256+
*
257+
* @return array<array-key, mixed>
258+
*/
259+
public function attributes()
260+
{
261+
return $this->attributes;
262+
}
263+
264+
/**
265+
* Set the request's attribute data.
266+
*
267+
* @param array<array-key, mixed> $attributes
268+
* @return $this
269+
*/
270+
public function setRequestAttributes($attributes)
271+
{
272+
$this->attributes = $attributes;
273+
274+
return $this;
275+
}
276+
247277
/**
248278
* Get the underlying PSR compliant request instance.
249279
*

tests/Integration/Http/HttpClientTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Http\Client\Events\RequestSending;
66
use Illuminate\Http\Client\Pool;
7+
use Illuminate\Http\Client\Request;
78
use Illuminate\Http\Client\Response;
89
use Illuminate\Support\Collection;
910
use Illuminate\Support\Facades\Event;
@@ -87,4 +88,25 @@ public function testForwardsCallsToPromise()
8788
$this->assertEquals('faked response', $myFakedResponse);
8889
$this->assertEquals('stub', $r);
8990
}
91+
92+
public function testCanSetRequestAttributes()
93+
{
94+
Http::fake([
95+
'*' => fn (Request $request) => match($request->attributes()['name'] ?? null) {
96+
'first' => Http::response('first response'),
97+
'second' => Http::response('second response'),
98+
default => Http::response('unnamed')
99+
}
100+
]);
101+
102+
$response1 = Http::withAttributes(['name' => 'first'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json');
103+
$response2 = Http::withAttributes(['name' => 'second'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json');
104+
$response3 = Http::get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json');
105+
$response4 = Http::withAttributes(['name' => 'fourth'])->get('https://some-store.myshopify.com/admin/api/2025-10/graphql.json');
106+
107+
$this->assertEquals('first response', $response1->body());
108+
$this->assertEquals('second response', $response2->body());
109+
$this->assertEquals('unnamed', $response3->body());
110+
$this->assertEquals('unnamed', $response4->body());
111+
}
90112
}

0 commit comments

Comments
 (0)