Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

ActiveRecord VS DataMapper

[es] :: PHP :: ActiveRecord VS DataMapper

[ Pregleda: 1321 | Odgovora: 3 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

mitke013
As Divljine
Freelancer

Član broj: 231934
Poruke: 338
*.dynamic.isp.telekom.rs.



+34 Profil

icon ActiveRecord VS DataMapper09.03.2011. u 22:57 - pre 160 meseci
Vec dugo koristim Doctrine 1.2 Active Record pattern. Sad je u prici Doctrine 2.0, DataMapper. Procitao sam mnogo dokumentacije, brdo teorije i ocigledno mi nesto promice posto nikako ne mogu da uklavirim prakticne prednosti DM-a. Mislim... svidja mi se teorija; podela odgovornosti, manje nasledjivanja, veca brzina... ali jednostavno ne kapiram zasto je lakse raditi. Zato mi treba pomoc; koristicu prave primere koda da bih lakse objasnio.

Evo jedna situacija:
imam klasu Activity. Klasa Album je one-2-many sa Activity klasom. Activity je many-2-many sa User klasom. Ideja je da kad se kreira novi Album, odredjeni korisnici budu obavesteni o tome; skraceno, tabela Activity_User je dobiti novi red; activity_id cilja na activity, user_id koji je user obavesten. Klasika.

U Doctrine 1.2 je to sledeci kod:
Code (php):

// klasa Album
          public function preInsert($event)
          {              
               /**
               * Create new activity when inserting so fans can see it
               */

               $activity = new Activity() ;
               $activity->type = Activity::NEW_ALBUM ;
                   
               foreach ($this->Creator->MyFans as $user)
                    $activity->NotifiedUsers[] = $user ;
               $this->Activities[] = $activity ;
               parent::preInsert($event) ;
          }
 

Ovo je SAV kod potreban u preInsert() metodi i prilicno je jednostavan. Doctrine se sam brine o relacijama. foreach petlja ce od kreatora albuma (Creator je alias za User-a koji je kreirao Album) izvuci listu fanova i njima poslati obavestenje. Sve se ovo snima kroz jednu transakciju i jako lepo radi.
E sad problem;
kako to uraditi preko Doctrine 2.0? Jednostavno ne mogu da nadjem nacin da lako uradim ovako nesto a da to ne zahteva daleko vise koda.

Problem 2, DQL:
U 1.2 verziji, DQL je boza za koristiti:
Code (php):

               return $this->createQuery('o')
                    ->select('o.*, m.value AS value')
                    ->leftJoin('o.WordTranslation m WITH m.translation_id=?', Translation::getForVisitor()->id)
                    ->execute() ;
 

Parametri se lako prosledjuju. Doctrine 2.0:
Code (php):

$query = $em->createQuery('SELECT u from ForumUser u WHERE (u.username = :name OR u.username = :name2) AND u.id = :id');
$query->setParameters(array(
    ':name' => 'Bob',
    ':name2' => 'Alice',
    ':id' => 321,
));
 

Meni ovo bas i nema previse razlike u odnosu na obicni PDO i manje je citljiv nego prvi primer.

Problem 3, validacija:
Prema ovom clanku , Doctrine 2.0 nema validaciju kao sto je ima Doctrine 1.2. Jasno mi je za custom validate pravila, ali ona najobicnija; regexp za polje, da li je u nekom range-u itd. je daleko lakse uraditi u staroj verziji:
Code (php):

               $this->hasColumn('title', 'string', 255, array(
                   'type' => 'string' ,
                   'regexp' => '/^[a-zA-Z0-9žŽđĐšŠćĆčČÁÉÍÓÚÑÜ áéíóúñüÄäÖöÜüß\-,\._]{4,255}$/'  )) ;
 

Da li ovo znaci da za ovako jednostavne stvari moram uvek da kreiram posebne metode? I kako da koristim isValid() kako bi kontroler znao da je objekat validan ili ne, tj. ili da ga snimi ili opet posalje template-u?

Problem 4, deep validacija:
Ova slika pokazuje validaciju klase Translation uz leftJoin svih Word objekata. Kod je standardno jednostavan; if ($translation->isValid()) ce mi dati odgovor da li su SVI pridruzeni objekti takodje validni. Ako jesu, $translation->save() ce opet kroz transakciju da snimi izmenjene Word-ove (Doctrine ne snima neizmenjene). Opet, vrlo, vrlo jednostavno za koriscnenje.

Kako to uraditi u Doctrine 2.0 a da ne moram da koristim neki framework?

 
Odgovor na temu

dakipro
Dalibor Jovic
Web Developer
Bergen, Norway

Moderator
Član broj: 31848
Poruke: 1792
..178.212.adsl.dyn.beotel.net.

Sajt: norway.dakipro.com


+190 Profil

icon Re: ActiveRecord VS DataMapper10.03.2011. u 08:49 - pre 160 meseci
Ovako laicki, preInsert() ti dodje @prePersist ili @preUpdate LifecycleCallbacks, i koliko kontam ovako, isto ili manje koda ti je potrebno jer ako metodi stavis da je @prePersist, ona se poziva automatski bez da ti moras da pozivas bilo kako. Znaci kad uradis ->flush(), adekvatna metoda se poziva (prePersist je samo pred dodavanje novog objekta u bazu, preUpdate je logicno samo pred update)
http://www.doctrine-project.or...m/2.0/en/reference/events.html
a ako pitas za cisto relacije, deluje mi kod prilicno identican, postuj dokle si stigao i gde si zapeo sa v2 kodom pa da vidimo mozda skontamo nesto. Inace bi isto bilo mislim, ako ne identicno, samo izvrtis vezane objekte (kako se vec strucno kaze) i spicis akciju. Al opet, daj malo koda dokle si stigao, nije mi bas najjasniji ovako sta gde koci konkretno.

mozes i u v2 da koristis queryBuilder, ako si za to pitao, mislim da je onda identican nacin rada
http://www.doctrine-project.or...n/reference/query-builder.html

Validacija, e to je malo zez, ja jos uvek radim na tome da provalim najlaksi nacin, ali definitivno preporucuju @prePersist i @preUpdate i to radi sasvim ok sa exceptionima.
Za sada objektu setujem niz sa pravilima za svaki property koji je persistent u bazi, svaki sa svojim pravilima i onda custom proveru validnosti. To sam kontao da bude u serviceLayeru, mada to meni drugacije malo izgleda nego "uobicajeno", lakse mi je da model nasledi serviceModel pa da sam bude sposoban da radi kao serviceLayer (ali mozda i promenim nacin razmisljanja u nekom trenutku).

4. nisam bas skontao problem, a i ako jesam nisam siguran kako bi mu pristupio. Verovatno je to vezano za 3., obicnu validaciju. Ali pogledaj kako u doctrine 2 rade translacije sa extenzijama
http://www.doctrine-project.or...vioral-extensions#translatable
Propertiju stavis "@gedmo:Translatable" (indicates that the column is translatable) i odmah se prave eventi koji na prePErsis i preUpdate i delete prave vezu izmedju prevoda i objekta, sve bi trebalo da je transparentno. Za ovaj jpg verovatno bi trebao i poseban model za prevod da napravis, ali i to ima u extenziji sa "@gedmo:TranslationEntity(class="my\class")"

Inace sam skotnao da je DataMapper ideologija priiilicno razlicita od activeRecord koja mi je u krvi. Mozda nekom znaci, ali sam skontao da DataMaper (bar u doctrinetu) radi i funckionise kao "sinhronizator" objekata i baze. Odnosno, ovde su jooos vise odvojeni objekti od baze, a orm samo "zapamti" objekte u bazi do sledeceg poziva skripte. Znaci radi se sa objektima kao da baze uopste nema, i kao da se skripta nikada ne prekida vec je stalno u memoriji. Jednostavno se samo na kraju skripte izvrsi sinhronizacija stanja objekta u memoriji i podataka u bazi pozivom na flush(), potpuno ne vidljivo. Sto meni koji godinama radim sa activeREcord nije bas najlakse za svariti iskreno. Ponekad mi deluje da bi mi bilo lakse da sam zavrsio fakultelt i naucio tamo sve fancy pojmove i ideje koje se koriste u "advanced OOP" :)

Ako si me nesto i razumeo, super :)
 
Odgovor na temu

mitke013
As Divljine
Freelancer

Član broj: 231934
Poruke: 338
*.dynamic.isp.telekom.rs.



+34 Profil

icon Re: ActiveRecord VS DataMapper10.03.2011. u 14:48 - pre 160 meseci
Citat:
Ovako laicki, preInsert() ti dodje @prePersist ili @preUpdate LifecycleCallbacks, i koliko kontam ovako, isto ili manje koda ti je potrebno jer ako metodi stavis da je @prePersist, ona se poziva automatski bez da ti moras da pozivas bilo kako. Znaci kad uradis ->flush(), adekvatna metoda se poziva (prePersist je samo pred dodavanje novog objekta u bazu, preUpdate je logicno samo pred update)
http://www.doctrine-project.or...m/2.0/en/reference/events.html
a ako pitas za cisto relacije, deluje mi kod prilicno identican, postuj dokle si stigao i gde si zapeo sa v2 kodom pa da vidimo mozda skontamo nesto. Inace bi isto bilo mislim, ako ne identicno, samo izvrtis vezane objekte (kako se vec strucno kaze) i spicis akciju. Al opet, daj malo koda dokle si stigao, nije mi bas najjasniji ovako sta gde koci konkretno.


Jasno mi to za prePersist i preUpdate, pogledao sam dokumentaciju za evente i to je skoro isto kao u V1.2. Mene muci ovaj deo:
Citat:

foreach ($this->Creator->MyFans as $user)
$activity->NotifiedUsers[] = $user ;
$this->Activities[] = $activity ;

U prevodu: od kreatora $this Album-a, izvuci listu fanova i za svakog kreiraj novi Activity (obavestenje o aktivnosti kreatora). Zadnja linija ce taj novo-kreirani Activity da 'prikaci' albumu i snimice se zajedno.

Koliko sam razumeo, u D2.0 bih morao da 'rucno' snimim ta obavestenja. Probaj da napises kod, cini mi se da je daaaaleko komplikovanije.

btw; nisam napisao jos nikakav kod, jer nemam vremena za to ali detaljno citam dokumentaciju. Krenuo sam u tu pricu isto kao i za D1.2; dokumentacija prvo, hvatanje logike rada... i za 3-4 dana naucis.
Citat:
mozes i u v2 da koristis queryBuilder, ako si za to pitao, mislim da je onda identican nacin rada
http://www.doctrine-project.or...n/reference/query-builder.html

Nazalost, nije. U real-life situaciji uvek ima MNOGO join-ova, zavisno od stranice do stranice. Evo primer:
Code (php):

          /**
          * For listen->song() page
          *
          * @param mixed $id
          * @return Song
          */

          public function findForListenSong($id)
          {
               $query = $this->createQuery('o')->select('o.*')  ;
               $this->addAlbum($query) ;
               $this->addLanguage($query) ;
               $this->addCreator($query) ;
               $this->addStatistics($query) ;
               $this->addCategory($query) ;
               $this->addCountry($query) ;
               $this->addActiveContest($query) ;
               ......
               return $query->addWhere('o.id=?', $id)->fetchOne() ;
          }


          /**
          * Add country as property:
          *
          * country_name
          *          
          * @param Doctrine_Query $query
          */

          protected function addCountry(Doctrine_Query $query)
          {
               $query->addSelect('e.name as country_name')
                    ->leftJoin('o.Country y')
                    ->leftJoin('y.CountryTranslation e WITH e.translation_id=?', Translation::getForVisitor()->id) ;
          }
 


Znaci za stranicu koja pusta pesmu, treba mi najvise informacija: jezik, zemlja (multijezicka podrska), statistika, da li je pesma u nekom takmicenje (Contest)... itd. Bitno u ovoj prici je metoda addCounty(). Tu na postojeci query samo uradim join potrebnih stvari, dodam addSelect() za ime zemlje i sve lepo radi. Kod QueryBuilder-a, ja ne mogu ovo da uradim vec bih iznova kopirao isti kod. Ili mi nesto promaklo a ne mogu da nadjem. Na primer; ako mi za ListenSong vise ne treba ime zemlje, ja iz metode samo izbacim liniji $this->addCountry($query). U 2.0 to ne mogu da uradim; query builder UVEK zahteva sve parametre, ne moze se tek tako dodati. Nadam se da me razumes...

Citat:
Validacija, e to je malo zez, ja jos uvek radim na tome da provalim najlaksi nacin, ali definitivno preporucuju @prePersist i @preUpdate i to radi sasvim ok sa exceptionima.
Za sada objektu setujem niz sa pravilima za svaki property koji je persistent u bazi, svaki sa svojim pravilima i onda custom proveru validnosti. To sam kontao da bude u serviceLayeru, mada to meni drugacije malo izgleda nego "uobicajeno", lakse mi je da model nasledi serviceModel pa da sam bude sposoban da radi kao serviceLayer (ali mozda i promenim nacin razmisljanja u nekom trenutku).


Aj postuj nesto koda da vidim na sta mislis. Nesto sam razmisljao da mi sve klase nasledjuju neku moju tipa 'BaseEntity', u nju da stavim isValid() a da ona posle iz child elemenata izvlaci pravila za osnovnu validaciju kao ovo gore: regexp, minlength itd. Tj. ono sto mi D1.2 pruza u Base klasama. Medjutim, ta ideja mi vec sad mirise na budzanje koja ce neka buduca verzija imati interno.

Citat:
4. nisam bas skontao problem, a i ako jesam nisam siguran kako bi mu pristupio. Verovatno je to vezano za 3., obicnu validaciju. Ali pogledaj kako u doctrine 2 rade translacije sa extenzijama
http://www.doctrine-project.or...vioral-extensions#translatable

Nisi me razumeo dobro; ovo sto ja koristim NIJE translation behaviour koji D1.2 pruza vec sam to ja napravio. Moja verzija je mnogo bolja i fleksibilnija nego originalna. Problem u tom primeru je sto ja imam formu gde se ne edituje samo jedan objekat, vec i mnogo child elemenata.

Ajde ovako; zamisli da imas Album kome je uradjen leftJoin svih Song-ova. Ti imas formu gde mozes da izmenis ime albuma, ali ujedno i imena svih pesama. $album->isValid() treba da vrati false ako i samo jedna od pesama nema ispravno ime, recimo krace je od 3 karaktera i slicno.

Citat:
Sto meni koji godinama radim sa activeREcord nije bas najlakse za svariti iskreno. Ponekad mi deluje da bi mi bilo lakse da sam zavrsio fakultelt i naucio tamo sve fancy pojmove i ideje koje se koriste u "advanced OOP"

Veruj, bolje sto nisi. Tamo bi ucio 300 programskih jezika, a nijedan ne bi znao kako treba. Tvrdio bi da je moj kod 'glupost' kao i koriscenje 'ORM-a i Framework-a'. Znas li da ja sam 4-5 puta padao Racunare? Moj algoritam je radio tacno i bio kraci od profinog, ali svaki put sam dobio isti odgovor: NISAM TAKO PREDAVAO! Na kraju sam morao da kupim knjigu i uradim po njegovoj ideji. Mikroprocesore nikad nisam ni polozio, napustio sam visu kad sam ukapirao da profesori znaju manje od mene.
Programiranje nije egzaktna nauka; to se uci SAMO kroz rad i vezbanje. Ja sam uveliko koristio Doctrine i tek na ovom forumu sam saznao da se to zove Active Record pattern. Do singleton-a sam sam dosao, ne secam se kako ali verovatno analizirajuci Doctrine kod; i tek posle par meseci saznao i 'zvanicno' ime
Citat:
Ako si me nesto i razumeo, super


Zapravo jesam, vidim da nisam jedini koji muci muku oko nekih osnovnih stvari na koje smo izgleda obojica navikli. I za mene je AR prirodan nacin rada, kod je uvej jako kratak, brz, lako citljiv... Znam da gresim, to je sigurno, ali nikako da uklavirim kako mi DataMapper olaksava stvar. Ili da bar bude isto, nema problema, ne bih kukao.

Posto D2 nema validaciju kao D1, kako ti zvuci ideja o BaseXXX klasama koje nasledjuju neku zajednicku npr. BaseEntity gde bi se postavilo isValid() i getErrorStack() kao u D1? getErrorStack() mi treba da izvucem gde je tacno pala validacija.

Ovo nije tesko napraviti, pogledaj ovu sliku. To je moja Settings klasa, ima identican API kao Doctrine, ali nema nikakve veze sa njim. Ona koristi .ini fajl za sebe, ne bazu.
Posto vec radis sa D2, da li ti se takva ideja cini kao budzanje? Meni su validacija i sigurnost podataka vazniji od bilo cega drugog.
 
Odgovor na temu

dakipro
Dalibor Jovic
Web Developer
Bergen, Norway

Moderator
Član broj: 31848
Poruke: 1792
..178.212.adsl.dyn.beotel.net.

Sajt: norway.dakipro.com


+190 Profil

icon Re: ActiveRecord VS DataMapper10.03.2011. u 15:13 - pre 160 meseci
Previse problema za jednu temu :)
Generalno nisam ni ja siguran bas za sve za DataMapper, ali se nadam da cu da skontam uskoro. Pocinje da mi se javlja pomalo :) Na dosta prakticnih problema sam i ja naisao koristeci doctrine2 koje uopste ne bi ni imao sa AR pristupom, verovatno zato sto sam ar razvijao veoma dugo za razliku od ovog sto mi ponekad dodje kao spansko selo.

SAd, opet napamet, necu stici da probam nista do srede sledece, al evo napamet kako bi trebalod a izgleda ovo
Code:

foreach ($this->Creator->MyFans as $user)
$activity->NotifiedUsers[] = $user ;
$this->Activities[] = $activity ;


Code:


foreach ($this->Creator->MyFans as $user)
$activity->setNotifiedUsers($user) ;
$this->getActivity()->add($activity) ; // ako je this user, ili da uprostimo primer. Activity je u konstruktoru napravljen kao arrayCollection
$em->persist($activity);
$em->persist($user);

ili da unutar setNotifiedUsers napravis odmah dole da se setuje i activiti za taj user i odma da bude persist. Seter moras da koristsi jer ti NotifiedUsers nije obican array (tj ne bi trebalo da je obican) vec docrtine arrayCollection, zbog lakse manipulacije kazu. Nazalost, i ja volim magic seterse i geterse, ali za relacije izgleda da je najlakse da se to rucno radi posebnim seterom i geterom.
Mada, nisam stigao bas dotle, mozda bi i moglo i da se setuje samo user sa activitijem ali da user bude "owning side", ali nisam siguran da li ce da uradi persist, mislim da nece. Mozda moze da se setuje nesto tom propertiju da bude uverk i persist, znam dai ma nesto, al za pocetak ja ga radim pusaka pa makar bio duzi kod, dok se ne uigram kako moze... tako mi lakse nekako

validacija, pa tako nekako sam i ja poceo. nasledi se baseModel, i ima property koji nije persistant u bazi nego se podesava u klasi svakog modela (opet, tako mi lakse da ga pratim i menjam, pa mozda i jeste budzenje za sada) i u taj property koji se zove recimo $this->formValidationRules setujem niz sa svim poljima 'emai' => 'trim|is_email|blalba' u posle taj niz da izvrtim na pre-persist i bacim exception. Mislim da ako se koristi prePersist ne moze da se setuje tako isTrue i da se juri. Ali, ti uvek mozes da uradis rucno checkValidation() pre nego pozoves ->flush() i onda da vidis jal valid ili ne. Mislim da doctrine nece imati validaciju u buducnosti, bar sam tako skontao iz blogova i tutorijala, u fazonu, svi framworci to bolje rade pa da ga ne tupe i oni. Nema bas puno tutorijala na netu, a i relativo je frisko kolko sam ja skontao doctrine 2, pa nema bas puno primera za koriscenje. Ja recimo jos cekam 2.1 koja ce imati ultra lazy loading bolje implementiran, ako uz recimo model Post vadis 400 komentara, trenutno mora sve to u memoriju, sto je neupotrebljivo prakticno. 2.1 ce moci da izvadi samo deo za paginaciju ili tako.

Iskreno, jos uvek gledam celu poentu DataMapera i upotrebe, i nadam se da ce neko da napravi klasu za dobru validaciju pa da se ne mucim bas previse, omatorelo se hehe :)

Mislim da samo strpljivo, pa cemo vremenom uvideti prednosti, iako kontam polako o cemu se radi, kao sto sam napisao, ti samo pravis prave objekte i ne majes se uopste sa opisom i strukturom tabela, niti te to u bilokom trenutku zanima, to doctrine pamti, kao "hibernacija" objekata. Znaci imas objekat sa 30 propertija, ali ti nekih 20 treba persistent i ti o tome ne razmisljas, ako pustam masti na volju u dobrom pravcu, a nije nemoguce da gresim.
Nadam se da ce jos neko da iznese misljenje o DataMaperu kao prednosti (u prakticnom svetu)
 
Odgovor na temu

[es] :: PHP :: ActiveRecord VS DataMapper

[ Pregleda: 1321 | Odgovora: 3 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.