There is a bi-directional relation between Sale, Stock and Catalog. Sales and Stock, should have an catalog entry. But this is not always the case at the moment ... So the relations are 'nullable'.
class Sale {
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Stock", inversedBy="sales")
*/
private $stock;
public function getCatalog(): ?Catalog
{
return $this->catalog;
}
public function setCatalog(?Catalog $catalog): self
{
$this->catalog = $catalog;
return $this;
}
}
class Stock
{
/**
* @ORM\OneToOne(targetEntity="App\Entity\Catalog", inversedBy="stock")
*/
private $catalog;
public function getCatalog(): ?Catalog
{
return $this->catalog;
}
public function setCatalog(?Catalog $catalog): self
{
$this->catalog = $catalog;
return $this;
}
}
class Catalog
{
/**
* @ORM\OneToMany(targetEntity="App\Entity\Sale", mappedBy="catalog")
*/
private $sales;
/**
* @ORM\OneToOne(targetEntity="App\Entity\Stock", mappedBy="catalog")
*/
private $stock;
public function addSale(Sale $sale): self
{
if (!$this->sales->contains($sale)) {
$this->sales[] = $sale;
$sale->setCatalog($this);
}
return $this;
}
public function removeSale(Sale $sale): self
{
if ($this->sales->contains($sale)) {
$this->sales->removeElement($sale);
// set the owning side to null (unless already changed)
if ($sale->getCatalog() === $this) {
$sale->setCatalog(null);
}
}
return $this;
}
public function getStock(): ?Stock
{
return $this->stock;
}
public function setStock(?Stock $stock): self
{
$this->stock = $stock;
// set (or unset) the owning side of the relation if necessary
$newCatalog = $stock === null ? null : $this;
if ($newCatalog !== $stock->getCatalog()) {
$stock->setCatalog($newCatalog);
}
return $this;
}
}
All this is auto generated in Symfony with make:entity. When organizing the Catalog, it is also neccessary to delete Catalog Entries.
class CatalogController extends AbstractController
{
/**
* @Route(
* path = "/catalog-delete/{id<[1-9]\d*>}",
* name = "catalog_delete",
* methods = {"GET"}
* )
*/
public function delete(int $id)
{
// get catalog
$catalog = $this->catalogRepository->find($id);
if (!$catalog) {
throw $this->createNotFoundException($this->translator->trans('system.error.notfound') . $id);
}
// delete
$this->entityManager->remove($catalog);
$this->entityManager->flush();
return $this->redirectToRoute('catalog_list');
}
}
Pretty simple so far. But how do I delete the associations, without deleting any Stocks or Sales? I do get here errors like this (without deleting associations)
Cannot delete or update a parent row: a foreign key constraint fails (`symfony`.`sale`, CONSTRAINT `FK_E54BC005DCD6110` FOREIGN KEY (`stock_id`) REFERENCES `stock` (`id`))
or like
Call to a member function getCatalog() on null
When I try inside function delete() ;)
$catalog->setStock(null);
foreach($catalog->getSales() as $sale) {
$catalog->getSales()->removeElement($sale); // ????????
}
I can use DQL to set the category_id in Sales and Stock to null (UPDATE sale/stock SET category_id = null WHERE category_id = X). But I think this not the common 'orm way'.
For this case, the auto generated function are a litte bit weired for me Also the doctrine documentation here https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/working-with-associations.html#removing-associations
I had read, that only the owning side is responsible for the association, but how do I get in my function Stock and all Sales, if there are any?
Sorry for the long question and a basic topic.
Thank you & best regards
My Questions was marked as duplicate. The main difference is
I would like to know in my question, how to implement the function calls to set owned entitys (two or multiple) to null. The delete process. Which entity, what kind of calls. Only adding
@ORM\JoinColumn(name="catalog_id", referencedColumnName="id", onDelete="SET NULL")
(the old answer) do not solve the problem.
--------- DQL WORKAROUND ----------
// Controller
/**
* @Route(
* path = "/catalog-delete/{id<[1-9]\d*>}",
* name = "catalog_delete",
* methods = {"GET"}
* )
*/
public function delete(int $id)
{
// get catalog
$numDeleted = $this->catalogRepository->delete($id);
if (!$numDeleted) {
throw $this->createNotFoundException($this->translator->trans('system.error.notfound') . $id);
}
return $this->redirectToRoute('catalog_list');
}
// Repository
/**
* Delete with associations
*/
public function delete(int $id): int
{
$this->getEntityManager()
->createQuery(/** @lang DQL */'
UPDATE App\Entity\Sale s
SET s.catalog = NULL
WHERE s.catalog = :id
')
->setParameter('id', $id)
->execute()
;
$this->getEntityManager()
->createQuery(/** @lang DQL */'
UPDATE App\Entity\Stock s
SET s.catalog = NULL
WHERE s.catalog = :id
')
->setParameter('id', $id)
->execute()
;
$numDeleted = $this->getEntityManager()
->createQuery(/** @lang DQL */'
DELETE FROM App\Entity\Catalog c
WHERE c.id = :id
')
->setParameter('id', $id)
->execute()
;
return $numDeleted;
}
my longest post ever ;)