Doctrine m:n uložení z inverzní strany
- Phalanx
- Člen | 310
Ahoj,
mám vazbu m:n, v podstatě stejné jako z dokumentace doctrine
<?php
<?php
class Article
{
private $tags;
public function addTag(Tag $tag)
{
$tag->addArticle($this); // synchronously updating inverse side
$this->tags[] = $tag;
}
}
class Tag
{
private $articles;
public function addArticle(Article $article)
{
$this->articles[] = $article;
}
}
?>
a nevím, jak mám z inverzní strany, tj. Tag v příkladu, ukládat záznamy.
Když dám
<?php
$tag->addArticle($article);
// persist tag
// flush tag
?>
tak se sice ukládají všechny ostatní hodnoty, ale tagy ne. Musím to navázat z druhé strany nebo se to dělá jinak?
Mockrát díky
Editoval Phalanx (22. 3. 2017 22:57)
- David Matějka
- Moderator | 6445
bezne to delam zhruba:
class Article
{
private $tags;
public function addTag(Tag $tag)
{
if (!$this->tags->contains($tag)) {
$this->tags->add($tag);
$tag->addArticle($this);
}
}
}
class Tag
{
private $articles;
public function addArticle(Article $article)
{
if (!$this->articles->contains($article)) {
$this->articles->add($article);
$article->addTag($this);
}
}
}
takze at to budes volat z jakekoliv strany, tak se obe aktualizuji
- Phalanx
- Člen | 310
Díky Davide, jenom mám ještě problém s tím, že articles->contains a articles->add hází Call to a member function add() on array
Našel jsem tohle, ale vůbec nevím co byla chyba
https://forum.nette.org/…an-exception
Protože getArticles a getTags mám definovány…
<?php
class Tag {
/**
* Many Articles have Many Tags.
* @var Articles[]|ArrayCollection
* @ORM\ManyToMany(targetEntity="Articles", mappedBy="tags")
*/
private $articles;
public function __construct()
{
$this->articles = new ArrayCollection;
}
/**
* @return Articles[]
*/
public function getArticles()
{
$active = Criteria::expr()->eq('published', true);
$criteria = Criteria::create()->where($active);
return $this->articles->matching($criteria);
}
}
?>
edit: a dělá mi to z obou stran
Editoval Phalanx (23. 3. 2017 6:56)
- Phalanx
- Člen | 310
@fizzy Díky za názor. Já se s Doctrine teprve seznamuju, ale tohle mi nepřijde jako správný krok. Kritérii potřebuju filtrovat hlavně smazané záznamy (soft delete), se kterými už nechci nadále pracovat.
Ale možná k tvému řešení někdy dospěju… :)
Editoval Phalanx (23. 3. 2017 7:31)
- fizzy
- Backer | 49
soft-delete taktiez sa neodporuca pouzivat :D inak na to je fajn rozsirenie do doctrine, ktore to filtruje automaticky: https://github.com/…neExtensions
- Phalanx
- Člen | 310
@fizzy Já vím, ale aplikace bez soft delete? To bych se fakt bál dát tu aplikaci komukoliv k používání… O rozšíření taky vím, ale řeším si je sám.
Mohl by mi prosím ještě někdo poradit jak s touhle chybou?
articles->contains a articles->add hází Call to a member function add()
on array
- Oli
- Člen | 1215
Ono soft delete opravdu není nejšťastnější řešení. Pokud
předpokládáš, že databáze může být velká (miliony záznamů), tak než
soft delete je lepší mít 2 databáze. Jednu „živou“ a jednu
„statistickou“. Takže všechno co se smaže přesuneš do
„statistické“ databáze. Typickej příklad:
Objednávky. Dokud není objednávka v konečným stavu (doručena,
stornována), tak je v „živé“ databázi. Pokud je doručena, tak se smaže
z živé databáze a přesune se do „statistické“.
Má minimálně 2 výhody:
- Nemusíš řešit soft delete věci, prostě vytáhneš všechno a nikdy nezapomeneš na příznak (isDelete).
- Je to o hodně rychlejší (místo milionů záznamů taháš pár tisíc)
Musíš se pak starat o 2 EntityManagery, ale není to problém. Jeden je defaultní a druhej (statistickej) si ručně autowiruješ kam potřebuješ. On stejně bude asi potřeba na celkem málo stránkách…
- Phalanx
- Člen | 310
@fizzy Díky za pomoc, už jsem to našel – https://forum.nette.org/…zni-strany-2#…
Měl sem tam ještě další práci s polem… Takže několik hodin zabitých na takové ptákovině.
A ohledně soft delete taky děkuju – přečtu si o tom více.
- kleinpetr
- Člen | 480
Resim ted jeden priklad a asi by se mi hodila rada
Priklad:
tabulka product(id, nazev, bla bla)
tabulka kategorie(id, nazev, hodnota1, hodnota2)
tabulka product_category(id_product, id_category)
a ted jde o to, ze mi parsuju nejaka externi data a prijde mi treba
produkt ventilator kategorie ventilatory + nejake dalsi info o kategorii
vysledek by mel byt takovy, zjistit zda dana kategorie uz existuje a pokud ano, tak porovnat a popripade updatnout hodnoty a nasledne ji pripradit k produktu. Pokud neexistuje, tak vytvorit a priradit k produktu.
Muj postup je ted takovy, ze kdyz prochazim data, tak kdyz narazim na kategorii, tak si vytvorim novou entitu a tu si predam do helperu, ktery zjisti zda takovy nazev uz existuje, porovna data a pokud jiz existovala, tak mi vrati tu entitu, a pokud neexistovala, tak persistne tu kterou jsem mu poslal a vrati ji.
Ono to funguje dobre, ale napada me, jestli tuto funkcnost nepridat spis Entite, tj. metoda addCategory($categoryEntity) v ProductEntity dostane nejakou novou entitu a uz se postara o zbytek, to zni asi jako spravny navrh, ale nevim jak v entite persistnu jinou entitu.
tzn. kdyz nastavim cascade=persist a v metode addCategory zjistim, ze takova kategorie neexistuje, tak po zavolani` $this->categories->add($newCategory); ` mi to vytvori automaticky zaznam do tabulky kategorie a zaroven zapise do relacni tabulky. To je OK
Ale kdyz v te metode zjistim, ze uz kategorie existuje, tak ji potrebuji updatnout data a potom persistnout, tudiz asi jedine si do entity natahnout entityManager, ale to se mi nechce, takze tenhle zpusob asi nebude uplne allright.
Editoval kleinpetr (23. 1. 2018 16:04)