1

I have an Employee class which has a OneToMany relation to the PhoneNumber class, and I'm using form builders, and using prototypes to embed multiple phone numbers into the New Employee form, with javascript.

From dumping my employee variable, I see that each submitted PhoneNumber is represented as an array, when I suppose it should be converted to a PhoneNumber object when the submitted data is processed.

My entitites are:

/**
 * Employee
 *
 * @ORM\Table(uniqueConstraints={@UniqueConstraint(name="employee_username_idx", columns={"username"})})
 * @ORM\Entity(repositoryClass="Acme\BambiBundle\Entity\EmployeeRepository")
 */
class Employee
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var array
     *
     * @OneToMany(targetEntity="PhoneNumber", mappedBy="employee", cascade={"persist","remove"}, fetch="EAGER")
     **/
    private $phoneNumbers;

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->phoneNumbers = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add phoneNumbers
     *
     * @param \Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers
     * @return Employee
     */
    public function addPhoneNumber(\Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers)
    {
        $phoneNumbers->setEmployee($this);
        $this->phoneNumbers[] = $phoneNumbers;

        return $this;
    }

    /**
     * Remove phoneNumbers
     *
     * @param \Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers
     */
    public function removePhoneNumber(\Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers)
    {
        $this->phoneNumbers->removeElement($phoneNumbers);
    }

    /**
     * Get phoneNumbers
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getPhoneNumbers()
    {
        return $this->phoneNumbers;
    }

    // ...
}

and

/**
 * PhoneNumber
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class PhoneNumber
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="type", type="text", nullable=true)
     */
    private $type;

    /**
     * @var string
     *
     * @ORM\Column(name="number", type="text")
     */
    private $number;

    /**
     * @var Employee
     *
     * @ManyToOne(targetEntity="Employee", inversedBy="phoneNumbers")
     * @JoinColumn(name="employee_id", referencedColumnName="id", onDelete="CASCADE")
     **/
    private $employee;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set number
     *
     * @param string $number
     * @return PhoneNumber
     */
    public function setNumber($number)
    {
        $this->number = $number;

        return $this;
    }

    /**
     * Get number
     *
     * @return string 
     */
    public function getNumber()
    {
        return $this->number;
    }

    /**
     * Set employee
     *
     * @param \Acme\BambiBundle\Entity\Employee $employee
     * @return PhoneNumber
     */
    public function setEmployee(\Acme\BambiBundle\Entity\Employee $employee = null)
    {
        $this->employee = $employee;

        return $this;
    }

    /**
     * Get employee
     *
     * @return \Acme\BambiBundle\Entity\Employee 
     */
    public function getEmployee()
    {
        return $this->employee;
    }

    /**
     * Set type
     *
     * @param string $type
     * @return PhoneNumber
     */
    public function setType($type)
    {
        $this->type = $type;

        return $this;
    }

    /**
     * Get type
     *
     * @return string 
     */
    public function getType()
    {
        return $this->type;
    }
}

My form types are:

class EmployeeType extends AbstractType {
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->add('phoneNumbers', 'collection', array(
                'type' => new PhoneNumberType(),
                'allow_add' => true,
                'allow_delete' => true,
                'delete_empty' => true,
                'prototype_name' => 'phoneNumberPrototype',
                'by_reference' => false,
            ))
            // ...
            ->add('save', 'submit', array('attr' => array('class' => 'btn btnBlue')));
    }

    public function getName() {
        return 'employee';
    }
}

and

class PhoneNumberType extends AbstractType {
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->add('type', 'text', array('required' => false, 'label' => 'Type (optional)'))
            ->add('number', 'text');
    }

    public function getName() {
        return 'phoneNumber';
    }
}

Are there any things I could try to solve the problem? Is there anything that I am obviously doing wrong?

1 Answer 1

1

The solution was in a detail that I didn't know about - setting a data_class in the PhoneNumberType class:

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\BambiBundle\Entity\PhoneNumber',
        ));
    }

Without this, the code that processes the data from the submitted form does not know that each phone number should be converted to a PhoneNumber class, and thus they stay as arrays.

Please bear in mind that I am using Symfony 2.6. In Symfony 2.7 the above function is called configureOptions and has a slightly different definition:

    public function configureOptions(OptionsResolver $resolver) {
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.