|
|
@@ -0,0 +1,258 @@ |
|
|
|
<?php |
|
|
|
|
|
|
|
namespace Lc\SovBundle\Form\Common; |
|
|
|
|
|
|
|
use EasyCorp\Bundle\EasyAdminBundle\Form\DataTransformer\StringToFileTransformer; |
|
|
|
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\Model\FileUploadState; |
|
|
|
use Lc\SovBundle\Model\File\FileInterface; |
|
|
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; |
|
|
|
use Symfony\Component\Form\DataMapperInterface; |
|
|
|
use Symfony\Component\Form\DataTransformerInterface; |
|
|
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; |
|
|
|
use Symfony\Component\Form\FormInterface; |
|
|
|
use Symfony\Component\HttpFoundation\File\File; |
|
|
|
use Lc\SovBundle\Doctrine\EntityManager; |
|
|
|
use Symfony\Component\Form\AbstractType; |
|
|
|
use Symfony\Component\Form\Extension\Core\Type\FileType; |
|
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType; |
|
|
|
use Symfony\Component\Form\FormBuilderInterface; |
|
|
|
use Symfony\Component\HttpFoundation\File\UploadedFile; |
|
|
|
use Symfony\Component\OptionsResolver\Exception\InvalidArgumentException; |
|
|
|
use Symfony\Component\OptionsResolver\Options; |
|
|
|
use Symfony\Component\OptionsResolver\OptionsResolver; |
|
|
|
use Symfony\Component\String\Slugger\AsciiSlugger; |
|
|
|
use Symfony\Component\Uid\Ulid; |
|
|
|
use Symfony\Component\Uid\Uuid; |
|
|
|
|
|
|
|
class FileUploadType extends AbstractType implements DataMapperInterface, DataTransformerInterface |
|
|
|
{ |
|
|
|
protected string $projectDir; |
|
|
|
protected EntityManager $entityManager; |
|
|
|
|
|
|
|
public function __construct(EntityManager $entityManager, ParameterBagInterface $parameterBag) |
|
|
|
{ |
|
|
|
$this->projectDir = $parameterBag->get('kernel.project_dir'); |
|
|
|
$this->entityManager = $entityManager; |
|
|
|
} |
|
|
|
|
|
|
|
public function buildForm(FormBuilderInterface $builder, array $options) |
|
|
|
{ |
|
|
|
$uploadDir = $options['upload_dir']; |
|
|
|
$uploadFilename = $options['upload_filename']; |
|
|
|
$uploadValidate = $options['upload_validate']; |
|
|
|
$allowAdd = $options['allow_add']; |
|
|
|
unset($options['upload_dir'], $options['upload_new'], $options['upload_delete'], $options['upload_filename'], $options['upload_validate'], $options['download_path'], $options['allow_add'], $options['allow_delete'], $options['compound']); |
|
|
|
|
|
|
|
$builder->add('path', FileType::class, $options); |
|
|
|
$builder->add('legend', TextType::class, array( |
|
|
|
'attr' => [ |
|
|
|
"placeholder" => 'Légende' |
|
|
|
], |
|
|
|
'label' => false |
|
|
|
)); |
|
|
|
$builder->add('delete', CheckboxType::class, ['required' => false, 'mapped' => false]); |
|
|
|
|
|
|
|
$builder->setDataMapper($this); |
|
|
|
$builder->setAttribute('state', new FileUploadState($allowAdd)); |
|
|
|
$builder->addModelTransformer(new StringToFileTransformer($uploadDir, $uploadFilename, $uploadValidate, $options['multiple'])); |
|
|
|
|
|
|
|
/* |
|
|
|
$builder->add('path', FileType::class, array( |
|
|
|
'block_prefix' => 'file_manager_image', |
|
|
|
'label' => false |
|
|
|
)); |
|
|
|
|
|
|
|
$builder->add('legend', TextType::class, array( |
|
|
|
'block_prefix' => 'file_upload_legend', |
|
|
|
'attr' => array( |
|
|
|
"placeholder" => 'Légende' |
|
|
|
), |
|
|
|
'label' => false |
|
|
|
)); |
|
|
|
|
|
|
|
$builder->add('position', HiddenType::class, array( |
|
|
|
'block_prefix' => 'file_upload_position', |
|
|
|
'empty_data' => 0, |
|
|
|
'required' => true, |
|
|
|
'attr' => array( |
|
|
|
'class' => 'field-position' |
|
|
|
), |
|
|
|
'label' => false |
|
|
|
)); |
|
|
|
*/ |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* {@inheritdoc} |
|
|
|
*/ |
|
|
|
public function configureOptions(OptionsResolver $resolver): void |
|
|
|
{ |
|
|
|
$uploadNew = static function (UploadedFile $file, string $uploadDir, string $fileName) { |
|
|
|
$file->move($uploadDir, $fileName); |
|
|
|
}; |
|
|
|
|
|
|
|
$uploadDelete = static function (File $file) { |
|
|
|
unlink($file->getPathname()); |
|
|
|
}; |
|
|
|
|
|
|
|
$uploadFilename = static function (UploadedFile $file): string { |
|
|
|
return $file->getClientOriginalName(); |
|
|
|
}; |
|
|
|
|
|
|
|
$uploadValidate = static function (string $filename): string { |
|
|
|
if (!file_exists($filename)) { |
|
|
|
return $filename; |
|
|
|
} |
|
|
|
|
|
|
|
$index = 1; |
|
|
|
$pathInfo = pathinfo($filename); |
|
|
|
while (file_exists($filename = sprintf('%s/%s_%d.%s', $pathInfo['dirname'], $pathInfo['filename'], $index, $pathInfo['extension']))) { |
|
|
|
++$index; |
|
|
|
} |
|
|
|
|
|
|
|
return $filename; |
|
|
|
}; |
|
|
|
|
|
|
|
$downloadPath = function (Options $options) { |
|
|
|
return mb_substr($options['upload_dir'], mb_strlen($this->projectDir.'/public/')); |
|
|
|
}; |
|
|
|
|
|
|
|
$allowAdd = static function (Options $options) { |
|
|
|
return $options['multiple']; |
|
|
|
}; |
|
|
|
|
|
|
|
$dataClass = static function (Options $options) { |
|
|
|
return $options['multiple'] ? null : File::class; |
|
|
|
}; |
|
|
|
|
|
|
|
$emptyData = static function (Options $options) { |
|
|
|
return $options['multiple'] ? [] : null; |
|
|
|
}; |
|
|
|
|
|
|
|
$resolver->setDefaults([ |
|
|
|
'upload_dir' => $this->projectDir.'/public/uploads/files/', |
|
|
|
'upload_new' => $uploadNew, |
|
|
|
'upload_delete' => $uploadDelete, |
|
|
|
'upload_filename' => $uploadFilename, |
|
|
|
'upload_validate' => $uploadValidate, |
|
|
|
'download_path' => $downloadPath, |
|
|
|
'allow_add' => $allowAdd, |
|
|
|
'allow_delete' => true, |
|
|
|
//'data_class' => $dataClass, |
|
|
|
'data_class' => $this->entityManager->getEntityName(FileInterface::class), |
|
|
|
'empty_data' => $emptyData, |
|
|
|
'multiple' => false, |
|
|
|
'required' => false, |
|
|
|
'error_bubbling' => false, |
|
|
|
'allow_file_upload' => true, |
|
|
|
]); |
|
|
|
|
|
|
|
$resolver->setAllowedTypes('upload_dir', 'string'); |
|
|
|
$resolver->setAllowedTypes('upload_new', 'callable'); |
|
|
|
$resolver->setAllowedTypes('upload_delete', 'callable'); |
|
|
|
$resolver->setAllowedTypes('upload_filename', ['string', 'callable']); |
|
|
|
$resolver->setAllowedTypes('upload_validate', 'callable'); |
|
|
|
$resolver->setAllowedTypes('download_path', ['null', 'string']); |
|
|
|
$resolver->setAllowedTypes('allow_add', 'bool'); |
|
|
|
$resolver->setAllowedTypes('allow_delete', 'bool'); |
|
|
|
|
|
|
|
$resolver->setNormalizer('upload_dir', function (Options $options, string $value): string { |
|
|
|
if (\DIRECTORY_SEPARATOR !== mb_substr($value, -1)) { |
|
|
|
$value .= \DIRECTORY_SEPARATOR; |
|
|
|
} |
|
|
|
|
|
|
|
if (0 !== mb_strpos($value, $this->projectDir)) { |
|
|
|
$value = $this->projectDir.'/'.$value; |
|
|
|
} |
|
|
|
|
|
|
|
if ('' !== $value && (!is_dir($value) || !is_writable($value))) { |
|
|
|
throw new InvalidArgumentException(sprintf('Invalid upload directory "%s" it does not exist or is not writable.', $value)); |
|
|
|
} |
|
|
|
|
|
|
|
return $value; |
|
|
|
}); |
|
|
|
$resolver->setNormalizer('upload_filename', static function (Options $options, $fileNamePatternOrCallable) { |
|
|
|
if (\is_callable($fileNamePatternOrCallable)) { |
|
|
|
return $fileNamePatternOrCallable; |
|
|
|
} |
|
|
|
|
|
|
|
return static function (UploadedFile $file) use ($fileNamePatternOrCallable) { |
|
|
|
return strtr($fileNamePatternOrCallable, [ |
|
|
|
'[contenthash]' => sha1_file($file->getRealPath()), |
|
|
|
'[day]' => date('d'), |
|
|
|
'[extension]' => $file->guessClientExtension(), |
|
|
|
'[month]' => date('m'), |
|
|
|
'[name]' => pathinfo($file->getClientOriginalName(), \PATHINFO_FILENAME), |
|
|
|
'[randomhash]' => bin2hex(random_bytes(20)), |
|
|
|
'[slug]' => (new AsciiSlugger()) |
|
|
|
->slug(pathinfo($file->getClientOriginalName(), \PATHINFO_FILENAME)) |
|
|
|
->lower() |
|
|
|
->toString(), |
|
|
|
'[timestamp]' => time(), |
|
|
|
'[uuid]' => Uuid::v4()->toRfc4122(), |
|
|
|
'[ulid]' => new Ulid(), |
|
|
|
'[year]' => date('Y'), |
|
|
|
]); |
|
|
|
}; |
|
|
|
}); |
|
|
|
$resolver->setNormalizer('allow_add', static function (Options $options, string $value): bool { |
|
|
|
if ($value && !$options['multiple']) { |
|
|
|
throw new InvalidArgumentException('Setting "allow_add" option to "true" when "multiple" option is "false" is not supported.'); |
|
|
|
} |
|
|
|
|
|
|
|
return $value; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* {@inheritdoc} |
|
|
|
*/ |
|
|
|
public function mapDataToForms($currentFiles, $forms): void |
|
|
|
{ |
|
|
|
/** @var FormInterface $fileForm */ |
|
|
|
$fileForm = current(iterator_to_array($forms)); |
|
|
|
$fileForm->setData($currentFiles); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* {@inheritdoc} |
|
|
|
*/ |
|
|
|
public function mapFormsToData($forms, &$currentFiles): void |
|
|
|
{ |
|
|
|
/** @var FormInterface[] $children */ |
|
|
|
$children = iterator_to_array($forms); |
|
|
|
$uploadedFiles = $children['path']->getData(); |
|
|
|
|
|
|
|
/** @var FileUploadState $state */ |
|
|
|
$state = $children['path']->getParent()->getConfig()->getAttribute('state'); |
|
|
|
$state->setCurrentFiles($currentFiles); |
|
|
|
$state->setUploadedFiles($uploadedFiles); |
|
|
|
$state->setDelete($children['delete']->getData()); |
|
|
|
|
|
|
|
if (!$state->isModified()) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if ($state->isAddAllowed() && !$state->isDelete()) { |
|
|
|
$currentFiles = array_merge($currentFiles, $uploadedFiles); |
|
|
|
} else { |
|
|
|
$currentFiles = $uploadedFiles; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* {@inheritdoc} |
|
|
|
*/ |
|
|
|
public function transform($data) |
|
|
|
{ |
|
|
|
return $data; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* {@inheritdoc} |
|
|
|
*/ |
|
|
|
public function reverseTransform($data) |
|
|
|
{ |
|
|
|
return null === $data ? '' : $data; |
|
|
|
} |
|
|
|
} |