API Platform version(s) affected: 2.5.7
When making a request in an ApiTestCase with a FormDataPart, the $request->files is empty on the controller side.
Here is my test :
<?php
namespace App\Tests\Controller;
use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
class ImportRequestTest extends ApiTestCase
{
public function testPostOk(): void
{
$client = static::createClient();
$data = ['file' => DataPart::fromPath(__DIR__.'/../path/to/file.csv')];
$formData = new FormDataPart($data);
$headers = $formData->getPreparedHeaders();
$client->request(
'POST',
'/import_requests/{my-request-id}/upload',
[
'headers' => $headers->toArray(),
'body' => $formData->bodyToString(),
]
);
$this->assertResponseIsSuccessful();
$this->assertResponseStatusCodeSame(204);
}
}
The related ApiResource :
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Controller\ImportRequestUpload;
/**
* @ApiResource(
* itemOperations={
* "get",
* "delete",
* "put",
* "upload"={
* "method"="POST",
* "path"="/import_requests/{id}/upload",
* "controller"=ImportRequestUpload::class,
* "deserialize"=false,
* "openapi_context"={
* "requestBody"={
* "content"={
* "multipart/form-data"={
* "schema"={
* "type"="object",
* "properties"={
* "file"={
* "type"="string",
* "format"="binary"
* }
* }
* }
* }
* }
* }
* }
* }
* },
* collectionOperations={
* "get",
* "post"
* }
* )
*/
final class ImportRequest
{
// ...
}
And my controller :
<?php
namespace App\Controller;
use App\Entity\ImportRequest;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final class ImportRequestUpload
{
public function __invoke(ImportRequest $data, Request $request)
{
/** @var null|UploadedFile $uploadedFile */
$uploadedFile = $request->files->get('file');
if (null === $uploadedFile) {
throw new BadRequestHttpException('"file" is required.');
}
// ...
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
}
}
When running my test, the ImportRequestUpload controller is throwing the BadRequestHttpException('"file" is required.').
What's weird is that the content and headers of my request seems ok when I dump them in the controller :
Symfony\Component\HttpFoundation\Request {
...
+server: Symfony\Component\HttpFoundation\ServerBag {#4930
#parameters: array:25 [
...
"CONTENT_TYPE" => "multipart/form-data; boundary=hqdh0ikk"
"REQUEST_METHOD" => "POST"
...
]
}
+files: Symfony\Component\HttpFoundation\FileBag {#4931
#parameters: []
}
...
+headers: Symfony\Component\HttpFoundation\HeaderBag {#4941
#headers: array:15 [
...
"content-type" => array:1 [
0 => "multipart/form-data; boundary=hqdh0ikk"
]
...
]
}
#content: """
--hqdh0ikk\r\n
Content-Type: text/csv\r\n
Content-Transfer-Encoding: 8bit\r\n
Content-Disposition: form-data; name="file"; filename="import_ok_1.csv"\r\n
\r\n
header1,header2\n
value1,value2\n
\r\n
--hqdh0ikk--\r\n
"""
}
If I replace the $formData->bodyToString() by $formData->bodyToIterable() (as initially suggested in the HttpClient documentation https://symfony.com/doc/current/http_client.html#uploading-data), I get the following error :
TypeError : Argument 6 passed to Symfony\Component\BrowserKit\AbstractBrowser::request() must be of the type string or null, object given, called in /srv/api/vendor/api-platform/core/src/Bridge/Symfony/Bundle/Test/Client.php on line 126
/srv/api/vendor/symfony/browser-kit/AbstractBrowser.php:341
/srv/api/vendor/api-platform/core/src/Bridge/Symfony/Bundle/Test/Client.php:126
Am I doing something wrong ? Is there any other way to upload a file in an ApiTestCase ?
Thanks for your help.