1

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

3 Answers 3

0

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;
    }
Sign up to request clarification or add additional context in comments.

5 Comments

That's help me a little. I've declare addLevels function, but I forgot to declare setLevels function in my program entity. It's help me to save what programs name that is related to the levels. And still the same problem, it's only save the first and the last levels, only 2 levels that saved in database.
Then check if you declare setProgram method in the Level class
Check my updates.I had declare that method. Still can't receive more than 2 levels. Do I need to make a loop and check how many levels form field that have a value? If i had to do like that, where should I add that loop condition?
you can add a counter in setLevel or check in your controller with count($form->getData()->getLevel())
Maybe I make mistake in building the form, because when I count($form->getData()->getLevel()), it returns 2. I expected to return 3.
0

remove this code from the controllor

 $level = new Level();

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

1 Comment

if I remove those code, I can only save 1 level. maybe I have to do a loop, but I can't get the numbers of levels form field.
0

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.

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.