Symfony2保存嵌入集合表单

I got problem to save embedded collection form field. Let say I have program, and the program have many levels. In my form type:

ProgramType.php

<?php

namespace Eifl\AdminBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class ProgramType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('id','text',array(
                'label'=>'Program Code',
            ))
            ->add('program','text',array(
                'label'=>'Program Name',
            ))
            ->add('levels','collection', array(
                'type'=>new LevelType(),
                'allow_add'=>true,
                'allow_delete'=>true,
                'by_reference' => false,
            ))
            ->add('save','submit', array(
                'label'=>'Save',
            ));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Eifl\AdminBundle\Entity\Program',
        ));
    }

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

LevelType.php

<?php

namespace Eifl\AdminBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class LevelType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('level','text',array(
            'label'=>'Level Name',
        ));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Eifl\AdminBundle\Entity\Level',
        ));
    }

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

I made the form that can add a new collection level field using jquery, following the tutorial from this link, and the result of my form is same with the picture in this link.

Now my problem is I can't save more than 2 levels. The collection form only save 2 levels.

e.g. I want to save a program name as English, and after that I add 3 levels(basic,intermediate,advanced). The levels that saved successfully to database only the first level(basic) and the last level(Advanced). All I want is to save all the levels to database. Can anyone help me?

In addition, here is part of my controller:

DefaultController.php

public function programAction(Request $request)
{
    $program = new Program();
    $level = new Level();

    $program->getLevels()->add($level);
    $newProgram = $this->createForm(new ProgramType(),$program);
    $newProgram->handleRequest($request);

    if($newProgram->isValid()){
        $em = $this->getDoctrine()->getManager();
        $em->persist($program);
        $em->flush();

        return $this->redirect($this->generateUrl('eifl_admin_program'));
    }
    return $this->render('EiflAdminBundle:Default:program.html.twig',array("new_program_form"=>$newProgram->createView()));
}

UPDATE

Here is my entity class.

Program.php

<?php

namespace Eifl\AdminBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Program
 *
 * @ORM\Entity
 * @ORM\Table(name="tbl_program")
 */
Class Program
{
    /**
     * @ORM\Id
     * @ORM\Column(name="id", type="string")
     */
    protected $id;

    /**
     *@ORM\Column(name="program_name",type="string")
     */
    public $program;

    /**
     * @ORM\OneToMany(targetEntity="Eifl\AdminBundle\Entity\Level", mappedBy="program", cascade={"remove","persist"})
     */
    public $levels;

    public function __construct(){
        $this->levels = new ArrayCollection();
    }

    /**
     * @param string $id
     * @return string
     */
    public function setId($id)
    {
        $this->id = $id;

        return $this;
    }

    /**
     * Add Level
     *
     * @param \Eifl\AdminBundle\Entity\Level $levels
     * @return Program
     */
    public function addLevels(\Eifl\AdminBundle\Entity\Level $level) {
        $this->levels[] = $level;
        $levels->setProgram($this);

        return $this;
    }

    /**
     * set levels
     *
     * @param \Doctrine\Common\Collections\ArrayCollection $levels
     * @return levels
     */
    public function setLevels(\Doctrine\Common\Collections\ArrayCollection $levels) {
        foreach ($levels as $level) {
            $level->setProgram($this);
        }
        $this->levels = $levels;
    }

    public function removeLevels(\Eifl\AdminBundle\Entity\Level $level)
    {
        $this->levels->removeElement($level);
    }

    /**
     * @param string $program
     * @return string
     */
    public function setProgram($program)
    {
        $this->program = $program;

        return $this;
    }

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

    /**
     * @return string
     */
    public function getProgram()
    {
       return $this->program;
    }

    /**
     * @return string
     */
    public function getLevels()
    {
       return $this->levels;
    }
}

Level.php

<?php

namespace Eifl\AdminBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Level
 *
 * @ORM\Entity
 * @ORM\Table(name="tbl_level")
 */
Class Level
{
    /**
     * @ORM\Id
     * @ORM\Column(name="id", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     *@ORM\Column(name="level",type="string")
     */
    public $level;

    /**
     * @ORM\ManyToOne(targetEntity="Eifl\AdminBundle\Entity\Program", inversedBy="levels")
     * @ORM\JoinColumn(name="program", referencedColumnName="id")
     */
    public $program;

    /**
     * @param string $id
     * @return string
     */
    public function setId($id)
    {
        $this->id = $id;

        return $this;
    }

    /**
     * @param string $level
     * @return string
     */
    public function setLevel($level)
    {
        $this->level = $level;

        return $this;
    }

    /**
     * @param mixed $program
     * @return string
     */
    public function setProgram(\Eifl\AdminBundle\Entity\Program $program)
    {
        $this->program = $program;

        return $this;
    }

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

    /**
     * @return string
     */
    public function getLevel()
    {
        return $this->level;
    }

    /**
     * @return string
     */
    public function getProgram()
    {
        return $this->program;
    }
}

Check if you put addLevel and setLevel in your program entity

     /**
     * Add Level
     *
     * @param \Eifl\AdminBundle\Entity\Level $levels
     * @return Program
     */
    public function addLevel(\Eifl\AdminBundle\Entity\Level $levels) {
        $this->levels[] = $levles;

        $level->setProgram($this);

        return $this;
    }

    /**
     * set levels
     *
     * @param \Doctrine\Common\Collections\ArrayCollection $levels
     * @return levels
     */
    public function setLevels(\Doctrine\Common\Collections\ArrayCollection $levels) {
        foreach ($levles as $level) {
            $level->setPogram($this);
        }
        $this->levels = $levels;
    }

remove this code from the controllor

 $level = new Level();

    $program->getLevels()->add($level);

Your getter and setter $levels in Entity Program are confused...

make :

public function addLevel(Level $level) { //without s
  $this->levels[] = $level;
}
public function removeLevel(Level $level) //without s
{
    $this->levels->removeElement($level);  
}
public function getLevels()
{
   return $this->levels;
}

Remove otherspublic function setLevels, public function removeLevels, etc

Like Adene Choubi said, $program->getLevels()->add($level); make no sense too.

Don't know if it's the only trouble but begin with that.