Doctrine. Сохранение связных сущностей One To Many в таблицы БД в фреймворке Symfony.

Сохранение связанных сущностей в Symfony 5.

У вас в проекте написанном на фреймворке Symfony, имеются связные между собой Entity, которые с помощью Doctrine можно сохранить в БД в связанных таблицах. Например у вас могут быть отношения Многие к Одному (Many To One). Сделать это очень легко.

Для примера код ниже представлен внутри контроллера:

// ...

use App\Entity\Category;
use App\Entity\Product;
use Symfony\Component\HttpFoundation\Response;

class ProductController extends AbstractController
{
    /**
     * @Route("/product", name="product")
     */
    public function index()
    {
        $category = new Category();
        $category->setName('Computer Peripherals');

        $product = new Product();
        $product->setName('Keyboard');
        $product->setPrice(19.99);
        $product->setDescription('Ergonomic and stylish!');

        // relates this product to the category
        $product->setCategory($category);

        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->persist($category);
        $entityManager->persist($product);
        $entityManager->flush();

        return new Response(
            'Saved new product with id: '.$product->getId()
            .' and new category with id: '.$category->getId()
        );
    }
}

В примере кода, выше, когда вы переходите к роуту в приложении /product, в таблицы категорий и продуктов добавляется одна строка. Столбцу product.category_id для нового продукта присваивается любой идентификатор новой категории. Доктрина управляет сохранением этих отношений для вас:

Если вы новичок с работой ORM Doctrine, то это самая сложная концепция: вам нужно перестать думать о своей базе данных, а вместо этого думать только о своих объектах. Вместо установки целочисленного идентификатора категории в Product, вы устанавливаете весь объект Category. Доктрина позаботится об остальном при сохранении.

Сохранение значений для связи Many To One.

В примере кода выше были обновлены данные в таблицах между связными сущностями, вызвав $product->setCategory($category). При этом каждое отношение имеет две стороны: в этом примере Product.category является владельцем, а Category.products является обратной стороной.

Чтобы обновить отношения в базе данных, вы должны установить отношения на стороне владельца. Сторона-владелец всегда находится там, где установлено отображение ManyToOne (для отношения ManyToMany вы можете выбрать, какая сторона является стороной-владельцем).

В классе сущности, с помощью аннотации, сторона-владелец будет выглядеть, например так:

class Product
{
    // ...

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="products")
     */
    private $category;

    public function getCategory(): ?Category
    {
        return $this->category;
    }

    public function setCategory(?Category $category): self
    {
        $this->category = $category;

        return $this;
    }
}

Означает ли это, что невозможно обновить $category->addProduct() или $category->removeProduct() для обновления базы данных? На самом деле, это возможно благодаря некоторому умному коду, который был сгенерирован командой bin/console make:entity:

// src/Entity/Category.php

// ...
class Category
{
    // ...

    public function removeProduct(Product $product): self
    {
        if ($this->products->contains($product)) {
            $this->products->removeElement($product);
            // set the owning side to null (unless already changed)
            if ($product->getCategory() === $this) {
                $product->setCategory(null);
            }
        }

        return $this;
    }
}

Благодаря этому, если вы вызовете $category->removeProduct($product) , для category_id этого продукта будет установлено значение null в базе данных.

Но вместо того, чтобы установить для category_id значение null, что, если вы хотите, чтобы Продукт был удален, если он становится «осиротевшим» (т.е. без категории)? Чтобы выбрать это поведение, используйте параметр orphanRemoval внутри категории:

// src/Entity/Category.php

// ...

/**
 * @ORM\OneToMany(targetEntity="App\Entity\Product", mappedBy="category", orphanRemoval=true)
 */
private $products;

Благодаря указанию orphanRemoval=true в аннотации, теперь если продукт будет удален из категории, он будет полностью удален из базы данных.

Добавить комментарий

Ваш адрес email не будет опубликован.