Kdyby/Doctrine 2 pár otázok

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
iNviNho
Člen | 352
+
0
-

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
+
+1
-

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
+
+2
-
  1. ano, pro spojovaci tabulku user_role nemusis vytvaret entitu – staci nadefinovat m:n asociaci
  2. 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
+
0
-

@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)

iNviNho
Člen | 352
+
0
-

Ano presne to sa mi stalo, ze som vytvoril usra a chcel mu pridat cez getRoles()->add() dane role, ale ladenka napisala ze getRoles vrati null pri novom vytvorenom objekte. Zvlastne … :) dakujem za odpovede

iNviNho
Člen | 352
+
0
-

Este ma napadlo, ze davali ste uz niekedy cez konstruktor do entity nejaku inu sluzbu? Konkretne som chcel vyriesit src obrazkov aby som tam nemusil pisat basePath, tak by som pri pouziti $img->getPath() dostal cestu aj s basepathom

greeny
Člen | 405
+
0
-

Entita by neměla mít přístup k žádné službě, entita reprezentuje jen přepravku na data. Buď tam ten basePath dostaň když tu entitu ukládáš v nějaké službě a nebo naopak službu co ti bude vracet cestu i s basePath pro danou entitu :)

iNviNho
Člen | 352
+
0
-

Myslel som si :(

Ukladanie multimédií rieši MultimediaService, takže asi tam teda no .) Chcel som len odbremeniť databázu :D

Ok Ďakujem!

Editoval iNviNho (15. 12. 2015 11:09)

David Matějka
Moderator | 6445
+
+2
-

@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
+
0
-

@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
+
0
-

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
+
+1
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

pro jednoduchy pripady je metoda findPairs v repository: https://github.com/…epository.md#…

iNviNho
Člen | 352
+
0
-

Jasné, o tej metode viem, lenže nechcem fetchovať User entitu, ale jej premennú $roles :-\