To insert data using Symfony with Doctrine, you need to follow these steps:

 

Create an Entity Class

First, you need to create an entity class that represents the table in your database. An entity class is a PHP class that defines the structure of the table and its properties. For example, let's say we want to create an entity class for a Product table with fields id, name, and price.

// src/Entity/Product.php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="products")
 */
class Product
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

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

    /**
     * @ORM\Column(type="decimal", precision=10, scale=2)
     */
    private $price;

    // Getters and Setters for properties (not shown here for brevity)
}

Create a Form

Symfony uses forms to handle data input and validation. Create a form that will be used to insert data into the Product entity.

// src/Form/ProductType.php

namespace App\Form;

use App\Entity\Product;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ProductType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('price');
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Product::class,
        ]);
    }
}

 

Create the Controller

Now, create a controller that handles the form submission and inserts the data into the database.

// src/Controller/ProductController.php

namespace App\Controller;

use App\Entity\Product;
use App\Form\ProductType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ProductController extends AbstractController
{
    /**
     * @Route("/product/create", name="product_create", methods={"GET","POST"})
     */
    public function createProduct(Request $request): Response
    {
        $product = new Product();
        $form = $this->createForm(ProductType::class, $product);

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

            return $this->redirectToRoute('product_list');
        }

        return $this->render('product/create.html.twig', [
            'form' => $form->createView(),
        ]);
    }
}

 

Create a Template: Create a Twig template to display the form.

{# templates/product/create.html.twig #}

{% extends 'base.html.twig' %}

{% block body %}
    <h1>Create a Product</h1>

    {{ form_start(form) }}
    {{ form_widget(form) }}
    <button type="submit">Save Product</button>
    {{ form_end(form) }}
{% endblock %}

 

Now, if you access the /product/create URL in your application, you should see a form where you can enter the product name and price. When you submit the form, the data will be inserted into the database using Doctrine.

 

Insert with joined one to many tables in symfony doctrine

Let's say we have two entities: Order and OrderItem, where each order can have multiple order items. The Order entity will have a one-to-many relationship with the OrderItem entity. Here's how you can insert data into both tables using Symfony with Doctrine:

Create the Order Entity

// src/Entity/Order.php

namespace App\Entity;

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

/**
 * @ORM\Entity
 * @ORM\Table(name="orders")
 */
class Order
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    // Other properties (e.g., customerName, orderDate, etc.)

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\OrderItem", mappedBy="order", cascade={"persist"})
     */
    private $orderItems;

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

    // Getters and Setters for properties (not shown here for brevity)

    /**
     * @return Collection|OrderItem[]
     */
    public function getOrderItems(): Collection
    {
        return $this->orderItems;
    }

    public function addOrderItem(OrderItem $orderItem): self
    {
        if (!$this->orderItems->contains($orderItem)) {
            $this->orderItems[] = $orderItem;
            $orderItem->setOrder($this);
        }

        return $this;
    }

    public function removeOrderItem(OrderItem $orderItem): self
    {
        if ($this->orderItems->contains($orderItem)) {
            $this->orderItems->removeElement($orderItem);
            // set the owning side to null (unless already changed)
            if ($orderItem->getOrder() === $this) {
                $orderItem->setOrder(null);
            }
        }

        return $this;
    }
}

 

Create the OrderItem Entity

// src/Entity/OrderItem.php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="order_items")
 */
class OrderItem
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string")
     */
    private $productName;

    /**
     * @ORM\Column(type="decimal", precision=10, scale=2)
     */
    private $price;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Order", inversedBy="orderItems")
     * @ORM\JoinColumn(nullable=false)
     */
    private $order;

    // Getters and Setters for properties (not shown here for brevity)

    public function getOrder(): ?Order
    {
        return $this->order;
    }

    public function setOrder(?Order $order): self
    {
        $this->order = $order;

        return $this;
    }
}

 

Create the Controller to Insert Data

// src/Controller/OrderController.php

namespace App\Controller;

use App\Entity\Order;
use App\Entity\OrderItem;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class OrderController extends AbstractController
{
    /**
     * @Route("/order/create", name="order_create", methods={"GET"})
     */
    public function createOrder(): Response
    {
        // Create a new Order
        $order = new Order();
        $order->setCustomerName('John Doe'); // Set other properties

        // Create OrderItems and associate them with the Order
        $orderItem1 = new OrderItem();
        $orderItem1->setProductName('Product 1');
        $orderItem1->setPrice(10.00);
        $order->addOrderItem($orderItem1);

        $orderItem2 = new OrderItem();
        $orderItem2->setProductName('Product 2');
        $orderItem2->setPrice(15.50);
        $order->addOrderItem($orderItem2);

        // Save the Order and OrderItems to the database
        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->persist($order);
        $entityManager->flush();

        return new Response('Order and OrderItems inserted successfully!');
    }
}

If you access the /order/create URL in your application, it will insert a new order and its associated order items into the database using Doctrine.

 

Insert with joined many to many tables in symfony form with twig and doctrine using transactions

Let's consider an example of two entities: Product and Category, where each product can belong to multiple categories, and each category can have multiple products. This creates a many-to-many relationship between the two entities. We will use Symfony forms, Twig templates, and Doctrine transactions to insert data into these tables.

Create the Product Entity

// src/Entity/Product.php

namespace App\Entity;

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

/**
 * @ORM\Entity
 * @ORM\Table(name="products")
 */
class Product
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

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

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Category", inversedBy="products")
     * @ORM\JoinTable(name="product_category")
     */
    private $categories;

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

    // Getters and Setters for properties (not shown here for brevity)

    /**
     * @return Collection|Category[]
     */
    public function getCategories(): Collection
    {
        return $this->categories;
    }

    public function addCategory(Category $category): self
    {
        if (!$this->categories->contains($category)) {
            $this->categories[] = $category;
        }

        return $this;
    }

    public function removeCategory(Category $category): self
    {
        if ($this->categories->contains($category)) {
            $this->categories->removeElement($category);
        }

        return $this;
    }
}

 

Create the Category Entity

// src/Entity/Category.php

namespace App\Entity;

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

/**
 * @ORM\Entity
 * @ORM\Table(name="categories")
 */
class Category
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

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

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Product", mappedBy="categories")
     */
    private $products;

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

    // Getters and Setters for properties (not shown here for brevity)

    /**
     * @return Collection|Product[]
     */
    public function getProducts(): Collection
    {
        return $this->products;
    }
}

 

Create the Controller

// src/Controller/ProductController.php

namespace App\Controller;

use App\Entity\Product;
use App\Form\ProductType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ProductController extends AbstractController
{
    /**
     * @Route("/product/create", name="product_create", methods={"GET", "POST"})
     */
    public function createProduct(Request $request, EntityManagerInterface $entityManager): Response
    {
        $product = new Product();
        $form = $this->createForm(ProductType::class, $product);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            // Start a Doctrine transaction to handle the insertion
            $entityManager->beginTransaction();

            try {
                $entityManager->persist($product);
                $entityManager->flush();

                // Commit the transaction if everything went well
                $entityManager->commit();

                return $this->redirectToRoute('product_list');
            } catch (\Exception $e) {
                // Rollback the transaction if an error occurred
                $entityManager->rollback();
                throw $e;
            }
        }

        return $this->render('product/create.html.twig', [
            'form' => $form->createView(),
        ]);
    }
}

 

Create the Form and Template

// src/Form/ProductType.php

namespace App\Form;

use App\Entity\Product;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ProductType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class)
            ->add('categories', CollectionType::class, [
                'entry_type' => CategoryType::class,
                'allow_add' => true,
                'allow_delete' => true,
                'by_reference' => false,
            ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Product::class,
        ]);
    }
}

 

Twig template

{# templates/product/create.html.twig #}

{% extends 'base.html.twig' %}

{% block body %}
    <h1>Create a Product</h1>

    {{ form_start(form) }}
    {{ form_row(form.name) }}

    <h2>Categories</h2>
    <ul id="categories-list" data-prototype="{{ form_widget(form.categories.vars.prototype)|e }}">
        {% for categoryForm in form.categories %}
            <li>{{ form_row(categoryForm) }}</li>
        {% endfor %}
    </ul>
    <button type="button" id="add-category">Add Category</button>

    <button type="submit">Save Product</button>
    {{ form_end(form) }}

    <script>
        var $addCategoryButton = $('#add-category');
        var $categoriesList = $('#categories-list');
        $addCategoryButton.on('click', function () {
            var prototype = $categoriesList.data('prototype');
            var index = $categoriesList.children().length;
            var newForm = prototype.replace(/__name__/g, index);
            $categoriesList.append(newForm);
        });
    </script>
{% endblock %}

If you access the /product/create URL in your application, you will see a form where you can enter the product name and add categories using the "Add Category" button. The form allows you to create a new product with multiple categories, and the data will be inserted into the products, categories, and product_category tables using Doctrine transactions.

Notice we are using some javascript here to add children categories to the main form. This script is missing code for removing already added but not submitted elements that you can include very easily.

If an error occurs during the insertion, the transaction will be rolled back, ensuring data consistency.