Symfony и Sonata admin - как прикрепить в поле input[type=file] выбранный на этапе создания формы файл?
Прошу простить за размытую формулировку в название темы, сейчас постараюсь конкретизировать. Создана форма для профиля пользователя (выводится на фронте и доступа к админке у пользователей с определенной ролью не будет).
- /user/profile/create
- /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", а название выбранного ранее файла.
Гуглю информацию второй день, пока не смог найти ничего дельного. Буду очень признателен, за любой совет!
