Kdyby/Doctrine 2 pár otázok
- iNviNho
- Člen | 352
Ahojte, používať Kdyby/Doctrine 2 do Nette a mám pár otázočiek.
Otázka 1
Pri dekompozícií M:N asociácie mám naozaj v databáze 3 tabuľky, napr.
User, Role, User_role, ale podľa dokumentáciu ak ju chápem správne stačí
len definovať User a Role a správne asociácie?
Otázka 2
Čo presne znamená cascade={„persist“} alebo cascade={„persist“,
„remove“} ? Teda „remove“ asi znamená, že ak zmažem ja neviem
article, tak sa zmažú k nemu všetky komentáre, ale načo tam je presne
persist?
Otázka 3
Všimol som si, že v Doc sa zapisuje aj konštruktor na ArrayCollection pre
gropus .. Zatial som tento konštruktor nepísal a nemal som žiadny problém ..
Je to nutnosť?
<?php
/**
* @ManyToMany(targetEntity="Group", inversedBy="users")
* @JoinTable(name="users_groups")
*/
private $groups;
public function __construct() {
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
}
?>
Ďakujem!
Editoval iNviNho (14. 12. 2015 18:28)
- Jan Endel
- Člen | 1016
Otázka 1: Ano
Otázka 2: pokud je nastaven cascade persist, tak:
$article = new Article();
$comment1 = new Comment();
$comment2 = new Comment();
$article->addComment($comment1);
$article->addComment($comment2);
$entityManager->persist($article); // bez persist se do databaze ulozi jen clanek a ne komentare
$entityManager->flush();
Otazka 3:
to je pro inicializaci kolekce před jejím persistováním, pokud bys ho
neuváděl tak:
class Article()
{
/**
* @ManyToOne(targetEntity="Comments", inversedBy="article")
* @var ICollection|Comment[]
*/
private $comments;
public function addComment(Comment $comment)
{
$this->comments->add($comment);
}
}
$article = new Article();
$comment = new Comment();
$article->addComment($comment) // vyhodi chybu, NULL nema metodu add
po načtení article z databáze je v entitě PersistentCollection, takže ti to hned funguje.
- David Matějka
- Moderator | 6445
- ano, pro spojovaci tabulku user_role nemusis vytvaret entitu – staci nadefinovat m:n asociaci
- vsechny entity, ktere chces vlozit do databaze museji byt persistovane, coz je nejaky oznaceni, ze se ma pri flushi ulozit, treba
$user = new User;
$user->address = $address = new Address;
$em->persist($user);
$em->persist($address);
$em->flush();
Pokud tam uvedes u te asociace address v entite User cascade persist, tak staci persistovat User a entita u tehle asociace se automaticky persistuje.
3. Pokud bys vytvoril entitu a hned se snazil zavolat treba
$this->groups->add($group)
, tak to nebude fungovat, jelikoz
by tam bylo null
- David Matějka
- Moderator | 6445
@JanEndel jen detail
bez persist se do databaze ulozi jen clanek a ne komentare
Nevyhodi to nahorou „new entity was found through the relationship“? (ted si nejsem jistej, jestli je i u to_many asociace, nebo jen u to_one)
- David Matějka
- Moderator | 6445
@greeny
entita reprezentuje jen přepravku na data
To by se jednalo o anemicky model, ktery nemusi byt idealni
Buď tam ten basePath dostaň když tu entitu ukládáš
to neni mod dobre, basePath se muze lisit dle prostredi
@iNviNho to, co by mela entita delat, nejde rict obecne a je to casto otazkou sporu. Rozhodne by si mela udrzovat vnitrni konzistenci – tedy ruzne validace, napr. nedovolit publikovat clanek, ktery nema titulek.
Co se tyce zavislosti, muzes je tam dostat obvykle udalostmi postLoad a
prePersist, ale zamysli se, jestli je to soucasti toho domenoveho modelu.
Napriklad basePath, tedy pokud tim myslis tu basePath url, ktera je
reprezentovana $basePath
v sablone, tak o tom by asi entita vedet
nemela.
mrkni na tyhle thready pro nejakou inspiraci:
- iNviNho
- Člen | 352
@DavidMatějka
Jasné, ja mám službu DirService:
<?php
class DirService extends \Nette\Object {
private $wwwDir;
private $appDir;
private $basePath;
public function __construct($wwwDir, $appDir, \Nette\Http\Request $httpRequest) {
$this->wwwDir = $wwwDir;
$this->appDir = $appDir;
$baseUrl = $httpRequest ? rtrim($httpRequest->getUrl()->getBaseUrl(), '/') : NULL;
$this->basePath = preg_replace('#https?://[^/]+#A', '', $baseUrl) . "/";
}
}
?>
A ked ju predám MultimediaSaveru a ukladám image
<?php
$imageWithPath = $this->dirService->getBasePath() . $path . $newName; /** $path = "multimedia/multimedias/ */
$image->save($imageWithPath, 90);
?>
Potom v šablone funguje v pohode
<img src="{$m->getPath()}">
Ale problém je pri mazaní obrázku kedy unlink mi hádže
unlink(/is/multimedia/multimedias/54321michaelcorleone.jpg): No such file or directory
Ak pri ukladaní obrázku tam nevopchám $basePath tak ho musím potom ručne do šablony pchať
<img src="{$basePath}/{$m->getPath()}">
A unlink potom funguje tak ako má, tak to mám teraz
Skúšal som tam vopchať aj baseUri, ale to mi zase prehliadač nezobrazí obrázok, lebo nemá prístup do C:/xampp atd atd …
Dá sa to vyriešiť aj viacerými stlpcami v DB, ale ako som povedal, prí kvantách obrázkov každý stlpec navyše nie je optimálne a preto som chcel tu basepathu vopchať do Entity a spraviť na to nejaký getPathWithBasePath()
Editoval iNviNho (15. 12. 2015 13:32)
- iNviNho
- Člen | 352
A inak neviem prečo, ale aj bez cascade={„persist“} mi vkladá uživateľove role do DB, nie je to nejaký default?
<?php
/**
* @ORM\ManyToMany(targetEntity="Role", inversedBy="users")
*/
protected $roles;
public function addRole(Role $role) {
$this->roles[] = $role;
}
?>
A následne toto naozaj vloží aj nového usera aj jeho role či tam je cascade persist, alebo nie ..
<?php
foreach($v["role"] as $idRole) {
$role = $this->roleService->getById($idRole);
$user->addRole($role);
}
$this->userService->insert($user)
?>
- David Matějka
- Moderator | 6445
A inak neviem prečo, ale aj bez cascade={„persist“} mi vkladá uživateľove role do DB, nie je to nejaký default?
ano, relaci bude ukladat vzdy. tady jde o tu entitu, napriklad kdybys mel
$user->addRole(new Role());
tak s cascade persist se ta nova entita ulozi, bez toho ne (a asi i vyhodi chybu), takze bys musel explicitne persistovat
$user->addRole($role = new Role());
$em->persist($role);
V tvem prikladu ale entitu nevytvaris, vybiras z db existujici
- iNviNho
- Člen | 352
Pochopené a otestované, +1
David Matějka napsal(a):
A inak neviem prečo, ale aj bez cascade={„persist“} mi vkladá uživateľove role do DB, nie je to nejaký default?
ano, relaci bude ukladat vzdy. tady jde o tu entitu, napriklad kdybys mel
$user->addRole(new Role());
tak s cascade persist se ta nova entita ulozi, bez toho ne (a asi i vyhodi chybu), takze bys musel explicitne persistovat
$user->addRole($role = new Role()); $em->persist($role);
V tvem prikladu ale entitu nevytvaris, vybiras z db existujici
- David Matějka
- Moderator | 6445
A k tomu basePath. base path neni cesta k adresari na filesystemu a nemel bys to pouzivat pro praci se soubory, je to jen nejaka cast URL, kde se nachazi index aplikace, treba kdybys mel
http://localhost/sandbox/www/article/detail/1
tak basePath bude obsahovat neco jako /sandbox/www
- iNviNho
- Člen | 352
Aha, rozumiem, ok :)
Chcel by som sa ešte opýtať ako získam fetchPairnute uživateľove role pre checkboxlist? Nechcem role ako entity, ale iba ich IDčka … napr. nech výsledok vyzerá takto:
<?php
$roles = array(
0 => 1,
1 => 2
)
?>
Skúsil som
<?php
$query = $this->em->createQuery("select r.id from \App\Entities\Role r"
. " inner join r.users u where u.id = :id")
->setParameter("id", $id);
return $query->getScalarResult();
?>
Avšak to mi vracia
array (2)
0 => array (1)
id => "1"
1 => array (1)
id => "2"
Viem si to tak spraviť ďalším foreachom, ale to už bude dalších pár riadkov :) Niečo podobné ako findPairs()
Editoval iNviNho (15. 12. 2015 15:15)
- David Matějka
- Moderator | 6445
pro jednoduchy pripady je metoda findPairs v repository: https://github.com/…epository.md#…