How to post an entity embedding collection of files using API Platform?

I have a Project entity embedding a collection of mediaObjects

    class Project
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups("project:read")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"project:read", "project:write"})
     */
    private $title;

    /**
     * @ORM\OneToMany(targetEntity=MediaObject::class, mappedBy="project", cascade={"persist"})
     * @Groups({"project:read", "project:write"})
     */
    private $mediaObjects;

My MediaOjbect class looks like the one described in API Platform doc to handle file upload using VichUploaderBundle (https://api-platform.com/docs/core/file-upload/), except I have the Project id also

/**
 * @ORM\Entity
 * @ApiResource(
 *     iri="http://schema.org/MediaObject",
 *     normalizationContext={
 *         "groups"={"media_object_read"}
 *     },
 *     denormalizationContext={
 *         "groups"={"media_object_create"}
 *     },
 *     collectionOperations={
 *         "post"={
 *             "controller"=CreateMediaObjectAction::class,
 *             "deserialize"=false,
 *             "security"="is_granted('ROLE_USER')",
 *             "validation_groups"={"Default", "media_object_create", "project:write"},
 *             "openapi_context"={
 *                 "requestBody"={
 *                     "content"={
 *                         "multipart/form-data"={
 *                             "schema"={
 *                                 "type"="object",
 *                                 "properties"={
 *                                     "file"={
 *                                         "type"="string",
 *                                         "format"="binary"
 *                                     }
 *                                 }
 *                             }
 *                         }
 *                     }
 *                 }
 *             }
 *         },
 *         "get"
 *     },
 *     itemOperations={
 *         "get",
 *         "put"={"security"="object.getUser() == user"},
 *         "patch",
 *         "delete"={"security"="object.getUser() == user"}
 *     }
 * )
 * @Vich\Uploadable
 * @ORM\HasLifecycleCallbacks()
 */
class MediaObject
{
    /**
     * @var int|null
     *
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     * @ORM\Id
     * @Groups({"read", "project:read", "media_object_read"})
     */
    protected $id;

    /**
     * @var string|null
     *
     * @ApiProperty(iri="http://schema.org/contentUrl")
     */
    public $contentUrl;

    /**
     * @var File|null
     *
     * @Assert\NotNull(groups={"media_object_create", "project:write"})
     * @Vich\UploadableField(mapping="media_object", fileNameProperty="filePath")
     */
    public $file;

    /**
     * @var string|null
     *
     * @ORM\Column(nullable=true)
     * @Groups({"read", "project:read", "media_object_read", "project:read"})
     */
    public $filePath;

    /**
     * @ORM\Column(type="datetime")
     * @Groups({"media_object_write", "project:write"})
     */
    private $createdAt;

    /**
     * @ORM\OneToOne(targetEntity=User::class)
     */
    private $user;

    /**
     * @ORM\ManyToOne(targetEntity=Project::class, inversedBy="mediaObjects")
     */
    private $project;

My question: is there a way to post a Project with a collection of mediaObjects in it?

I’m using React.js client side. I was trying to post an array of formData, this kind of request payload:

{
   title: "title",
   mediaObjects: [
                   formData,
                   formData
                 ]
}

But it doesn’t work.

I have "nested documents for attribute are not allowed. use iris instead".

1 thought on “How to post an entity embedding collection of files using API Platform?”

  1. Hey @helloguys well I was struggling with the same dub and ask the Api Platform team… look at this conversation it may be helpful for you…here… but well basically I don’t use VichUploader\Bundle, I normally use a CustomUploader class that help me to upload the files to the filesystem, expose two fields in MediaObject ("filename","data") filename represents the file name of the file inside the filesystem and data is the base64encode representation of the file (the downside of this approach is that this way the file is slightly bigger than usual, which is ok for small files), then you could expose those fields with some serialization groups like normal fields. Then you could do some DataPersister and then fill in the fields and move the file to its final destination on the filesystem using the CustomUploader and persist the object through the relation, with this solution you could send normal json to the API endpoint instead of multipart/form-data and it will work perfectly! Let me know if this helps you or you need more details! Cheers…
    PD: int the conversation there is the code of one example with a Service entity with OneToMany relationship with MediaObject! and also the CustomUploaderHelper class

    Reply

Leave a Comment