I got a blog plateform, with an entity Category
this entity has associated to it
as the file is very small and mime-type assured to be always png, I've decided to store the file content as a Base64 encoded string in the entity/database
this way the page can be rendered at once without needing to do extra request for very small files (same for the API call GET /api/categories
). for pre-loaded data it works pretty well. The problem come when I want to edit one category
I've created a form with a file type for the icon
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new FileToBase64Transformer();
$iconField = $builder->create('iconColor', 'file', ['required' => false]);
$iconField->addModelTransformer($transformer);
$builder
->add('title')
->add($iconField)
;
}
the data transformer being
class FileToBase64Transformer implements DataTransformerInterface
{
public function transform($base64)
{
return null;
}
public function reverseTransform($file)
{
if (is_null($file)) {
return null;
}
return base64_encode(file_get_contents($file));
}
}
but when i submit the form with a valid image, the form fails in the profiler, in form section i can see
Symfony\Component\Validator\ConstraintViolation Object(Symfony\Component\Form\Form).data.icon = THE_BASE_64_OF_THE_FILE
is it because the data is transformed before the validation happpens ?
my current solution is to have two fields for the icon in my entity
/**
* @Constraints\Image(
* maxWidth = 40,
* maxHeight = 40,
* allowSquare = true,
* mimeTypes = "image/png",
* )
*/
private $iconFile = null;
/**
* Base64 of the icon in color version
*
* @var string
*
* @ORM\Column(name="icon_color", type="text", nullable=true)
*/
private $icon = null;
(with the appropriate getter and setter)
then to have my data transformer for the WHOLE class Category
class FileToBase64Transformer implements DataTransformerInterface
{
/**
* Transforms an object (file) to a base64.
*
* @param $file
* @return string
*/
public function transform($channel)
{
return $channel;
}
/**
* reverse transforms
*
*/
public function reverseTransform($categoryl)
{
$iconFile = $category->getIconFile();
if (!is_null($iconFile)) {
$channel->setIcon(
base64_encode(file_get_contents($iconFile))
);
}
return $channel;
}
}
and then in my CategoryType to associate the data transformer to the whole channel
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new FileToBase64Transformer();
$builder
->add('title')
->add('theme_color')
->add('type')
->add('iconFile')
->addModelTransformer($transformer)
;
}
the validation still happen after the data transform, but now it's no more a problem , as the entity will not be persisted if the form is not valid