Kdyby/Doctrine best practice
- Oli
- Člen | 1215
Ahoj,
snažím se přejít z Nette database k Doctrine 2 (Kdyby/Doctrine). Něco
jsem si o tom přečetl:
- Doctrine 2 od Honzy Tichýho
- Bezbolestná integrace Doctrine 2 ORM do Nette – Kdyby/Doctrine
- https://github.com/…/en/index.md
- Pět vrstev modelu.
Mám v tom ale docela hokej.
Například v Nette database bych si napsal něco jako:
public function getBySlug($slug)
{
return $this->connection->table('article')->where('slug = ?', $slug)->fetch();
}
Kam a jak napsat tohle pomocí Doctrine 2? Používá se na to standardně
->findBy(array());
nebo se to něčím někde obaluje? Kde bych
měl například napsat tu metodu getBySlug
? Přímo do tý entity?
Logické mě přijde podědit \Kdyby\Doctrine\EntityDao
a dat tu
metodu tam, ale HosipLan píše, že by se DAO
nemělo dědit.
Z toho plyne otázka kde a jak pracovat s entitou. Mělo by se s ní pracovat v presenteru?
public function actionDefault()
{
$articles = $this->em->getDao(\App\Article::getClassName());
$article = new \App\Article();
$article->title = "The Tigger Movie";
$articles->save($article);
}
Kde potom určím, kam se bude entita ukládat (např. cache)?
Zatím to mám takhle (ale nepřijde mě, že to je
správně):
config
doctrine:
user: *
password: *
dbname: *
metadata:
App: %appDir%
Article: annotations(%appDir%/model/entity)
services:
entityManager: @Kdyby\Doctrine\EntityManager
article: App\Article(@doctrine.dao(App\Article))
Article
namespace App;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Article extends \Kdyby\Doctrine\Entities\IdentifiedEntity
{
/**
* @ORM\Column(type="string")
*/
protected $title;
/**
*
* @ORM\Column(type="string")
*/
protected $slug;
/**
* @ORM\Column(type="string")
*/
protected $text;
}
Homapage
private $em;
public function __construct(\Kdyby\Doctrine\EntityManager $em)
{
$this->em = $em;
}
public function actionDefault()
{
$articles = $this->em->getDao(\App\Article::getClassName());
$article = new \App\Article();
$article->title = "The Tigger Movie";
$article->slug = 'the-tigger-movie';
$articles->save($article);
$article = $articles->findBy(array('slug' => 'the-tigger-movie')); // Místo tohodle bych rád zavolal např. $articles->getBySlug($slug);
dump($article[0]->title);
}
Moc nevím jak to mám uchopit. Díky moc za nějaký nakopnutí jakým směrem se pustit k best practice. :-)
- Filip Procházka
- Moderator | 4668
Oli napsal(a):
Například v Nette database bych si napsal něco jako… Kam a jak napsat tohle pomocí Doctrine 2?
Můžeš použít DAO v presenteru a zavolat si
$article = $articlesDao->findOneBy(array('slug' => $slug));
Nebo si napíšeš facade třídu, do které to schováš. Obecně doporučuji klidně to ze začátku psát do presenteru a v momentě kdy budeš mít kus funkčnosti hotový tak refaktorovat. Tedy tohle bych napsal jednoduše pomocí dao a pak si napsal třídu a přesunul to do jejich metod.
Přímo do tý entity?
To rozhodně ne, entita nemůže sama sebe někde hledat.
Logické mě přijde podědit
\Kdyby\Doctrine\EntityDao
a dat tu metodu tam, ale HosipLan píše, že by se DAO nemělo dědit.
Správně, DAO nedědit, vytvářel bys god class
doctrine: metadata: App: %appDir% Article: annotations(%appDir%/model/entity)
Ten article namespace v metadatech tam máš zbytečný, stačí ten App, pokud ten namespace budeš používat. Popřípadě to můžeš na něco změnit.
services: entityManager: @Kdyby\Doctrine\EntityManager article: App\Article(@doctrine.dao(App\Article))
Tohle je úplně zbytečné, kdekoliv si řekneš o
EntityManager
, tak se ti tam doplní pomocí autowire, dělat
aliasy nepotřebuješ, protože ta služba už
v DIC je registrovaná.
private $em; public function __construct(\Kdyby\Doctrine\EntityManager $em) { $this->em = $em; }
Na tohle by se ti mohl hodit autowired
Moc nevím jak to mám uchopit. Díky moc za nějaký nakopnutí jakým směrem se pustit k best practice. :-)
Co takhle si napsat službu
class ArticlesFacade extends Nette\Object
{
private $articles;
public function __construct(\Kdyby\Doctrine\EntityManager $em)
{
$this->articles = $em->getDao(\App\Article::getClassName());
}
public function findBySlug($slug)
{
return $this->articles->findOneBy(array('slug' => $slug));
}
}
Službu zaregistruješ
services:
- ArticlesFacade() # netřeba ani pojmenovávat
Necháš si injectnout do presenteru a používáš.
Malá vsuvka, findBy metody na repozitáři ti většinou stačit nebou a jsou spíše na prototypování a postupem času budeš muset psát místo nich DQL dotazy, protože je to efektivnější, ale prozatím je klidně používej :)
- Jiří Nápravník
- Člen | 710
Filip Procházka napsal(a):
Malá vsuvka, findBy metody na repozitáři ti většinou stačit nebou a jsou spíše na prototypování a postupem času budeš muset psát místo nich DQL dotazy, protože je to efektivnější, ale prozatím je klidně používej :)
Kam bys poradil ty DQL psát? Vím, že Kdyby\Doctrine má ty QueryAble, ale nějak se mi nechce kvůli každému DQL dělat speciální třídu. A dát to přímo do Facade se nabízí, ale přeci jen neměla by Facade být tenká a delegovat jinam, než pokládat dotazy tady?
- Filip Procházka
- Moderator | 4668
QueryObjecty jsou určtěné do presenterů a komponent, tam kde stránkuješ a vypisuješ hodně záznamů. Pokud nestránkuješ, neřadíš jenom chceš vrátit nějakej omezenej set záznamů, piš s klidem servisní/facade třídy a měj DQL v nich. Ale opět platí pravidlo nedědit DAO, pouze kompozice.
V momentě kdy ti bude dávat smysl využít funkce QueryObjektu, tak si ho prostě napíšeš :)
- Jiří Nápravník
- Člen | 710
Díky za reakci a upřesnění, já právě na základě článku bral, že se mají používat, kde píšu nějaký DQL