It looks like there is no direct way to save the outcome of <input type="email" multiple>
into Doctrine's simple_array
field, through Symfony 2 forms.
Details:
simple_array
: http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html#simple-array$builder->add('emails', EmailType::class, array('attr'=>array('multiple'=>'multiple')));
<input type="email" multiple="multiple">
Now, when I enter two email addresses in the form (comma-separated, as expected by HTML5), the entity receives a comma-separated string.
However, when persisting into the simple_array
field, Doctrine expects an array, onto which it calls implode()
.
So the error message I get is: Warning: implode(): Invalid arguments passed
Reason: Symfony doesn't explode the comma-separated string into an array, before handing it over to Doctrine.
Solution: Do it manually:$entity->setEmails(explode(',', $entity->getEmails()));
So finally my question is: Is there an easier way for this?
After the answers of @Max P. and @jeremy:
Both methods work in principle! However, they break validation (see comments).
So here's what I finally came up with to enable validation:
Following http://symfony.com/doc/current/validation/custom_constraint.html
// src/AppBundle/Validator/Constraints/Array255Validator.php
class Array255Validator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
$string = implode(',', $value);
if (strlen($string) > 255) {
$this->context->buildViolation($constraint->message)
->setParameter('%string%', $string) // use $string here, since $value is an array!
->addViolation();
}
}
}
You can even apply validation to each array element, by using the All
constraint: http://symfony.com/doc/current/reference/constraints/All.html
properties:
email:
- AppBundle\Validator\Constraints\Array255: ~
- All:
- NotBlank: ~
- Length:
min: 5
- Email:
checkMX: true
message: "Some message for {{ value }}"
Thanks!!
I can suggest model transformer for this form field. Transformer will convert value from array to string for form and from string to array for doctrine.
http://symfony.com/doc/current/form/data_transformers.html
$builder->add('emails', EmailType::class, array('attr'=>array('multiple'=>'multiple')));
$builder->get('emails')
->addModelTransformer(new \Symfony\Component\Form\CallbackTransformer(
function ($original) {
return implode(',', $original);
},
function ($submitted) {
return explode(',', $submitted);
}
))
;
Maybe you can do it inside the setter of the Entity, by testing if the parameter given is a string or an array
public function setEmails($emails)
{
if (is_string($emails)) {
$emails = explode(',', $emails);
}
$this->emails = $emails;
}