6. Asociace mezi entitami
class Comment {
private $article;
public function __construct(Article $article) {
$this->article = $article;
}
7. Asociace mezi entitami
class Article {
private $comments;
public function __construct() {
$this->comments = new ArrayCollection();
}
function addComment(Comment $comment) {
$this->comments[] = $comment;
}
9. Magic to the rescue
use KdybyDoctrineEntitiesMagicAccessors;
class Article {
use MagicAccessors;
10. Magic to the rescue
- pouze na protected properties
- magické (get|set)tery
- magické collection accessory
11. Magic to the rescue
class Article {
private $comments;
function getComments() {
return $this->comments;
}
12. Magic to the rescue
class Article {
protected $comments;
13. Magic to the rescue
$article->comments
->add(new Comment($article)); // vyhodi vyjimku
$article->comments
->filter(function () { .. }); // ok
14. Magic to the rescue
class Article {
// ...
function getComments();
function addComment(Comment $comment);
function hasComment(Comment $comment);
function removeComment(Comment $comment);
15. Less is more
class Comment {
private $article;
// ...
function getArticle() {
return $this->article;
}
16. Less is more
private $published;
function isPublished() {
return $this->published;
}
function publish() {
$this->published = TRUE;
}
18. Životní cyklus entity
- create -> persist -> flush -> konec rq
- load -> update -> flush -> konec rq
- load -> delete -> flush -> konec rq
Existence entity
- začíná s create
- končí s delete+flush
19. Aby entita byla entita
- musí mít metadata
- její NS s driverem musí být registrovaný
29. V presenterech
private $article;
public function actionDefault() {
$this->article = $this->em->find(Article::class, 42);
}
public function renderDefault() {
$this->template->article = $this->article
}
30. Ve formulářích: vytvoření
protected function createComponentForm() {
$form = new UIForm;
$form->onSuccess[] = function ($form, $values) {
$article = new Article($values->title);
$this->em->persist($article);
$this->em->flush();
}
return $form;
}
31. Ve formulářích: editace
protected function createComponentForm() {
$form = new UIForm;
$form->onSuccess[] = function ($form, $values) {
$this->article->setTitle($values->title);
$this->em->flush();
}
return $form;
}
40. ResultSet: why
function findAll($limit, $offset) {
return $this->repository
->createQuery("SELECT a FROM AppArticle a")
->setMaxResults($limit)
->setFirstResult($offset);
function countAll() {
return $this->repository
->createQuery("SELECT COUNT(a.id) FROM AppArticle a")
->getSingleScalarResult();
41. ResultSet: how
public function findAll() {
$query = $this->repository
->createQuery("SELECT a FROM AppArticle a")
return new ResultSet($query);
}
// usage
$this->template->articles = $articles->findAll()
->applyPaginator($this['vp']->getPaginator());
49. M*N problem: násobení řádků
- moc dat na projití
- vysoká komplexita
- moc práce pro databázi
- moc práce pro doctrine
- performance killer
50.
51. Query Object: efektivně
- každá query musí načítat pouze toOne
relace
- toMany relace načítat s WHERE IN dalšími
queries (postFetch)
- konstatní počet queries
52. Query Object: postFetch
public function withComments() {
$this->onPostFetch[] = function ($_, Queryable $repository, Iterator $iterator) {
$ids = array_keys(iterator_to_array($iterator, TRUE));
$repository->createQueryBuilder()
->select('partial article.{id}', 'comments')
->from(Article::class, 'article')
->leftJoin('article.comments', 'comments')
->andWhere('article.id IN (:ids)')->setParameter('ids', $ids)
->getQuery()->getResult();
}
return $this;
}
58. Facade
- brána mezi presenterem/komponentou a
modelem
- snadnější sdílení logiky mezi api a frontem
- vhodné místo pro flush
- není nutné mít 1:1 k entitám
59. Facade
class BlogFacade {
function findPublished();
function fetch(ArticlesQuery $query);
function saveComment(Comment $comment);
class RedactorFacade {
function createDraft();
function save(Article $article);
60. Služby
- dělení aplikace na menší logické celky
- nějaké konkrétní operace nad db/entitami
- klidně i externí api
- používají se ve facades
63. Lifecycle eventy na entitě
/** @ORMEntity @ORMHasLifecycleCallbacks */
class User {
/** @ORMPrePersist */
public function doStuffOnPrePersist() {
$this->createdAt = date('Y-m-d H:i:s');
}
64. Listenery
class MyEventListener implements KdybyEventsSubscriber {
function preUpdate(LifecycleEventArgs $args) {
$entityManager = $args->getObjectManager();
$entity = $args->getObject();
if ($entity instanceof User) {
// do something with the User
}
}
65. Listenery pro typ
class MyEventListener {
function preUpdate(User $user, LifecycleEventArgs $args) {
$entityManager = $args->getObjectManager();
// do something with the User
}