ImageField: bug with Symfony Image constraint
Describe the bug Hi, I'm using EasyAdmin on a side project, and I decided to use an ImageField on a form to upload... well, an image. That being done, I tried to use it and it was working just fine, until I tried to put a constraint on the ImageField in the CrudController. Once you put on constraint on it, to prevent users to from uploading other types of files, you get the error 'The file could not be found.'. It is even impossible to create the entity.
To Reproduce
- Create an entity with an Image property (string) and make a CRUD controller for it.
- In the CrudController, try to use the Image constraint from Symfony.
(OPTIONAL) Additional context This is what I've done:
ImageField::new('image')
->setBasePath('uploads/post-images')
->setUploadDir('public/uploads/post-images')
->setUploadedFileNamePattern('[slug]-[timestamp].[extension]')
->setFormTypeOptions([
'required' => false,
'constraints' => [
new Image(),
],
]),
I think using the ImageField should be enough. We shouldn't have to add an Image constraint, should we?
Well explained! Based on this, I think this issue has 2 sub-issues:
- ImageField should allow uploading only images out of the box
- ImageField should allow adding
Imageconstraint to add more strict limitations for specific cases
Hi, in case someone else tries to add a mime validation to the field type "ImageField". The main problem is that the field type "ImageField" only passes the file name as a value to the validator instead of the object. Therefore I created my own constraint which first loads the object out of the context and then passes it to the Symfony validator. With this it works for me now.
Versions: Symfony: 6.1 Eeasyadmin: 4.3.2
CrudController
ImageField::new('image')
->setBasePath('uploads/post-images')
->setUploadDir('public/uploads/post-images')
->setUploadedFileNamePattern('[slug]-[timestamp].[extension]')
->setFormTypeOption(
'constraints',
[
new \App\Validator\Constraints\EasyAdminFile([
'mimeTypes' => [ // We want to let upload only jpeg or png
'image/jpeg',
'image/png',
],
])
]
);
src/Validator/Constraint/EasyAdminFile.php
<?php
namespace App\Validator\Constraints;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @property int $maxSize
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class EasyAdminFile extends \Symfony\Component\Validator\Constraints\File
{
}
src/Validator/Constraint/EasyAdminFileValidator.php
<?php
namespace App\Validator\Constraints;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\Model\FileUploadState;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* This constraint is created for adding validation support to the easyAdmin field type "ImageField".
* The Symfony constraint file validation is expecting an object of type "UploadedFile" or "FileObject" for
* handling the validation but EasyAdmin only returned the filename.
* Therefore, we have to load the object first before calling the symfony file validator.
* Created for versions:
* symfony: 6.1
* easycorp/easyadmin-bundle: 4.3.2
*
* Class EasyAdminFileValidator
* @package App\Validator\Constraints
*/
class EasyAdminFileValidator extends \Symfony\Component\Validator\Constraints\FileValidator
{
/**
* @param mixed $value
* @param \Symfony\Component\Validator\Constraint $constraint
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof EasyAdminFile) {
throw new UnexpectedTypeException($constraint, EasyAdminFile::class);
}
if ($value !== null &&
$this->context->getObject() instanceof Form &&
$this->context->getObject()->getConfig() instanceof FormBuilder
) {
$config = $this->context->getObject()->getConfig();
/** @var FileUploadState $state */
$state = $config->getAttribute('state');
if (!$state instanceof FileUploadState ||
!$state->isModified()
) {
return;
}
// On the upload field we can set the option for multiple uploads, so we need to take care of this
foreach ($state->getUploadedFiles() as $index => $file) {
parent::validate($file, $constraint);
}
}
}
}
I still think it should work out-of-the-box in EA, but your workaround is valid, thanks for sharing it!
@javiereguiluz It will be great to add the validation of Image with ImageField :)
@Digi92 thanks for your implementation. I am getting following error message on using it, do you have any idea what is wrong?

In fact currently it sends two values including the file name first then the file second, just ignore the validation if it is not an instance of FileUploaded:
src/Validator/EasyadminImage.php :
<?php
namespace App\Validator;
use Symfony\Component\Validator\Constraints\Image;
/**
* @Annotation
*
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class EasyadminImage extends Image
{
}
src/Validator/EasyadminImageValidator.php :
<?php
namespace App\Validator;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\ImageValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
class EasyadminImageValidator extends ImageValidator
{
public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof EasyadminImage) {
throw new UnexpectedTypeException($constraint, EasyadminImage::class);
}
if ($value instanceof UploadedFile)
parent::validate($value, $constraint);
}
}
usage example :
ImageField::new('image', 'Icon')
->setColumns(4)
->setUploadDir('public' . DIRECTORY_SEPARATOR . 'uploaded' . DIRECTORY_SEPARATOR . 'images')
->setBasePath('uploaded' . DIRECTORY_SEPARATOR . 'images')
->setUploadedFileNamePattern('[slug]-[contenthash].[extension]')
->setHelp('Image .png, .jpg et jpeg uniquement au format 100 x 100 px')
->setFormTypeOption('constraints', [new EasyadminImage(null, null, null, ['image/png', 'image/jpg', 'image/jpeg'],
100, 300, 100, 300, 1, 1)])
I came to the same conclusion @abouross.
https://github.com/EasyCorp/EasyAdminBundle/issues/5227#issuecomment-1167821550
Just to say thanks to @Digi92 . Working solution on Symfony 5.4.22 and Easyadmin 4.6.1.
@javiereguiluz do you have any ideas on how this one could be fixed so we do not need a workaround? I plan to try and solve this issue, so looking for some feedback if there's one before I dive into this.