diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 28bde9944772..43169c9c4b75 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -1021,7 +1021,21 @@ protected function parseHttpOptions(array $options) protected function parseMultipartBodyFormat(array $data) { return (new Collection($data)) - ->map(fn ($value, $key) => is_array($value) ? $value : ['name' => $key, 'contents' => $value]) + ->flatMap(function ($value, $key) { + if (is_array($value)) { + // If the array has 'name' and 'contents' keys, it's already formatted for multipart... + if (isset($value['name']) && isset($value['contents'])) { + return [$value]; + } + + // Otherwise, treat it as multiple values for the same field name... + return (new Collection($value))->map(function ($item) use ($key) { + return ['name' => $key.'[]', 'contents' => $item]; + }); + } + + return [['name' => $key, 'contents' => $value]]; + }) ->values() ->all(); } diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 1604be010c15..535d7c12aee2 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -785,6 +785,53 @@ public function testCanSendMultipartDataWithBothSimplifiedAndExtendedParameters( }); } + public function testCanSendMultipartDataWithArrayValues() + { + $this->factory->fake(); + + $this->factory->asMultipart()->post('http://foo.com/multipart', [ + 'name' => 'Steve', + 'roles' => ['Network Administrator', 'Janitor'], + ]); + + $this->factory->assertSent(function (Request $request) { + return $request->url() === 'http://foo.com/multipart' && + Str::startsWith($request->header('Content-Type')[0], 'multipart') && + $request[0]['name'] === 'name' && + $request[0]['contents'] === 'Steve' && + $request[1]['name'] === 'roles[]' && + $request[1]['contents'] === 'Network Administrator' && + $request[2]['name'] === 'roles[]' && + $request[2]['contents'] === 'Janitor'; + }); + } + + public function testCanSendMultipartDataWithFileAndArrayValues() + { + $this->factory->fake(); + + $this->factory + ->attach('attachment', 'photo_content', 'photo.jpg', ['Content-Type' => 'image/jpeg']) + ->post('http://foo.com/multipart', [ + 'name' => 'Steve', + 'roles' => ['Network Administrator', 'Janitor'], + ]); + + $this->factory->assertSent(function (Request $request) { + return $request->url() === 'http://foo.com/multipart' && + Str::startsWith($request->header('Content-Type')[0], 'multipart') && + $request[0]['name'] === 'name' && + $request[0]['contents'] === 'Steve' && + $request[1]['name'] === 'roles[]' && + $request[1]['contents'] === 'Network Administrator' && + $request[2]['name'] === 'roles[]' && + $request[2]['contents'] === 'Janitor' && + $request[3]['name'] === 'attachment' && + $request[3]['contents'] === 'photo_content' && + $request[3]['filename'] === 'photo.jpg'; + }); + } + public function testItCanSendToken() { $this->factory->fake();