I'm trying to upload files with Api Platform and Vich Uploader Bundle. When I send POST request with multipart/form-data and Id of the entity to attach image file to, I get 200 response with my entity. But uploaded file doesn't uploads to destination directory and it's generated filename doesn't persists. No errors, no any clues, no idea.
Here is my code:
//vich uploader mappings
vich_uploader:
db_driver: orm
mappings:
logo:
uri_prefix: /logo
upload_destination: '%kernel.project_dir%/public/images/logo/'
namer: App\Infrastructure\Naming\LogoNamer
//Organization Entity
<?php
namespace App\Infrastructure\Dto;
...use
/**
* @ORM\Entity()
* @ApiResource(
* iri="https://schema.org/Organization",
* shortName="Place",
* collectionOperations={
* "post" = {
* "denormalization_context" = {
* "groups"={
* "organization:collection:post"
* }
* }
* },
* "get" = {
* "normalization_context" = {
* "groups"={
* "organization:collection:get"
* }
* }
* }
* },
* itemOperations={
* "get",
* "CreateOrganizationLogoAction::OPERATION_NAME" = {
* "groups"={"logo:post"},
* "method"="POST",
* "path"=CreateOrganizationLogoAction::OPERATION_PATH,
* "controller"=CreateOrganizationLogoAction::class,
* "deserialize"=false,
* "validation_groups"={"Default", "logo_create"},
* "openapi_context"={
* "summary"="Uploads logo file to given Organization resource",
* "requestBody"={
* "content"={
* "multipart/form-data"={
* "schema"={
* "type"="object",
* "properties"={
* "logoFile"={
* "type"="string",
* "format"="binary"
* }
* }
* }
* }
* }
* }
* }
* }
* }
* )
* @Vich\Uploadable
*/
final class Organization
{
/**
* @Groups({"organization:collection:get"})
* @ORM\Id
* @ORM\Column(type="uuid", unique=true)
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class=UuidGenerator::class)
* @ApiProperty(identifier=true)
*/
protected Uuid $id;
/**
* @Groups({"organization:collection:get", "organization:collection:post"})
* @ORM\Column(type="string", length=100, unique=true)
*/
public string $slug;
/**
* @ORM\Column(type="smallint")
*/
public int $status;
/**
* @ApiProperty(iri="https://schema.org/name")
* @Groups({"organization:collection:get"})
* @ORM\Column(type="string", length=100, nullable=true)
*/
public ?string $title = null;
/**
* @ApiProperty(iri="http://schema.org/logo")
* @Groups({"organization:collection:get", "logo:post"})
* @ORM\Column(nullable=true)
*/
public ?string $logoPath = null;
/**
* @ApiProperty(iri="https://schema.org/description")
* @ORM\Column(type="text", nullable=true)
*/
public ?string $description = null;
/**
* @ApiProperty(iri="https://schema.org/disambiguatingDescription")
* @Groups({"organization:collection:get"})
* @ORM\Column(type="string", length=150, nullable=true)
*/
public ?string $disambiguating_description = null;
/**
* @ApiProperty(iri="https://schema.org/addressCountry")
* @ORM\Column(type="string", length=2, nullable=true)
*/
public ?string $country = null;
/**
* @ApiProperty(iri="https://schema.org/addressRegion")
* @ORM\Column(type="string", nullable=true)
*/
public ?string $region = null;
/**
* @ApiProperty(iri="https://schema.org/streetAddress")
* @ORM\Column(type="string", nullable=true)
*/
public ?string $street = null;
/**
* @ApiProperty(iri="https://schema.org/telephone")
* @ORM\Column(type="string", nullable=true)
*/
public ?string $telephone = null;
/**
* @ApiProperty(iri="https://schema.org/email")
* @ORM\Column(type="string", nullable=true)
*/
public ?string $email = null;
/**
* @ApiProperty(iri="https://schema.org/contentUrl")
* @Groups({"logo_read"})
*/
public ?string $logoContentUrl = null;
/**
* @var File|null
*
* @Assert\NotNull(groups={"logo_create"})
* @Vich\UploadableField(mapping="logo", fileNameProperty="logoPath")
*/
public ?File $logoFile = null;
public function __construct()
{
$this->status = OrganizationStatus::DRAFT()->getValue();
}
public function getId(): ?Uuid
{
return $this->id ?? null;
}
public function setId(Uuid $id)
{
$this->id = $id;
}
}
final class CreateOrganizationLogoAction extends AbstractController
{
const OPERATION_NAME = 'post_logo';
const OPERATION_PATH = '/places/{id}/logo';
private OrganizationPgRepository $repository;
public function __construct(OrganizationPgRepository $repository)
{
$this->repository = $repository;
}
/**
* @param Request $request
*
* @return EntityOrganization
*/
public function __invoke(Request $request): EntityOrganization
{
$uploadedFile = $request->files->get('logoFile');
if (!$uploadedFile) {
throw new BadRequestHttpException('"file" is required');
}
$organization = $this->repository->find(Uuid::fromString($request->attributes->get('id')));
$organization->logoFile = $uploadedFile;
return $organization;
}
}
I'm sending request:
curl -X POST "http://localhost:8081/api/places/0dc43a86-6402-4a45-8392-19d5e398a7ab/logo" -H "accept: application/ld+json" -H "Content-Type: multipart/form-data" -F "[email protected];type=image/png"
... and getting response:
{
"@context": "/api/contexts/Place",
"@id": "/api/places/0dc43a86-6402-4a45-8392-19d5e398a7ab",
"@type": "https://schema.org/Organization",
"slug": "consequatur-aut-optio-corrupti-quod-sit-libero-aspernatur",
"status": 0,
"title": "Block LLC",
"logoPath": "a268cde1-d93e-4d48-9f0d-177b4f89f1f8.png",
"description": "Nisi sint ducimus consequatur dicta sint maxime. Et soluta facere in quisquam quia. Tempore quae non qui dignissimos optio rem cum illum. Eum similique vitae autem aut. Reiciendis nesciunt rerum libero in consequuntur excepturi repellendus unde. Tempore ea perferendis sunt quibusdam autem est. Similique qui illum necessitatibus velit dolores. Voluptas sapiente excepturi ad assumenda exercitationem est. Nesciunt sint sint fugiat quis blanditiis. Rerum vel sint temporibus nobis fugiat nostrum aut. Voluptatibus temporibus magnam cumque asperiores. Adipisci qui perferendis mollitia tempore accusantium aut. Possimus numquam asperiores repellendus non facilis.",
"disambiguating_description": "Et libero temporibus ut impedit esse ipsum quam.",
"country": "RU",
"region": "Idaho",
"street": "15544 Delbert Underpass",
"telephone": "+78891211558",
"email": "[email protected]",
"pictures": [],
"social_profiles": [],
"logoContentUrl": "/logo/a268cde1-d93e-4d48-9f0d-177b4f89f1f8.png",
"logoFile": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD//gA7Q1JFQVRPUjog
...
...
... TgjNWnJ7YWPrMCWGxWbi57Tj58TfPQL1Hi54DRFD/FkuLcuXBKFB3TFLcuaUvpqKuYUJaLL/yV/R/+kf/Z",
"id": "0dc43a86-6402-4a45-8392-19d5e398a7ab"
}
As you can see it's all ok. Proper organization was found. And even logoFile field was filled with uploaded picture. But uploaded file wasn't moved to destination. And logoPath contains old logo filename.
As I said no errors. Please help me to figure out where to dig.
__invoke
function. There you get the image, but you don't move it. You assign it to theorganisation
, but you don't save the updated organisation. This way your return data seems correct, but any new request will use the old setting – Verbenia