1
votes

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:

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?

3

3 Answers

2
votes

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);
        }
    ))
;
1
votes

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;
}
0
votes

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!!