A
A
Alexey Alekseev2020-10-11 16:21:02
symfony
Alexey Alekseev, 2020-10-11 16:21:02

How to save a form that has a collection of another form embedded in it?

Hello! I've been struggling for a week now, I can not solve the problem, help someone with what they can)).

There are 2 tables:
1. Customers
2. Phone

The Customers table is related to the Phone table in a one-to-many relationship.

In accordance with the manual https://symfony.com/doc/3.4/form/form_collections.html
implemented embedding another form collection into my form.

The problem is that when saving the form, an error occurs when inserting a record into the associated table, because at the time of saving, Customer has not yet been created, and the Pnone table requires the client's customer_id:

An exception occurred while executing 'INSERT INTO phone (phone, description, customer_id) VALUES (?, ?, ?)' with params ["+7 (132) 143-24-12", "My note", null]:

SQLSTATE[23000]: [Microsoft][ODBC Driver 11 for SQL Server][SQL Server]Cannot insert the value NULL into column 'customer_id', table 'CustomersBase.dbo.phone'; column does not allow nulls. INSERT fails.

How can this problem be solved? thank!

Below is the shortened code:

// src/AppBundle/Entity/Customers.php

/**
 * Customers
 *Заказчики
 * @ORM\Table(name="Customers")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\CustomersRepository")
 */
class Customers implements UserInterface
{
    /**
     * @var integer
     *
     * @ORM\Column(name="CustomerID", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $customerid;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Phone", mappedBy="customer_id", cascade={"persist", "remove", "merge"})
     */
    private $phone;

    public function __construct()
    {
        $this->phone = new ArrayCollection(); //Создаем коллекцию телефонов (связанная таблица phone)
    }

    public function getPhone()
    {
        return $this->phone;
    }

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


// src/AppBundle/Entity/Phone.php

**
 * Phone
 *
 * @ORM\Table(name="phone", indexes={@ORM\Index(name="IDX_444F97DD9395C3F3", columns={"customer_id"})})
 * @ORM\Entity
 */
class Phone
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var \AppBundle\Entity\Customers
     *
     * @ORM\ManyToOne(targetEntity="Customers", inversedBy="customerid")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="customer_id", referencedColumnName="CustomerID")
     * })
     */
    private $customer_id;

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

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

    /**
     * @return \AppBundle\Entity\Customers
     */
    public function getCustomerId()
    {
        return $this->customer_id;
    }

    /**
     * @param \AppBundle\Entity\Customers $customer
     */
    public function setCustomerId(\AppBundle\Entity\Customers $customer)
    {
        $this->customer_id = $customer;
    }
}


// src/AppBundle/Form/CustomerType.php

class CustomerType extends AbstractType
{
   public function buildForm(FormBuilderInterface $builder, array $options)
    {
        //....
        $builder
            ->add('phone',CollectionType::class, array(
                'entry_type' => PhoneType::class,
                'allow_add' => true,
                'allow_delete' => true,
                'delete_empty' => true,
                'entry_options' => array(
                    'required' => false,
                    'label' => false
                )
            ));
          //....
   }
    
public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Customers'
        ));
    }


// src/AppBundle/Form/PhoneType.php

class PhoneType extends AbstractType
{


    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('phone', null);
        $builder->add('description', null);
        $builder->add('customerId', HiddenType::class);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Phone',
        ));
    }
}


// src/AppBundle/Controller/CustomersController.php

class CustomersController extends Controller
{
    public function indexAction(Request $request)
    {

        $customer = new Customers();
        //Добавляем пустой телефон, чтобы отобразить его в форме
        $phone = new Phone();
        $customer->getPhone()->add($phone);

        $form = $this->createForm('AppBundle\Form\CustomerType', $customer);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($customer);
            $em->flush();
     }
}

}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
B
BoShurik, 2020-10-12
@remlin1000

Your link suggests a solution:

// src/AppBundle/Form/CustomerType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
    //....
    $builder
        ->add('phones',CollectionType::class, array(
            'by_reference' => false,
            // ...
        ));
    //....
}

class Customers implements UserInterface
{
    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Phone", mappedBy="customer_id", cascade={"persist", "remove", "merge"})
     */
    private $phones; // Это же коллекция, нужно множественное число, чтобы работали adder и remover

    public function addPhone(Phone $phone)
    {
        $phone->setCustomer($this);
        $this->phones->add($phone);
    }

    public function removePhone(Phone $phone)
    {
        $phone->setCustomer(null);
        $this->phones->removeElement($phone);
    }
}

// src/AppBundle/Form/PhoneType.php
// $builder->add('customerId', HiddenType::class); // не нужен

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question