Doctrine v3 one-to-many maping a používání

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

Ahoj, koukal jsem na prezentaci od Filipa Procházky http://www.slideshare.net/…ne-orm-model a další dokumenty o nete a podle toho vytvořil dvě entity (event a site…1 event ma X site) a k nim fasády presenter a další věci, ale nejspíš sem špatně pochopil dokumentaci. Koktrétně mi jde vložení nové strany s vazbou a také sql které mi dá všechy eventy a jejich sites.

  1. nemělo by v tabulce events existovat pole sites ??
  2. nemělo by v siteFace stačit $evetn->addsite($element) aby se přidala závislost(MagicAccessors)?
  3. jak upravit AllEventsQuery.php aby tedy vypisoval eventy a jejich sites? momentálně bere iterátor, který vezme 0 ale za předpokladu, že jsem už předešlé eventy smazal nevezme sites pro event s id 2
  4. mohu nějak aplikovat paginátor? například abych vypsal 5 eventů s jejich sites na každou stránku

Předem říkám, že jsem entity promazal aby zbylo jen podstaté, proto nesedí doCreateQuery

Pokud jsou otázky hloupě položené, tak se omlouvám a na jakoukoli specifikaci se stačí zeptat. Předem děkuji za odpovědi

Event.php

/**
 * @ORM\Entity
 * @ORM\Table(name="events")
 */
class Event
{
    use Entities\MagicAccessors;
    use Entities\Attributes\Identifier;

    /**
     * @ORM\OneToMany(targetEntity="Site",cascade={"persist","remove"},mappedBy="event")
     * @var Site[]|ArrayCollection
     */
    protected $sites;

    /**
     * @ORM\Column(type="string", length=32, nullable=false)
     */
    protected $name;
}

Site.php

/**
 * @ORM\Entity
 * @ORM\Table(name="sites")
 */
class Site
{
    use Entities\MagicAccessors;
    use Entities\Attributes\Identifier;

    /**
     * @ORM\ManyToOne(targetEntity="Event", inversedBy="sites")
     */
    protected $event;

    /**
     * @ORM\Column(type="string", length=32, nullable=false)
     */
    protected $name;

}

SiteFacade.php

<?php
class SiteFacade extends BaseFacade
{
    /**
     * @param Event $event
     * @param ArrayHash $data
     */
    public function createSite(Event $event,$data)
    {
        $element = new Site();
        $element->name = $data->name;

        $event->addSite($element);
        $this->em->persist($event);
        $this->em->flush();
    }


}

SitePresenter.php

class SitePresenter extends BaseAdminPresenter
{
    /** @var Forms\CreateSiteFormFactory @inject */
    public $createSiteFactory;

    protected $eventId;

    public function actionCreate($id = NULL)
    {
        $this->eventId = $id;
    }
    protected function createComponentCreateSiteForm()
    {
        return $this->createSiteFactory->create($this->eventId,function () {
            $this->flashMessage("Strana byla úspěšně vytvořena", 'success');
            $this->redirect(':Admin:Event:show');
        });
    }

}

AllEventsQuery.php

namespace App\Model\Query;

use App\Model\Entities\Event;
use App\Model\Entities\Site;
use Doctrine\ORM\QueryBuilder;
use Kdyby\Doctrine\QueryObject;
use Kdyby\Persistence\Queryable;

class AllEventsQuery extends QueryObject
{
    /**
     * @param Queryable $repository
     * @return QueryBuilder
     */
    protected function doCreateQuery(Queryable $repository)
    {
        return $repository->createQueryBuilder()
            ->addSelect('partial e.{id,visible,name,date,approve,regCars,optionalItems,note}')
            ->from(Event::class, 'e')
            ->orderBy('e.date', 'DESC');
    }

    public function withSites()
    {
        $this->onPostFetch[] = function ($_, Queryable $repository, \Iterator $iterator){
           $ids = array_keys(iterator_to_array($iterator,TRUE));

            $repository->createQueryBuilder()
                ->select('partial event.{id}', 'sites')
                ->from(Event::class,'event')
                ->leftJoin('event.sites','sites')
                ->andWhere('event.id IN (:ids)')->setParameter('ids',$ids)
                ->getQuery()->getResult();
        };
        return $this;
    }


}
jarda256
Člen | 130
+
0
-

Nejspíš jediné řešení bude změnit protected na private a přidat funkce.

akadlec
Člen | 1326
+
+2
-

1. Obousměrná asociace není správná cesta. Zvaž ji mít je jednosměrnou, tedy jen jedna entita bude vědět o té druhé viz „docka
“:http://docs.doctrine-project.org/…mapping.html
2. Magii se vyhni, je použitelná jen pokud si něco testuješ, ale pak bys měl entitu zavřít a mít v ní metody co potřebuješ.
3. Stejně jako bys to dělal v SQL, přijoinuješ tu tabulku co ti tam chybí ->join()
4. Ano opět je něco v docce a pokud používáš doctrine přes kdyby tak o tom máš zmínku v docce tam

ZahorskyJan
Člen | 59
+
0
-

@akadlec omlouvám se za vpád do tématu, ale můžeš přidat nějaký zdroj k tomu bodu jedna? Slyším o tom poprvé a v dokumentaci ani v části best practices jsem na to nenarazil. Díky.

akadlec
Člen | 1326
+
0
-

Tak jednen z hlavních důvodů je performace. Psal o tom tuším i ocramius, ale linky ti bohužel nenaházím, neukládal sem si je.

Tharos
Člen | 1030
+
+2
-

@ZahorskyJan Opravdu se o tom píše i v oficiálních best practices:

avoid bidirectional associations if possible

A teď je otázkou, jak chápat to if possible… :)


Jsou tací, kteří se jim vyhýbají jako čert kříži. To mi ale nepřijde úplně dobré, protože se tím mnohdy ochuzují a zbytečně pak musí sahat po různých berličkách, hackovat a elegance je ta tam. Zkrátka občas si situace o obousměrnou asociaci vyloženě říká…

Ale horší je určitě jejich nadužívání, tzn. kdybys například asociace automaticky implementoval jako obousměrné, aniž bys pak obou směrů reálně využíval…

Proč jsou problematické: kladou větší nároky na programátora co se udržení konzistentního stavu týče (v tom pak totiž Doktrína vůbec nijak nepomáhá) a pak se hodně uvádějí jisté výkonnostní důvody.

Taky se uvádí, že přece jenom zvyšují provázání, ale to mi přijde jako takový argument pro argument… :)

Editoval Tharos (4. 12. 2016 23:43)