Symfony и Sonata admin - как прикрепить в поле input[type=file] выбранный на этапе создания формы файл?

Прошу простить за размытую формулировку в название темы, сейчас постараюсь конкретизировать. Создана форма для профиля пользователя (выводится на фронте и доступа к админке у пользователей с определенной ролью не будет).

  1. /user/profile/create
  2. /user/profile/{id}/edit

При создание профиля есть несколько полей для закрепления файлов и так как использую SonataAdminBundle при создание этих полей создал пользовательский тип поля ImageFieldType (фактически расширил стандартный FileType).

Код созданного типа поля
<?php
declare(strict_types=1);

namespace App\Application\Cms\ExpertBundle\Form\Type;

use Doctrine\ORM\EntityManagerInterface;
use Sonata\MediaBundle\Model\MediaInterface;
use Symfony\Component\Form\CallbackTransformer;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Form\FormBuilderInterface;
use Sonata\MediaBundle\Model\MediaManagerInterface;
use App\Application\Sonata\MediaBundle\Entity\Media;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

class ImageFieldType extends FileType
{
  /**
   * @var MediaManagerInterface
   */
  private $mediaManager;

  /**
   * @var EntityManagerInterface
   */
  private $em;

  public function __construct(MediaManagerInterface $mediaManager, EntityManagerInterface $em, $translator = null)
  {
      parent::__construct($translator);
      $this->mediaManager = $mediaManager;
      $this->em = $em;
  }

  /**
   * @param $object
   * @param ExecutionContextInterface $context
   */
  protected function validateObject($object, ExecutionContextInterface $context): void
  {
      $optionObj = $context->getObject()->getConfig()->getOption('required');
      $maxFileSize = 2097152;

      if ($optionObj && is_null($object)) {
          $context->addViolation('expert.expert_profile.files.not_blank');
      }

      if ($object !== null && (int)$object->getSize() > $maxFileSize) {
          $context->addViolation('expert.expert_profile.files.large_file', ['maxSize' => number_format($maxFileSize / 1048576)]);
      }

      if ($object !== null && !in_array($object->getContentType(), ['image/jpeg', 'image/png'])) {
          $context->addViolation('expert.expert_profile.files.ext_incorrect', ['formats' => '.jpg, .jpeg, .png']);
      }
  }

  /**
   * @param OptionsResolver $resolver
   */
  public function configureOptions(OptionsResolver $resolver): void
  {
      parent::configureOptions($resolver);
      $resolver->setDefault('multiple', true);
      $resolver->setDefault('required', false);
      $resolver->setDefault('data_class', null);
      $resolver->setDefault('constraints', new Callback([
          'callback' => function ($data, ExecutionContextInterface $context) {
              if (!empty($data) && $data instanceof ArrayCollection) {
                  foreach ($data->getValues() as $file) {
                      $this->validateObject($file, $context);
                  }
              } else {
                  $this->validateObject($data, $context);
              }
          }
      ]));
  }

  /**
   * @param FormBuilderInterface $builder
   * @param array $options
   */
  public function buildForm(FormBuilderInterface $builder, array $options): void
  {
      parent::buildForm($builder, $options);

      $builder->addModelTransformer(new CallbackTransformer(function ($data) {
          return $data;
      }, function ($data) use ($options) {
          if ($data) {
              $result = new ArrayCollection();
              if ($options['multiple']) {
                  foreach ($data as $file) {
                      $media = $this->addPhoto($file);
                      $this->mediaManager->save($media, false);
                      $result->add($media);
                      $this->em->persist($media);
                      $this->em->flush($media);
                  }
              } else {
                  $media = $this->addPhoto($data);
                  $this->mediaManager->save($media, false);
                  $result->add($media);
                  $this->em->persist($media);
                  $this->em->flush($media);
              }
              return $result;
          }
          return null;
      }));
  }

  /**
   * @return string
   */
  public function getBlockPrefix(): string
  {
      return 'file_field';
  }

  /**
   * @param $data
   * @return MediaInterface
   */
  private function addPhoto($data): MediaInterface
  {
      /**@var MediaInterface $media */
      $media = new Media();
      $media->setContext('default');
      $media->setProviderName('sonata.media.provider.file');
      $media->setBinaryContent($data);
      $media->setName($data->getClientOriginalName());

      return $media;
  }
}

Суть проблемы:

Если заполнить профиль и допустить ошибку валидации в любом из полей и попытаться сохранить форму, то происходит редирект с сохранением всех введенных данных, которые были указанны в input за исключением полей, в которые были прикреплены файлы (приходится повторно их выбирать).

Столкнулся с проблемой ещё на этапе создания профиля, но на тот момент - это раздражало но не более. А на странице редактирования профиля дела обстоят куда печальнее:

Условно, если пользователь решил изменить какую-то информацию в профиле, ему в обязательном порядке придется прикреплять файлы (хотя они были выбраны на этапе создания профиля и прекрасно выводятся на странице редактирования - приложил скриншот).

введите сюда описание изображения

Хочу добиться следующего: если в поле input[type=file] на этапе создания формы прикреплялся файл, то на странице редактирования у этих полей отображалось не "No file chosen", а название выбранного ранее файла.

Гуглю информацию второй день, пока не смог найти ничего дельного. Буду очень признателен, за любой совет!


Ответы (0 шт):