Symfony Form & FOSRESTBundle: Как загрузить файл?

Для загрузки файла с использованием Symfony Form и FOSRESTBundle существует несколько шагов:

Шаг 1: Настройка сущности
Сначала необходимо настроить сущность, в которую будет загружаться файл. В нашем примере, предположим, что у нас есть сущность "Product" и мы хотим добавить поле "image" для загрузки изображения:

<?php
namespace AppEntity;
use DoctrineORMMapping as ORM;
use SymfonyComponentHttpFoundationFileFile;
use VichUploaderBundleMappingAnnotation as Vich;
/**
* @ORMEntity(repositoryClass="AppRepositoryProductRepository")
* @VichUploadable
*/
class Product
{
    // ...

    /**
    * @ORMColumn(type="string", length=255, nullable=true)
    */
    private $imageName;

    /**
    * @VichUploadableField(mapping="product_images", fileNameProperty="imageName")
    * @var File
    */
    private $imageFile;

    // ...

    public function setImageFile(File $image = null): void
    {
        $this->imageFile = $image;
        if ($image) {
            // вносим изменения в updatedAt для обновления записи в БД при загрузке файла
            $this->updatedAt = new DateTimeImmutable();
        }
    }

    public function getImageFile(): ?File
    {
        return $this->imageFile;
    }

    public function setImageName(?string $imageName): void
    {
        $this->imageName = $imageName;
    }

    public function getImageName(): ?string
    {
        return $this->imageName;
    }

    // ...
}

В этом примере мы добавили поле "imageName", которое будет хранить имя загруженного файла, и поле "imageFile", которое будет использоваться для временного хранения самого файла при загрузке.

Также добавили методы "setImageFile" и "getImageFile", которые будут использоваться для установки и получения файла.

Шаг 2: Настройка формы
Далее необходимо настроить форму для загрузки файла. Создайте класс формы "ProductType" в директории "Form":

<?php
namespace AppForm;
use AppEntityProduct;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;
use SymfonyComponentFormExtensionCoreTypeFileType;
class ProductType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            // ...
            ->add('imageFile', FileType::class, [
                'label' => 'Image',
                'required' => false,
            ])
            // ...
        ;
    }
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Product::class,
        ]);
    }
}

В этом примере мы добавили поле "imageFile" с типом FileType, которое будет использоваться для загрузки файла. Обратите внимание на параметр "required" - он установлен в "false" для того, чтобы поле было необязательным.

Шаг 3: Обработка загрузки файла в контроллере
Теперь нужно обработать загрузку файла в контроллере. Создайте метод в вашем контроллере для обработки запроса:

<?php
namespace AppController;
use AppEntityProduct;
use AppFormProductType;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentRoutingAnnotationRoute;
/**
* @Route("/products")
*/
class ProductController extends AbstractController
{
    /**
    * @Route("/", name="product_create", methods={"POST"})
    */
    public function create(Request $request)
    {
        $product = new Product();
        $form = $this->createForm(ProductType::class, $product);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($product);
            $entityManager->flush();

            return $this->json([
                'message' => 'Product created successfully',
            ]);
        }

        return $this->json([
            'message' => 'Unable to create product',
        ]);
    }
}

Мы создаем новый объект Product, затем создаем форму, связываем ее с объектом Product и обрабатываем запрос с использованием метода "handleRequest". Если форма была отправлена корректно, то сохраняем данные в БД.

Вы можете изменить это действие в вашем контроллере в соответствии с вашими потребностями.

Шаг 4: Работа с аннотациями VichUploaderBundle
Наконец, у вас должна быть некоторая конфигурация VichUploaderBundle для обработки загрузки файла. Вам нужно настроить пути сохранения и некоторые другие параметры. Вот пример конфигурации "vich_uploader.yaml":

# config/packages/vich_uploader.yaml
vich_uploader:
    db_driver: orm
    mappings:
        product_images:
            uri_prefix:         /images/products
            upload_destination: '%kernel.project_dir%/public/images/products'
            namer:              VichUploaderBundleNamingUniqidNamer
            inject_on_load:     false
            delete_on_update:   true
            delete_on_remove:   true

В этом примере мы настроили путь, по которому будут сохраняться изображения, и указали имя файла, которое будет генерироваться с помощью класса "UniqidNamer".

Теперь, когда все настроено, вы сможете загружать файлы с помощью Symfony Form и FOSRESTBundle.