[Doctrine] Flag op unieke wijze op groep entities toepassen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Struikrover
  • Registratie: Juni 2005
  • Laatst online: 09-09 07:28
Ik ben op zoek naar de beste manier om in Doctrine (2.0) het volgende voor elkaar te krijgen:

Er bestaat in mijn applicatie een Entity waaraan ik een eigenschap wil toevoegen. De eigenschap houdt in dat van alle instances van Entity die ik in de database heb, er een de 'hoofdentity' is. De eigenschap is te wijzigen, zodat ik een andere entity als hoofdentity mag instellen, waarna de eigenschap bij alle andere entities op 0, false of null (wat maar het handigst is) wordt gezet.

Ik weet alleen niet zo goed wat hier de beste methode voor is. Ik zou natuurlijk bij het wijzigen van de ene entity in mijn controller, alle andere entities kunnen opvragen en een voor een de eigenschap op false kunnen zetten, maar iets zegt met dat hier misschien ook een automatisch mechanisme voor is. Ik heb hem alleen niet kunnen vinden in de Doctrine documentatie. Tenminste: ik weet niet zo goed hoe ik dit zou moeten benoemen dus zoeken is wat lastig gebleken.

Kunnen jullie me op weg helpen door een best practice voorbeeld of de terminologie waarop ik kan zoeken?

Acties:
  • 0 Henk 'm!

  • IceM
  • Registratie: Juni 2003
  • Laatst online: 11-09 20:35
Dit is een vrij specifiek probleem waar, voor zover ik weet, geen generieke oplossing voor is. Ik zou dit oplossen middels DQL, iets als:
PHP:
1
2
3
$query = $em->createQuery("UPDATE MyProject\Model\EntityName e SET e.is_head = '0' WHERE e.id NOT IN (:id)");
$query->setParameter('id', $entity->getId());
$query->execute();


(niet getest, werk niet vaak met DQL maar zoiets zou moeten kunnen)

...


Acties:
  • 0 Henk 'm!

  • Struikrover
  • Registratie: Juni 2005
  • Laatst online: 09-09 07:28
Dankje IceM, zoiets had ik inderdaad in gedachten. Het is echter wel een handmatige oplossing. Als het inderdaad niet standaard is dan is zoiets wellicht wel een goede oplossing.

Wat ik alleen niet zo mooi vind is dat de constraint niet nageleefd wordt door de database; alleen mijn applicatie logica zorgt voor de constraint door handmatige alle entities aan te passen.

Het gevolg is dat wanneer ik eens onvoorzichtig ben en de entities vergeet te updaten, de ORM niet gaat zeuren maar gewoon mijn entities aanpast, met als gevolg dat er meer dan 1 hoofdentity bestaat.
Als het zo simpel was dat ik een unique constraint kon toepassen dan was dit geen issue, maar ik wil graag dat er 1 entity is die de unique waarde true (of 1 ofzo) heeft, waarbij de rest dus een niet-unieke waarde heeft.

Acties:
  • 0 Henk 'm!

  • IceM
  • Registratie: Juni 2003
  • Laatst online: 11-09 20:35
Het hebben van maar 1 hoofdentiteit kun je afdwingen met validators (je gebruikt Symfony?) maar dat betekend alsnog dat je zelf moet zorgen dat de oude hoofdentiteit omgezet wordt naar een normale. Wat je zou kunnen doen is je entityrepository extenden met iets als:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use Doctrine\ORM\EntityRepository;

/**
 * Repository for XXX
 */
class XXXRepository extends EntityRepository
{

    /**
     * Returns the headentity
     * 
     * @return XXX|null
     */
    public function findHeadEntity()
    {
        return $this->findOneBy(array('isHead' => true));
    }

}


Je zult dan in je controller wel de oude hoofdentiteit om moeten zetten naar een normale:
PHP:
1
2
3
4
5
6
7
$repository = $em->getRepository('MyProject:XXX');
$currentHead = $repository->findHeadEntity();
if ( null !== $currentHead ) {
    $currentHead->setIsHead(false);
}
$newHead->setIsHead(true);
$em->flush();

...


Acties:
  • 0 Henk 'm!

  • Struikrover
  • Registratie: Juni 2005
  • Laatst online: 09-09 07:28
Wat denk je dan van zo'n implementatie? Ik denk dat ik daarmee het dichtst bij een good practice aan blijf zitten, terwijl ik er toch voor heb gezorgd dat ik weinig moeite hoef te doen om mijn database niet stuk te maken.

Functie in controller:
PHP:
1
2
3
4
5
6
7
8
9
10
    public function setHeadAction($pagename)
    {
        $page = $this -> getDoctrine() -> getRepository('PageBundle:Page') -> setHead($pagename);
        $em = $this -> getDoctrine() -> getEntityManager();
        
        $em -> persist($page);
        $em -> flush();
        
        return new Response("gelukt");
    }


functie in repository:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
    public function setHead($pagename)
    {
        $page = $this -> findOneByRef($pagename);
        
        $current = $this -> findOneByHead(true);
        $current -> setHead(false);
        
        $page -> setHead(true);
        
        $this -> getEntityManager() -> persist($current);
        
        return $page;
    }

Acties:
  • 0 Henk 'm!

  • kwaakvaak_v2
  • Registratie: Juni 2009
  • Laatst online: 02-06 12:29
Dit klinkt toch eerder iets wat je met een lifecycle event zou kunnen lossen.

Driving a cadillac in a fool's parade.


Acties:
  • 0 Henk 'm!

  • Struikrover
  • Registratie: Juni 2005
  • Laatst online: 09-09 07:28
Maar het probleem daarmee is dat je binnen je Entity vervolgens in een @PrePersist of iets dergelijks, alle entities van dezelfde soort moet kunnen aanroepen. Daarvoor je moet dus de EntityManager binnen je klasse aanroepen, en dat schendt weer het idee van POPO (Plain Old PHP Objects) binnen de Symfony2 Entities. Je controller en de Repository zijn juist gemaakt voor dat soort handelingen, als ik het goed begrijp

Acties:
  • 0 Henk 'm!

  • kwaakvaak_v2
  • Registratie: Juni 2009
  • Laatst online: 02-06 12:29
Mischien begrijp ik je verkeerd, maar met http://symfony.com/doc/cu...isteners_subscribers.html kun je toch een class aangeven die op een bepaald lifecycle event wordt aangroepen?

Driving a cadillac in a fool's parade.


Acties:
  • 0 Henk 'm!

  • Struikrover
  • Registratie: Juni 2005
  • Laatst online: 09-09 07:28
Ah, dat klinkt inderdaad als hetgene waarnaar ik op zoek ben. Ik zal er eens voor gaan zitten, dankjewel :)
Pagina: 1