Вопрос

Currently in a bit of a pickle. I have 2 entities: Main and Sub, it is a OneToMany relationship (one main can have many subs) I made a collection of form embedded together. I first had a search form where a user can search a Main by one of its attributes, then it sends them to a page where there is a form with the searched Main, its attributes listed on the form but is disabled so users cannot edit them, and the enabled fields are from the embedded Sub form which users need to enter in for submission.

1) User searches Main by its attribute, i.e. "pono" (PO number)
2) User is redirected to a page that shows the row that he/she searched for with the listed (pono), (cano), (bano) - it is disabled so it cannot be edited 3) Enabled fields are empty and users must enter the information that would be submitted into the Sub entity.

In my Main entity

 /**
 * @var Sub
 * @ORM\OneToMany(targetEntity="Sub", mappedBy="mainId")
 */
protected $sub;

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

And my Sub entity:

 /**
 * @var integer
 *
 * @ORM\Column(name="main_id", type="integer")
*/
protected $mainId;

 /**
 * @ORM\ManyToOne(targetEntity="Main", inversedBy="sub", cascade={"persist"})
 * @ORM\JoinColumn(name="main_id", referencedColumnName="id")
 */
protected $main;

In my Main form:

 public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('pono', 'text', array(
                'label' => 'PO: ',
                'disabled' => true
            ))
        ->add('cano','text', array(
                'label' => 'CA: ',
                'disabled' => true
            ))
        ->add('bano', 'text', array(
                'label' => 'BA: ',
                'disabled' => true
            ))
        ->add('sub', 'collection', array('type' => new SubType()));
}

In my Sub form:

 public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('qty','integer', array(
                'label' => 'Qty: '
            ))
        ->add('location','text', array(
                'label' => 'Location: '
            ))
        ->add('priority','text', array(
                'label' => 'Priority: '
            ));
}

So on my controller

 public function submitItemAction(Request $request, $pono) {
    $em = $this->getDoctrine()->getManager();
    $entity = $em->getRepository('ItemBundle:Main')
        ->findOneByPono($pono);

    $cano = $entity->getCano();
    $bano = $entity->getBano();

    $main = new Main();
    $main->setPono($pono);
    $main->setCano($cano);
    $main->setBano($bano);

    $sub = new Sub();
    $sub->setMain($main);
    $main->getSub()->add($sub);

    $form = $this->createForm(new MainType(), $main, array(
            'method' => 'POST'
        ))
        ->add('submit','submit');

    $form->handleRequest($request);
    if($form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($sub);
        $em->flush();

        return $this->redirect($this->generateUrl('success'));

    }

Now when this is submitted, it's submitting BOTH Main and Sub. It's giving me a duplicate Main and the newly added Sub. I know it is what it's supposed to do, but I need it to only submit the Sub. I tried retrieving the id from Main with a $mainid = $entity->getId(); and putting it into $sub->setMainId($mainid) and I keep getting the error message that main_id cannot be null.

Any takers? Edit: Twig template:

{{ form_start(form) }}
            {{ form_label(form.pono) }}
            {{ form_widget(form.pono) }} <br>

            {{ form_label(form.cano) }}
            {{ form_widget(form.cano) }}<br>

            {{ form_label(form.bano) }}
            {{ form_widget(form.bano) }} <br>

            {% for sub in form.sub %}
                {{ form_label(sub.qty) }}
                {{ form_widget(sub.qty) }} <br>

                {{ form_label(sub.location) }}
                {{ form_widget(sub.location) }} <br>

                {{ form_label(sub.priority) }}
                {{ form_widget(sub.priority) }}<br>

            {% endfor %}
        {{ form_widget(form.submit) }}
        {{ form_end(form) }}
Это было полезно?

Решение

After looking at your code, I think it is possible to make it work, there are a few things you will need to fix. I will edit this answer in a few steps.. Also make a backup/commit of your code before you start changing it.

1) In your MAIN entity (add cascade persist)

 /**
 * @var Sub
 * @ORM\OneToMany(targetEntity="Sub", mappedBy="main", cascade={"persist"}) 
 */
protected $sub;

2) SUB entity:

Remove protected $mainId; and it's annotation.

Remove cascade={"persist"} from ManyToOne

3) Look at your controller action.

$sub = new Sub();
$sub->setMain($main);
$main->getSub()->add($sub);

Pay attention to the setMain() method. You do not want to do this in controller, but automatically in entity. And also you should add to collection manually, but make a method for it. So you will only have this:

$sub = new Sub();
$main->addSub($sub);

4) In MAIN entity add (you might need to import Sub):

public function addSub(Sub $sub) {
    $sub->setMain($this);
    $this->sub->add($sub);
    return $this;
}

You should also add other methods like removeSub(), removeSub(), getSub(). getSub() returns collection, while the first two will return $this.

5) Controller

Do not persist Sub, but Main. (Doctrine will cascade persistance to Sub)

$em->persist($main);

6) You will need to add 'by_reference' option to sub collection inside you Main Form Type.

->add('sub', 'collection', array('type' => new SubType(), 'by_reference' => false));

This will call the actual addSub() method and not call the add method directly.

7) I do not know why you make a new Main entity below.

$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ItemBundle:Main')
    ->findOneByPono($pono);

$cano = $entity->getCano();
$bano = $entity->getBano();

$main = new Main();
$main->setPono($pono);
$main->setCano($cano);
$main->setBano($bano); 

Try to change to:

$em = $this->getDoctrine()->getManager();
$main = $em->getRepository('ItemBundle:Main')
    ->findOneByPono($pono);

You probably should define Pono as unique.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top