vendor/vich/uploader-bundle/src/Form/Type/VichFileType.php line 26

  1. <?php
  2. namespace Vich\UploaderBundle\Form\Type;
  3. use Symfony\Component\Form\AbstractType;
  4. use Symfony\Component\Form\Extension\Core\Type;
  5. use Symfony\Component\Form\FormBuilderInterface;
  6. use Symfony\Component\Form\FormEvent;
  7. use Symfony\Component\Form\FormEvents;
  8. use Symfony\Component\Form\FormInterface;
  9. use Symfony\Component\Form\FormView;
  10. use Symfony\Component\OptionsResolver\OptionsResolver;
  11. use Symfony\Component\PropertyAccess\PropertyAccess;
  12. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  13. use Symfony\Component\PropertyAccess\PropertyPath;
  14. use Vich\UploaderBundle\Form\DataTransformer\FileTransformer;
  15. use Vich\UploaderBundle\Handler\UploadHandler;
  16. use Vich\UploaderBundle\Mapping\PropertyMappingFactory;
  17. use Vich\UploaderBundle\Storage\StorageInterface;
  18. /**
  19.  * @author Kévin Gomez <contact@kevingomez.fr>
  20.  * @author Konstantin Myakshin <koc-dp@yandex.ru>
  21.  * @author Massimiliano Arione <max.arione@gmail.com>
  22.  */
  23. class VichFileType extends AbstractType
  24. {
  25.     protected readonly PropertyAccessorInterface $propertyAccessor;
  26.     public function __construct(
  27.         protected readonly StorageInterface $storage,
  28.         protected readonly UploadHandler $handler,
  29.         protected readonly PropertyMappingFactory $factory,
  30.         PropertyAccessorInterface $propertyAccessor null
  31.     ) {
  32.         $this->propertyAccessor $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
  33.     }
  34.     public function configureOptions(OptionsResolver $resolver): void
  35.     {
  36.         $resolver->setDefaults([
  37.             'allow_delete' => true,
  38.             'asset_helper' => false,
  39.             'download_uri' => true,
  40.             'download_label' => 'vich_uploader.link.download',
  41.             'delete_label' => 'vich_uploader.form_label.delete_confirm',
  42.             'error_bubbling' => false,
  43.         ]);
  44.         $resolver->setAllowedTypes('allow_delete''bool');
  45.         $resolver->setAllowedTypes('asset_helper''bool');
  46.         $resolver->setAllowedTypes('download_uri', ['bool''string''callable']);
  47.         $resolver->setAllowedTypes('download_label', ['bool''string''callable'PropertyPath::class]);
  48.         $resolver->setAllowedTypes('error_bubbling''bool');
  49.     }
  50.     public function buildForm(FormBuilderInterface $builder, array $options): void
  51.     {
  52.         $builder->add('file'Type\FileType::class, [
  53.             'required' => $options['required'],
  54.             'label' => $options['label'],
  55.             'attr' => $options['attr'],
  56.             'translation_domain' => $options['translation_domain'],
  57.         ]);
  58.         $builder->addModelTransformer(new FileTransformer());
  59.         if ($options['allow_delete']) {
  60.             $this->buildDeleteField($builder$options);
  61.         }
  62.     }
  63.     protected function buildDeleteField(FormBuilderInterface $builder, array $options): void
  64.     {
  65.         // add delete only if there is a file
  66.         $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options): void {
  67.             $form $event->getForm();
  68.             $parent $form->getParent();
  69.             // no object: no delete button
  70.             if (null === $parent) {
  71.                 return;
  72.             }
  73.             $object $parent->getData();
  74.             // no object or no uploaded file: no delete button
  75.             if (null === $object || null === $this->storage->resolveUri($object$this->getFieldName($form))) {
  76.                 return;
  77.             }
  78.             $form->add('delete'Type\CheckboxType::class, [
  79.                 'label' => $options['delete_label'],
  80.                 'mapped' => false,
  81.                 'translation_domain' => $options['translation_domain'],
  82.                 'required' => false,
  83.             ]);
  84.         });
  85.         // delete file if needed
  86.         $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event): void {
  87.             $form $event->getForm();
  88.             $object $form->getParent()->getData();
  89.             $delete $form->has('delete') ? $form->get('delete')->getData() : false;
  90.             if (!$delete) {
  91.                 return;
  92.             }
  93.             $this->handler->remove($object$this->getFieldName($form));
  94.         });
  95.     }
  96.     public function buildView(FormView $viewFormInterface $form, array $options): void
  97.     {
  98.         $object $form->getParent()->getData();
  99.         $view->vars['object'] = $object;
  100.         $view->vars['download_uri'] = null;
  101.         if ($options['download_uri'] && $object) {
  102.             $view->vars['download_uri'] = $this->resolveUriOption($options['download_uri'], $object$form);
  103.             $view->vars \array_replace(
  104.                 $view->vars,
  105.                 $this->resolveDownloadLabel($options['download_label'], $object$form)
  106.             );
  107.         }
  108.         $view->vars['asset_helper'] = $options['asset_helper'];
  109.     }
  110.     public function getBlockPrefix(): string
  111.     {
  112.         return 'vich_file';
  113.     }
  114.     final protected function getFieldName(FormInterface $form): string
  115.     {
  116.         return $form->getConfig()->getOption('property_path') ?? $form->getName();
  117.     }
  118.     protected function resolveUriOption(mixed $uriOptionobject $objectFormInterface $form): string|bool|null
  119.     {
  120.         if (true === $uriOption) {
  121.             return $this->storage->resolveUri($object$this->getFieldName($form));
  122.         }
  123.         if (\is_callable($uriOption)) {
  124.             return $uriOption($object$this->storage->resolveUri($object$this->getFieldName($form)));
  125.         }
  126.         return $uriOption;
  127.     }
  128.     protected function resolveDownloadLabel(mixed $downloadLabelobject $objectFormInterface $form): array
  129.     {
  130.         if (true === $downloadLabel) {
  131.             $fieldName $this->getFieldName($form);
  132.             $mapping $this->factory->fromField($object$fieldName);
  133.             if (null === $mapping) {
  134.                 throw new \UnexpectedValueException(\sprintf('Cannot find mapping for "%s" field'$fieldName));
  135.             }
  136.             return ['download_label' => $mapping->readProperty($object'originalName'), 'translation_domain' => false];
  137.         }
  138.         if (\is_callable($downloadLabel)) {
  139.             $result $downloadLabel($object);
  140.             return [
  141.                 'download_label' => $result['download_label'] ?? $result,
  142.                 'translation_domain' => $result['translation_domain'] ?? false,
  143.             ];
  144.         }
  145.         if ($downloadLabel instanceof PropertyPath) {
  146.             return [
  147.                 'download_label' => $this->propertyAccessor->getValue($object$downloadLabel),
  148.                 'translation_domain' => false,
  149.             ];
  150.         }
  151.         return ['download_label' => $downloadLabel];
  152.     }
  153. }