Drukowana wersja tematu

Kliknij tu, aby zobaczyć temat w orginalnym formacie

Forum PHP.pl _ Pro _ ActiveRecord, ORM

Napisany przez: seaquest 19.03.2007, 12:58:19

Na początek po reorganizacji forum chcielibyśmy zaproponować wam temat dotyczący mapowania tabel z baz danych na obiekty w PHP.

Napisany przez: Sh4dow 19.03.2007, 13:36:04

czy czegos podobnego nie robi http://propel.phpdb.org ? Bardzo ciekawe rozwiazanie. Niedawno znalazlem i zachwycam sie co jakis czas biggrin.gif Poza łatwością i przyjemnością w pisaniu, nie miałem okazji przetestować wszystkiego pod względem wydajności.

Edit:
Chociaz przy propel'u to by sie przydalo narzedzie do tworzenia tablic w XML'u. Coś podobnego w stylu tworzenia tablic w phpMyAdmin. Bo na większą skale jest to kosmar tak pisac biggrin.gif

Napisany przez: athabus 19.03.2007, 14:02:56

Moje doświadczenia z klasami tego typu są dość małe. Zastanawia mnie jednak kwestia wydajności. Dla przykładu ZF ma klasę Zend_Db_Table, która jest implementacja Active Record. Zauważyłem, że już przy inicjacji takiej klasy wykonywane jest jedno dodatkowe zapytanie -> w tym przypadku Describe Table. Czyli np, aby odczytać wiersz o id=5 muszę wykonać 2 zapytania - 1 opisujące strukturę tabeli, drugie odczytujące wiersz. Powiem szczerze, że trochę mnie to zniechęca do tego rozwiązania - stosuje je tylko w panelu administracyjnym, gdzie mogę sobie pozwolić na wykonywanie dodatkowych zapytań - na stronach, które są "mocniej oblegane" raczej wolę sam optymalizować zapytania.

Druga sprawa to obiekty oparte o ActiveRecord stoją trochę w sprzeczności z ideą OOP i dają publiczny dostęp do wszystkich swoich składowych. Sam np. nadpisałem Klasę Zend_Db_Record tak aby była możliwość określenia parametrów publicznych i prywatnych oraz zakresu wartości jakie przyjmują.

Trzecia sprawa to to, że początkowy zysk w postaci szybszego kodowania jest opłacony przez mniejszą przejrzystość kodu w przyszłości.

Z drugiej jednak strony muszę przyznać, że jest to kolosalne ułatwienie przy pisaniu i praca idzie znacznie szybciej - nie trzeba "klepać" ręcznie każdego małego obiektu.

Napisany przez: Sh4dow 19.03.2007, 14:12:36

Nie znam framework'a zend'a ale propel dzieli sie na dwie czesci, ta ktora generuje klasy dla bazy danych i druga gdzie wykozystujesz juz gotowe obiekty, ktore nie za bardzo sa sprzeczne z OOP, raczej idealnie wpasowywują się w założenia OOP.
Osobiscie znam jedynie propela, jeśli chodzi o tego typu skrypty. Czy jest ktoś w stanie podać jakieś inne z którymi miał jakąś styczność ?

Napisany przez: mike_mech 19.03.2007, 14:15:21

Cytat(athabus @ 19.03.2007, 14:02:56 ) *
Zauważyłem, że już przy inicjacji takiej klasy wykonywane jest jedno dodatkowe zapytanie -> w tym przypadku Describe Table. Czyli np, aby odczytać wiersz o id=5 muszę wykonać 2 zapytania - 1 opisujące strukturę tabeli, drugie odczytujące wiersz.
W Propelu przy takich operacjach jest wykonywane tylko jedno zapytanie.
  1. <?php
  2.  
  3. $user = UserPeer::retrieveByPK(5);
  4.  
  5. ?>
I mamy użytkownika o identyfikatorze 5. Całościowo w jednym zapytaniu.

Cytat(athabus @ 19.03.2007, 14:02:56 ) *
Druga sprawa to obiekty oparte o ActiveRecord stoją trochę w sprzeczności z ideą OOP i dają publiczny dostęp do wszystkich swoich składowych. Sam np. nadpisałem Klasę Zend_Db_Record tak aby była możliwość określenia parametrów publicznych i prywatnych oraz zakresu wartości jakie przyjmują.
To akurat błąd w ZF a nie w idei ActiveRecordu.
Propel na przykład nie pozwala na takie rzeczy i ma settery i gettery do swoich właściwości.

Cytat(athabus @ 19.03.2007, 14:02:56 ) *
Trzecia sprawa to to, że początkowy zysk w postaci szybszego kodowania jest opłacony przez mniejszą przejrzystość kodu w przyszłości.
No coś ty?
  1. <?php
  2.  
  3. $author = new Author();
  4. $author->setFirstName("Jack");
  5. $author->setLastName("London");
  6. $author->save();
  7.  
  8. ?>
Moim zdaniem przejrzystość idzie tylko na plus.

Napisany przez: athabus 19.03.2007, 14:30:13

Propela jeszcze nie próbowałem, ale z przykładów, które podajesz widzę, że moje przekonania są błędne. Niestety w ZF nie działa to, aż tak fajnie i trochę mnie to rozwiązanie zniechęcało.

Co do przejrzystości kodu to znowu -> jeśli tak jest jak piszesz, to zmienia postać rzeczy. W ZF tworzysz klasę dziedziczącą po Zend_Db_Table i ona nie definiuje ani pól ani ich typów. Później piszesz np.

  1. <?php
  2. $author->setField('name', 'Szymon');
  3. ?>

Tyle tylko, że pole name nie jest nigdzie zdefiniowane - po prostu musi istnieć w tabeli. To miałem na myśli.
Tak jak pisałem wcześniej udało mi się to nieco obejść i utworzyć nową klasę wiersza, która narzucała różne rzeczy.
Jeśli Propel definiuje cały kod klasy wraz z setterami i getterami to mnie to ostatecznie przekonuje aby przetestować to rozwiązanie.

Napisany przez: splatch 19.03.2007, 23:18:38

Cytat(Sh4dow @ 19.03.2007, 13:36:04 ) *
czy czegos podobnego nie robi http://propel.phpdb.org ? Bardzo ciekawe rozwiazanie. Niedawno znalazlem i zachwycam sie co jakis czas biggrin.gif Poza łatwością i przyjemnością w pisaniu, nie miałem okazji przetestować wszystkiego pod względem wydajności.

Edit:
Chociaz przy propel'u to by sie przydalo narzedzie do tworzenia tablic w XML'u. Coś podobnego w stylu tworzenia tablic w phpMyAdmin. Bo na większą skale jest to kosmar tak pisac biggrin.gif


Kod
propel_gen project-name creole
propel_gen project-name om


Krótki opis całości znajdziecie http://blog.dywicki.pl/2007/02/11/propel-12-a-istniejaca-baza-danych/.

Cytat(Sh4dow @ 19.03.2007, 14:12:36 ) *
Nie znam framework'a zend'a ale propel dzieli sie na dwie czesci, ta ktora generuje klasy dla bazy danych i druga gdzie wykozystujesz juz gotowe obiekty, ktore nie za bardzo sa sprzeczne z OOP, raczej idealnie wpasowywują się w założenia OOP.

Dwa autonomiczne elementy propela to generator oraz runtime. Pierwszy do działania nie potrzebuje drugiego a drugi pierwszego, ponieważ mają one zupełnie inne zadania.

Cytat(mike_mech @ 19.03.2007, 14:15:21 ) *
W Propelu przy takich operacjach jest wykonywane tylko jedno zapytanie.
  1. <?php
  2.  
  3. $user = UserPeer::retrieveByPK(5);
  4.  
  5. ?>
I mamy użytkownika o identyfikatorze 5. Całościowo w jednym zapytaniu.

To akurat błąd w ZF a nie w idei ActiveRecordu.
Propel na przykład nie pozwala na takie rzeczy i ma settery i gettery do swoich właściwości.

News - w przyszłości mają pojawić się "lekkie obiekty", które nie będą miał standardowych setterów i getterów.

ORM to nie tylko AR, są różne strategie implementowania odwzorowań jak i ich zachowań. Spektrum problemu jest wbrew pozorom dość duże i obejmuje rzeczy tak elementarne jak klucze główne i tak złożone jak hierarchie dziedziczenia czy tak abstrakcyjne jak identyfikowanie raz stworzonego obiektu.

Myślę, że warto odwiedzających zachęcić do lektury PoEAA. Jeśli idzie o implementację mechanizmów O/R jest to czołowa pozycja, z której można wynieść bardzo wiele.

Myślę, że porównywanie Propela i Active Recorda to tak jak dyskusja o tym co jest lepsze - Abstract Factory czy Factory Method? Fakt jest jeden - to zależy.

Napisany przez: ActivePlayer 20.03.2007, 00:09:17

A ja sobie napisałem swoją klasę (swego czasu opisywaną w phpsolutions) i to z niej korzystam. Zestaw Finderów wraz z obiektami (które wszystkie są dokładnie takie jak mi się to wymarzy, nic nie narzuca mi propel) to wg mnie najlepsza sprawa na jaką mogłem wpaść.

Napisany przez: nospor 20.03.2007, 08:13:36

Ja mam podobnie (tak mi sie wydaje) jak ActivePlayer. Własna klasa, nawet nie wiem jak dziają te inne zendowe czy propelowe smile.gif
Klasa bazowa, która zawiera operacje zapisu i odczytu tabeli oraz zawiera wspolne pole dla wszystkich tabel (akurat u mnie w projektach tak mam).
Nastepnie dla danej tabeli tworze klase, ktora dziedziczy po bazowej i zawiera definicje dodatkowych pol tabeli, ktorych nie ma w bazowej. I to wszystko.
Jesli podczas zapisywywania danej tabeli potrzebuje wykonac jakies dodatkowe operacje, to nadpisuje metode save z bazowej i robie tam co mi potrzeba.

Rozwiązanie jest banalnie proste, elastyczne i przejrzyste. Jak musze cos kombinowa przy tabeli, to robie to tylko w danej klasie tabeli, nie latam juz po zadnych innych czesciach aplikacji.

Napisany przez: Sh4dow 21.03.2007, 10:18:24

No to robisz prawie tak samo jak propel, Tylko ze propel generuje ci wszystko na podstawie xml'a. Masz obiekty dla tablic, masz plik sql zeby zrobic insert do bazy. Osobiście zapoznaje się jedynie z propelem, bo zend jakos mi nie podchodzi. I musze powiedziec ze trzeba sie troche przedstawic zeby wykozystac w pełni możliwości.
Jedyne co mnie martwi to wydajność której chyba na razie nikt nie sprawdził, jak bardzo tracimy na wydajności. Bo wygoda to jedno a wydajnosc to drugie. z czego chyba bardziej by mi zalezalo na tym drugim.

Napisany przez: nospor 25.03.2007, 20:14:56

Cytat
Jedyne co mnie martwi to wydajność której chyba na razie nikt nie sprawdził, jak bardzo tracimy na wydajności.

To zalezy czy umiejetnie tego uzywasz czy nie. Przyklad:
mamy liste id. iterujemy tę listę i dla kazdego id z tej listy tworzymy obiekt reprezentujacy dany rekord dla danego id. Czyli dla kazdego id leci zapytanie do bazy - delikatnie rzecz mowiąc "średnio" optymalne smile.gif

Przyklad2 (edycja rekordu):
majac id rekordu ktory chcemy edytowac tworzymy dla niego obiekt a dane z obiektu przekazujemy do forma. Potem modyfikujemy dane w formie i zapisujemy. Dane z forma trafiaja do obiektu, a obiekt robi save w bazie - sposob przyjemny i zbytnio nie traci na optymalności. Jedyne zbedne zapytanie moze byc w momencie wcisniecia "zapisz" na formie i pobraniu danych rekordu, ktore i tak zachwile zostana zmodyfikowane (pod warunkiem ze form przeszedl walidacje). Ale mozemy sobie na to pozwolic

Przyklad3 (usuwanie rekordu):
Majac id rekordu do usunięcie tworzymy obiekt (wczytujemy dane z bazy) a nastepnie wywolujemy metodę Remove danego obiektu, ktora usuwa rekord z bazy. Zbedne wydaje się tu pobieranie danych rekordu, ktory i tak za chwile zostanie usuniety. Ale czy oby napewno? Czasami potrzebne nam są te dodatkowe dane zanim jeszcze usuniemy rekord. Chociazby poto by zapamietac informacje o tym, ze taki a taki user usunal taki a taki rekord

Podsumowujac:
Rozsądne używanie ActiveRecord umila życie programiście a jednocześnie nie obciąża zbytnio aplikacji

Napisany przez: splatch 27.03.2007, 21:59:00

Pragnę nadmienić, że w przypadku Propela nie trzeba każdorazowo powoływać do życia instancji obiektu. W chwili gdy mamy do czynienia z odpytaniem na rzecz tabeli możemy wykorzystać obiekt Criteria i przy jego pomocy wymodelować zapytanie delete. Troszkę problematyczny jest update. W przypadku wstawiania danych zapytanie jest wykonywane dopiero po wykonaniu metody save(), a więc, bez zbędnych dodatków.

Napisany przez: Sedziwoj 28.03.2007, 00:25:53

Może się wyda dziwne pytanie, ale czy obiekt nie może wyciągać danych z bazy, tylko kiedy są mu potrzebne a ich nie ma? Czyli nie podczas tworzenia a podczas odczytu (podkreślam kiedy ich nie ma).

Napisany przez: Hacker 29.03.2007, 18:43:47

Eeeee...
@Sedziwoj czy mi się zdaje czy mówisz o leniwej konkretyzacji??

Napisany przez: Sedziwoj 29.03.2007, 23:11:06

Ja piszę to co myślę, tak kochane 'wzorce projektowania' czy inne aspekty jak się okazało mi są obce, jak również zbędne, da się samemu wymyślić.

A chodzi mi o to co napisałem, chyba wyraziłem się jasno?
Że pobieramy dane nie przy tworzeniu obiektu, a przy wybieraniu nich.

A jako że nie mam zbytniego doświadczenia, pytam się o słuszność takiego postępowania, bo ma ono pewne zalety ale też wady. Tylko że ja mogę wszystkich nie widzieć (patrz brak doświadczenia) więc pytam, a że nie było to poruszane uważam, że jest na miejscu. (nie podaję tu swoich wywodów, bo oczekuję ich weryfikacji, ponieważ mogą okazać się moimi wymysłami tylko)

Napisany przez: splatch 31.03.2007, 11:03:35

Cytat(Sedziwoj @ 28.03.2007, 01:25:53 ) *
Może się wyda dziwne pytanie, ale czy obiekt nie może wyciągać danych z bazy, tylko kiedy są mu potrzebne a ich nie ma? Czyli nie podczas tworzenia a podczas odczytu (podkreślam kiedy ich nie ma).


Takie zachowanie jest wskazane a nawet konieczne. Często jeden obiekt referuje do kilku innych, z kolei te referują gdzieś dalej. Gdyby tworzyć wszystkie obiekty w fazie inicjowania obiektu orm cały proces byłby znacznie wydłużony. Technika wczytywania na żądanie zwie się http://martinfowler.com/eaaCatalog/lazyLoad.html. Zachowuje się to dokładnie tak jak opisywałeś swój problem. Może na przykładzie propela.

  1. <?php
  2. // pobieramy obiekt, Propel wykona zapytanie:
  3. // SELECT FROM authors WHERE author_id = 11
  4. $author = AuthorsPeer::retrieveByPK(11);
  5. while($book = $author->getBooks()) {
  6. // przegladamy ksiazki, tutaj jest wykonywane zapytanie:
  7. // SELECT FROM books WHERE author_id = 11
  8. http://www.php.net/echo $book->getTitle() .'<br />';
  9. }
  10. ?>


Lazy load jest wygodny, aczkolwiek warto pamiętać by go nie nadużywać ponieważ w pewnym momencie jego wpływ na działanie aplikacji stanie się ujemny i inicjowanie obiektu na początku wszystkimi wartościami będzie bardziej wskazane.

Napisany przez: pawel_k 26.04.2007, 14:16:59

@splatch - nie do konca dobry przyklad
pobierajac w propelu wiersz zwracany jest obiekt. problem w tym ze czesto chcesz pobrac np. tylko tytuly stron bez ich tresci, a samą treść tylko przy jej wyświetleniu w akcji show (która dajmy na to jest jeszcze w aplikacji cachowana). ustawiając w propelu lazy_load dla kolumny content w tabeli pages wartosc content pobierana jest tylko gdy wykonasz getContent() na obiekcie a nie zawsze gdy pobierasz dowolna ilosc obiektow pages.
jesli sie myle niech ktos mnie poprawi winksmiley.jpg

Napisany przez: cicik 27.04.2007, 09:15:45

Mnie przed ORMami odstrasza jedna rzecz.
Jeżeli mam powiedzmy użytkownika, który należy do jakiejś grupy.
I teraz chce dostać jego imię, nazwisko i nazwę grupy do której należy to w przybliżeniu musiałbym zrobić coś takiego:

$user = new User($id);
$group = $user->getGroup();

Co powoduje wykonanie dwóch selectów zamiast jednego używającego złączenia tabel.
Poza tym wszędzie gdzie czytam o ORMach to zawsze podawany jest przykład taki jak powyżej, który ma być uzasadnieniem tego, że to jest fajne.
Ale co w sytuacjach kiedy potrzebuję mieć zapytanie z kilkoma złączeniami, limitem, sortowaniem, funkcjami specjalnymi typu CONCAT, funkcjami agregującymi itp? Mam wtedy dla takiego zapytania zrobić perspektywę i użyć wzorca Active Record do opisania tej perspektywy? Niby tak można ale wtedy w bazie będę miał 10 razy więcej perspektyw niż tabel...

Napisany przez: athabus 27.04.2007, 10:09:51

Nie wiem jak to jest w innych ORM'ach ale właśnie zaczynam uczyć się propela i tam jest to dosyć ciekawie rozwiązane.

Z miejsca masz wygenerowane metody, służące do robienia joinow po foreign key. Możesz zarówno pobrać tylko jedną wybraną tablę, złączyć ją z jakąś tabelą, albo złączyć ją ze wszystkimi możliwymi tabelami.

Poza tym zawsze zostaje ci samemu odczytać odpowiednie dane wywołując odpowiednie zapytanie sql i użyć metody populateObject, która służy do wypełnienia obiektów ręcznie pobranymi danymi.

Ogólnie ORM'y (na przykładzie propela) mają swoje wady - chociażby dość duża ilośc kodu do przeparsowania (klasy propela są dość sporawe), ale jeśli chodzi o optymalność zapytań sql to zawsze idze je jakoś podrasować. Trzeba tylko sobie zdawać sprawę, że mechanizmy takie jak propel są po to, aby ułatwiać standardowe zadania i proste operacje - jeśli chodzi o te bardziej złożone to nikt tego za programistę nie zrobi.

Do niedawna miałem podobne zdanie do Ciebie, ale teraz gdy poznaje propela (dzięki właśnie temu tematowi) to zmieniam poglądy. Propel zdjął ze mnie konieczność pisania banalnego kodu do operacji CRUD i mogę się bardziej skupić nad logiką aplikacji jako całości. Jeśli chodzi o wydajność - to zgodzę się, że ORM nigdy nie będzie tak wydajny jak własne klasy - ale nie są to różnice na tyle duże aby sobie nimi zaprzątać głowę - co z tego, że aplikacja będzie chodziła 0,05s wolniej, jeśli dzięki temu zamiast pisać ją przez dwa tygodnie, zrobię to w 4-5 dni.

Napisany przez: dr_bonzo 27.04.2007, 10:10:38

Nie, chocby w Railsach masz :include => 'group' i wykona ci zapytanie z JOINEm do grup przy znajdywaniu usera (User::find($id)). Dodatkowo dodajesz ORDER i LIMITY. Po SQLu tez da sie znalezc obiekty

Napisany przez: Yacho 14.05.2007, 18:00:11

Cytat(athabus @ 19.03.2007, 15:02:56 ) *
Trzecia sprawa to to, że początkowy zysk w postaci szybszego kodowania jest opłacony przez mniejszą przejrzystość kodu w przyszłości.

No cos ty - to wyobraz sobie co sie dzieje w momencie kiedy masz aplikacje napisana z palca - i masz jakies 200 roznych SQL query - i klient jest bardzo przesądny i naprzyklad nie podoba mu sie pole czarny_kot w bazie danych - musisz zmienic 200 zapytań - w propelu jeden tag XML i działasz... winksmiley.jpg

pozatym myślę ze idea AR i ORM jest inna niż wszyscy myśla tu - klasy ORM sa po to aby juz enkapsulować jakąs logike biznesowa - powstały po to aby zintegrowac warste funkcjonalności biznesowych z dotyczacych tych danych. obiekt ORM jest po to zeby zdefiniowac także akcje jakie z obiektem sa powiazane, jest gdzies pomiedzy warstwa danych a biznesowa - natomiast nie ma watpliwosci ze AR jest tylko do ujednolicenia dostepu do bazy - na mniejszym stopniu abstrakcji niż ORM ale znacznie wiekszym niz bawienie sie w zapytania...

Napisany przez: athabus 14.05.2007, 21:27:35

Yacho nie dość, że cytujesz moją wypowiedź sprzed 2 miesięcy, to jeszcze była ona na temat AR a nie ORM tongue.gif

Tak jak tam pisałem odnosiłem się do AR na przykładzie ZF, z którym miałem okazję spędzić trochę czasu. Problem jak się tu pojawił to, to że w momencie zmiany nazwy pola w tabeli musiałbym poprawić wszystkie odwołania, które korzystały z tej tabeli - także akurat Twój przykład tutaj nie za bardzo był trafny.

Pod wpływem tego wątku zainteresowałem się ORM (konkretnie Propelem) o czym też zresztą pisałem już w tym wątku tongue.gif Powiem szczerze, że jestem pozytywnie zaskoczony tym rozwiązaniem - nie myślałem, że w PHP uda się takie coś popełnić. Właśnie kończę pierwszy projekt z wykorzystaniem Propel'a i to jest coś czego mi od dawna brakowało.

Co do ORM to nie podoba mi się przekonanie, że są one bez sensu bo przy skomplikowanych zapytaniach wykonują nieoptymalne operacje i są be. Wiadomo, że jeśli robisz joina po wielu tabelach, czy wykonujesz jakieś skomplikowane zapytanie, to automatix nie jest najlepszym wyjściem - ORM ułatwia korzystanie z bazy, ale nie zdejmuje z programisty konieczności myślenie i optymalizacji. Po prostu są rzeczy, które można zostawić Propelowi do zrobienia i są takie w których trzeba mu trochę pomóc.
W propelu podoba mi się to, że przewidziano możliwość własnego konstruowania zapytań czy dodawania logiki do klasy. Programowanie z Propelem to jest po prostu bajka.

Napisany przez: Sokal 23.05.2007, 17:57:58

Myślę sobie teraz o ORM...

Według mnie jest to utrudnianie sobie życia. Chyba lepiej poznać SQL niż uczyć się metod, które działają tak samo jak polecenia w SQL-u... Argument? Mamy jakieś złożone zapytanie, przy pomocy takiego ActiveRecords tego nie zrobimy. No i co? Musimy się uczyć SQL-a lub szukać po internecie jak coś zrobić. A nie lepiej od razu poznać go? Aplikacja działa szybciej, bo nie odpala iluś tam metod zanim wykona zapytanie.

IMHO ORM jest ułatwieniem dla początkujących winksmiley.jpg

Napisany przez: menic 23.05.2007, 18:05:32

Jestes w błedzie Misiu (a moze pingwinku;) )
Złozone zapytania? Ich raczej czesto nie piszemy.

Napisany przez: Sokal 23.05.2007, 18:11:20

A co powiesz na to, że piszesz jakąś super złożoną aplikację. W bazie trudno się połapać a złożone zapytania to są co drugą linijkę w kodzie.

Nie zrobisz tego przy użyciu, np. activerecords. Co prawda masz tam metodę query(), ale jak jest activerecords to po co taka metoda? snitch.gif Skoro: złożone zapytania => "Ich raczej czesto nie piszemy."...

Według mnie lepiej korzystać np. z PDO winksmiley.jpg

// I jeszcze jeden argument:
Przez ORM kod aplikacji się wydłuża

Napisany przez: bela 23.05.2007, 19:22:15

Cytat
// I jeszcze jeden argument:
Przez ORM kod aplikacji się wydłuża

kod? no prosze.

  1. <?php
  2. $news = NewsPeer::doSelect(new Criteria()); 
  3. ?>

jest dluzsze od selecta w sqlu?

poza tym, orm sprawia kod bardziej czytelnym

co do zlozonych zapytan, ja czesto ich nie uzywam, czasem zdarzaja sie join na dwoch poziomach, ktorych niestety propel jeszcze nie obsluguje. ale miejmy nadzieje ze propel 2.0 bedzie niebawem smile.gif

Napisany przez: menic 23.05.2007, 19:31:18

No to zaczynamy:
Sam AR moze i jest trudniejszy i bez sensu przy PDO, ale juz odpowiednio zbudowany ORM to juz inna bajka. Przyklady beda sie opierac na moim skrypcie. Dodatko do pelni szczescia potrzebne jest np. PHPIDE aby ladnie podpowiadalo metody obiektu snitch.gif Zacznijmy od tego ze strukture bazy danych definiujemy podobnie jak w propelu w xmlu. Na podstawie tego sa generowane odpowiednie klasy modelu. Najpierw "tworzymy" zapytanie

  1. <?php
  2. $oNews = new NewsModel();
  3. $oNews->addWhere( NewsModel::CAT_ID, swRequest::Get( 'id' ) );
  4. $oNews->addJoin( NewsModel::AUTHOR_ID, UsersModel::ID, 'LEFT' );
  5. $oNews->addJoin( NewsModel::CAT_ID, News_categoriesModel::ID, 'LEFT' );
  6. $aNews = $oNews->selectJoin();
  7. ?>

Mamy juz pobrane dane do $aNews. Wpisujujac $aNews-> otrzymujemy z podpowiedzi cala liste dostepych kolumn. Bo kazda kolumna ma metode getKolumna(). Dodatkowo dla dolaczonych tablel najpierw $aNews->joinJakasKolumna()->jakasKolumna() Oczywiscie wszystkie metody podpowiada nam eclipse. Tak by wygladala sprawa z pobieraniem danych. Przejdzmy teraz moze do ich dodawania snitch.gif
  1. <?php
  2. $oNews = new NewsModel();
  3. $oNews->setAuthor_id( 1 );
  4. $oNews->setCat_id( swRequest::Post( 'news_categories_id' ) );
  5. $oNews->setContent( swRequest::Post( 'content' ) );
  6. $oNews->setCREATED_AT( http://www.php.net/time() );
  7. $oNews->setTitle( swRequest::Post( 'title' ) );
  8. $oNews->insert();
  9. ?>
No i znowu tutaj kazda metoda odpowiada kolumnie w bazie danych. Dodatkowo mamy tutaj filtrowanie danych, tak wiec nie wstawimy jakiegos stringa do kolumny ktora oczekuja liczbe. I powiedz mi ze to jest niewygodne to cie normalnie nie wiem co tongue.gif

Napisany przez: Sokal 23.05.2007, 20:04:59

Dla mnie to zawsze będzie niewygnodne, co z tego, że podpowiada mi składnie...

Więcej czasu zabiera wykonywanie zapytań winksmiley.jpg

Napisany przez: menic 23.05.2007, 20:07:08

Co z tego? Np. to ze nie musisz pamietac nazw wszystkich tabel ani kolumn w bazie danych. To ze masz wieksza kontrole. To ze jest wygdniej tongue.gif Dorosniesz to zrozumiesz (joke) winksmiley.jpg

Napisany przez: webik 24.05.2007, 00:19:43

Witam

Ot dorzuce swoje 3 grosze.... Osobiście używam PEAR DB_DataObject... Bardzo mnie sie podoba mialem troch problemów tyczącyc sie pierwszegoo uruchomienia i pierwszego utworzenia klas odwzorowujacych tabele.... Ale teraz wszystko idzie gładko..... Wszystko tworzy sie automatycznie pozniej tylko wykorzystuje klasy... Do tej pory nie zauważylem nadmiaru zapytań chciaż czasem jestem zbyt wyrozumiały wobec ilośici zapytań generowanych przez moj kod... Wczećniej uzywałem ADOdb i teraz wydaje mnie sie ze teraz ograniczyłem liczbe zapytań.... Kod też staje sie bardziej przejżysty ot chodźby pobranie usera:

  1. <?php
  2. //$id = primary key;
  3. $user = DB_DataObject::factory('users_desc');
  4. $user->get($id);
  5. ?>


i w objekcie user mam odrazu wszystko, warunki nie ma problemu:

  1. <?php
  2. $user = DB_DataObject::factory('users_desc');
  3. $user->id = $id;
  4. $user->online = 1;
  5. $user->find();
  6. ?>


cala struktura klasy na podstawie bazy jest przygotowywana z pommocą skryptu.... wiec zero pracy do wykonania... No chyba że chcemy jekies specjalne warunki przy dodawaniu do bazy... validatory nie napisza sie same....

wydaje mnie sie proste i przyjemne...

Ale moze to tylko przyzwyczajenie....

Pozdrawiam

Napisany przez: mike 24.05.2007, 11:52:32

~Sokal a dlaczego uważasz że ORM jest dla osób nie znających SQL'a?
Tak się składa że jest dokładnie odwrotnie. Nie podejdziesz do żadnego ORM'a nie mając solidnych podstaw i wiedzy o SQL.

"IMHO ORM jest ułatwieniem dla początkujących winksmiley.jpg" - to Twoja opinia. A praktyka pokazuje że żaden większy bądź duży projekt nie jest pisany bez ORM'a
Już pomijam PHP, w Java na przykład większość aplikacji śmiga na http://www.hibernate.org.

Napisany przez: splatch 24.05.2007, 12:04:35

Cytat(Sokal @ 23.05.2007, 21:04:59 ) *
Dla mnie to zawsze będzie niewygnodne, co z tego, że podpowiada mi składnie...

Więcej czasu zabiera wykonywanie zapytań winksmiley.jpg

To po cholerę tu siedzisz, pytam? To forum to niby PRO więc się nie zachowuj jak dziecko i nie strzelaj fochów, że coś Ci się nie podoba i basta. Po cholerę wcinałeś się do tego wątku, tylko po to, żeby pokazać swoje wstecznictwo i ciemnotę? Jeśli nie masz więcej argumentów przeciw to, proszę, zamknij się i nie wtrącaj z byle gównem.

Ps. Jestem za usunięciem postów-śmieci z tego wątku (w tym i mojego).

Napisany przez: athabus 26.05.2007, 18:27:32

splatch ty jakiś agresywny ostatnio jesteś blink.gif

Sokal - ORM nie jest po to aby nie uczyć się SQL. Ideą (tak mi się przynajmniej wydaje) to zdjęcie z programisty powtarzania ciągle tych samych operacji na bazie danych. Ciagłego pisania banalnych selectów itd. W PHP w porównaniu z innymi językami duży procent rzeczy, które robisz są "banalne", dlatego, że nie ma narzędzi automatyzujących pracę, albo mało osób z nich korzysta.

Powiem szczerze, że czasami jak pisze jakąś prostą stronkę to już mi się chce za przeproszeniem rzygać jak muszę napisać kolejny obiekt DAO, który w zasadzie robi to samo co inne tylko ma trochę inne nazwy pól itp. Dzięki Propelowi, frameworkom itd itp możesz skupić się na tych bardzie zawiłych rzeczach, a te rutynowe zostawiasz odpowiedniemu narzędziu.

Co do tego, że ORM jest dla osób nie znających SQL to mam takie zdanie jak Mike - żeby napisać dobrze coś w ORM trzeba na prawdę orientować się jak działa SQL i w ogóle baza danych. Trzeba wiedzieć, kiedy użyć gotowych rozwiązań ORM, a kiedy warto rozszerzyć daną klasę np. o pobieranie kolekcji nietypowych elementów.

Przykład z życia - masz sklep internetowy w którym produkty przynależą do różnych kategorii, mają różne stawki vat, marki, cechy. Liczba cech produktu jest zmienna. Każdy produkt ma różne progi rabatowe itd itp. Stajesz przed zadaniem pobrania x produktów z bazy z pełną informacją (czyli dodatkowe cechy, progi rabatowe itd). Gdybyś tutaj użył ORM'a bez własnej inwencji to położyłbyś bazę na łopatki ilością zapytań. Pół dnia zajęło mi, aby to zoptymalizować, napisać własne metody pobierania i wypełniania obiektów itd. Ale skutek jest taki, że dowolną ilość obiektów z bazy pobieram 2 zapytaniami Wcześniej jednak musiałem użyć tabel przejściowych, trochę cachowania itd. Mechanizmy Propela pozwoliły mi przebrnąć przez całe zadanie w miarę wygodnie - ale na pewno nie rozwiązały same mojego problemu - po prostu były punktem wyjścia. Swoją drogą było to fajne doświadczenie, bo rozwiązując kolejne problemy przejrzałem kod propela wzdłuż i wszerz - pewne rzeczy wydawały mi się na początku dziwne, ale potem często zauważałem ich uniwersalność i możliwość dostosowania całego narzędzia do swoich potrzeb.

Napisany przez: eai 31.05.2007, 14:10:14

Nie ukrywam, temat dość ciekawy.
Nie wiem jednak czy dobrze to zrozumiałem, a nie chce tkwić w błędzie dlatego napisałem:

  1. <?php
  2.  
  3. class Query
  4. {
  5.  public http://www.php.net/static function http://www.php.net/exec ($sql)
  6.  {
  7. if(http://www.php.net/mysql_connect('localhost','root', 'idesql'))
  8. {
  9.  if(http://www.php.net/mysql_select_db('test'))
  10.  {
  11.  return new ORM(http://www.php.net/mysql_query($sql));
  12. }
  13. }
  14. }
  15. }
  16.  
  17. class ORM
  18. {
  19.  private $__dquery = http://www.php.net/array();
  20.  
  21.  public function __construct($query)
  22.  {
  23.  $this->__dquery = $query;
  24. }
  25.  
  26.  public function select()
  27.  {
  28. if($array = http://www.php.net/mysql_fetch_assoc($this->__dquery))
  29. {
  30.  return new Data($array);
  31. }
  32.  
  33. return false;
  34. }
  35. }
  36.  
  37. class Data
  38. {
  39.  private $__darray = http://www.php.net/array();
  40.  
  41.  public function __get($name)
  42.  {
  43. if(http://www.php.net/empty($this->__darray)) { return false; }
  44.  
  45.  if(http://www.php.net/array_key_exists($name, $this->__darray))
  46.  {
  47. return $this->__darray[$name];
  48.  }
  49. }
  50.  
  51.  public function __construct($array)
  52.  {
  53.  $this->__darray = $array;
  54. }
  55. }
  56.  
  57.  
  58.  
  59. $table = Query::http://www.php.net/exec('SELECT * FROM `tabela`');
  60.  
  61. while($row = $table->select()) {
  62. http://www.php.net/echo $row->nr . '; ';
  63. http://www.php.net/echo $row->imie . '; ';
  64. http://www.php.net/echo $row->nazwisko . ' <br>';
  65. }
  66.  
  67.  
  68. ?>


Jest to oczywiście bardzo prosty przykład, posiadający jedynie możliwośc pobierania wyników.

Moje pytanie brzmi: Czy ide w dobrym kierunku czy kompletnie nie zrozumiałem ORM?

Napisany przez: splatch 31.05.2007, 17:40:38

Cytat(eai @ 31.05.2007, 15:10:14 ) *
Moje pytanie brzmi: Czy idę w dobrym kierunku czy kompletnie nie zrozumiałem ORM?


Idziesz w prawie dobrym kierunku. smile.gif
Ideą stosowania mapowań jest wykluczenie klepania SQLa na każdą potrzebę, a w tym momencie, mimo tego, że wynik masz reprezentowany w postaci obiektu, a nie różni się to od:
  1. <?php
  2. $rs = http://www.php.net/mysql_query($sql);
  3. while ($row = http://www.php.net/mysql_fetch_object($rs)) {
  4. http://www.php.net/echo $rs->id .' '. $rs->name .'<br />';
  5. }
  6. ?>


Owszem, umiejętność interpretacji każdego zapytania to cenna funkcjonalność, ale nie zapominaj o tym, że zależy Ci na obiektach jako takich a nie płaskich strukturach pokroju tablicy, a taki efekt uzyskujesz korzystając z __get (zwracasz po prostu kolumnę z wyniku nie zwracając uwagi na to z jakiego obiektu to jest property). Zwróć uwagę, że tu nie ma obiektu. Nie możesz odczytanych wartości zmodyfikować i zapisać.
Obiekt Query może się przydać przy mapowaniu zapytań, ale raczej nie przy ich interpretowaniu.

Kilka przykładów użycia "klasycznego" ORM:
  1. <?php
  2. // Użycie sesji, na podobę Hibernate
  3. // zauważ, że relacje są przeźroczyste
  4. $factory = SessionFactory::build(new PropertiesConfiguration('php-hibernate.ini'));
  5. $session = $factory->getSession();
  6.  
  7. $book = $session->load('Book', 11);
  8. $authors = $book->getAuthors(); // tutaj oczekujemy złączenia po relacji M:N
  9. $book->setTitle('[nakład wyczerpany]' . $book->getTitle());
  10. $book->setAvailable(false);
  11. $authros[0] = new Author('Stanisław', 'Lem');
  12.  
  13. $session->flush(); // wymuszamy zapisanie zmian
  14.  
  15. // uproszczony przykład użycia Table Data Gateway + Row Data Gateway
  16. // relacje M:N są obsługiwane ręcznie
  17. $book = BooksPeer::retrieveByPk(11);
  18. $authors = $book->getAuthors();
  19. $book->setTitle('[nakład wyczerpany]' . $book->getTitle());
  20. $book->setAvailable(false);
  21. // dobieramy się do tabelki pośredniej pomiędzy autorami a książkami
  22. $authros[0]->getProxyForBook(11)->delete();
  23. $authros[0] = new Author('Stanisław', 'Lem');
  24.  
  25. $authros[0]->createProxyForBook(11); // przywiązujemy autora do książki
  26. $book[0]->save(); // ten zapis załatwia nam wszystko
  27. ?>


Pamiętaj, że różnice implementacji przy różnych ORMach są czasami olbrzymie, zawsze możesz znaleźć swoją własną implementację bazując na http://martinfowler.com/eaaCatalog/.

Napisany przez: nasty 2.06.2007, 13:28:42

Witam,
Chciałbym się odnieść do wypowiedzi paru osób które uważają ze ORM-y to tylko ułatwienie dla programisty, i ze jest ucieczka od nauki SQL-a.

Najważniejszą idea systemów ORM jest wspomaganie idei Domain-Driven-Develpment (DDD) która przeważnie jest podzielona na warstwy takich jak:

Używając tradycyjnych metod dostępu do danych byłoby bardzo ciężko dobrze wymodelować warstwę logiki biznesowej bo np. powiedzmy ze Książka może dostać zniżkę tylko w wypadku kiedy jest kupowana w ilości x/miesiąc oraz ma Dostawce który jest na liście stabilnych dostawców. W tym przypadku używając reprezentacji danych w postaci obiektów, łatwo jest wymusić taka logikę na aplikacji na wiele sposobów takich jak używanie systemu workflow.

Drugim bardzo ważnym argumentem przemawiającym za ORM-ami jest zasada DRY (Don't Repeat Yourself). gdyż obiekty z Business Entities nierzadko biorą udział w Service Layer czyli w warstwie odpowiedzialna za eksponowanie funkcjonalności aplikacji za pośrednictwem Web Services. Używając SQL-a i tak byś musiał operować na obiektach by móc reprezentować dane w wspomnianej Service Layer, tak wiec musiałbyś najpierw wyciągać dane z tych obiektów, następnie zapisywać do bazy SQL-em a w razie potrzeby znowu wyciągać te dane sql-em i zapisywać do obiektów. UI tez czesto uzywa Business Entities...

I jeszcze jedno: używając systemu ORM, możemy wymusić walidacje danych z poziomu samych obiektów poprzez umieszczanie logiki walidacyjnej w setter-ach. W przypadku SQL-a byłoby kilka if() else() przed zapisem.

Dla tych którzy maja bardzo duże wątpliwości co do ORM-ow zalecam przyjrzenie się bardziej dojrzałym produktom takim jak (N)Hibernate, gdzie to ORM może zapisywać dane do prywatnych pól, które są i tak nie eksponowane przez obiekt a wykorzystywane w operacjach logicznych.

Pozdrawiam

Napisany przez: Sokal 12.06.2007, 17:33:19

Chyba mnie przekonaliście do ORM-a winksmiley.jpg
Propel jest zajebiaszczo prosty w obsłudze, a możliwości są wielkie.
Miałem po prostu złe doświadczenia z ORM'em po poznaniu CodeIgniter'a. A kiedy chciałem poznać Propel to miałem same problemy, a to nie ma rozrzerzenia PHP - xslt (które było) a to co innego ...

W piątek spróbowałem jeszcze raz, a wcześniej jakiś tydzień temu w Symfony. Wszystko działa super smile.gif

//
Za moje poprzednie posty przepraszam.

Napisany przez: Martio 6.07.2007, 01:05:47

Jakie znacie lub macie u siebie zaimplementowane sposoby rozwiązania problemu z relacjami pomiędzy tabelami? Jak rozwiązujecie konieczność pobrania danych z bazy danych przy złożonym warunków opierającym się o dwie tablice?

Napisany przez: SongoQ 6.07.2007, 01:15:01

Takie cos jest w ORMach zaimplementowane. Patrz np propel http://propel.phpdb.org/trac/wiki/Users/Documentation/1.3/Relationships

Napisany przez: NuLL 6.07.2007, 01:17:38

lub w phpDoctrine smile.gif

Napisany przez: splatch 6.07.2007, 07:48:08

Cytat(splatch @ 31.05.2007, 18:40:38 ) *
Pamiętaj, że różnice implementacji przy różnych ORMach są czasami olbrzymie, zawsze możesz znaleźć swoją własną implementację bazując na http://martinfowler.com/eaaCatalog/.


Wystarczy zajrzeć pod wspomniany adres..

Data Source Architectural Patterns Table Data Gateway, Row Data Gateway, Active Record, Data Mapper.
Object-Relational Structural Patterns Identity Field, Foreign Key Mapping, Association Table Mapping, Dependent Mapping, Embedded Value, Serialized LOB, Single Table Inheritance, Class Table Inheritance, Concrete Table Inheritance, Inheritance Mappers.
Object-Relational Metadata Mapping Patterns Metadata Mapping, Query Object, Repository.

Napisany przez: g00fy 21.07.2007, 23:55:44

Cytat(cicik @ 27.04.2007, 08:15:45 ) *
Mnie przed ORMami odstrasza jedna rzecz.
Jeżeli mam powiedzmy użytkownika, który należy do jakiejś grupy.
I teraz chce dostać jego imię, nazwisko i nazwę grupy do której należy to w przybliżeniu musiałbym zrobić coś takiego:

$user = new User($id);
$group = $user->getGroup();

Co powoduje wykonanie dwóch selectów zamiast jednego używającego złączenia tabel.
Poza tym wszędzie gdzie czytam o ORMach to zawsze podawany jest przykład taki jak powyżej, który ma być uzasadnieniem tego, że to jest fajne.
Ale co w sytuacjach kiedy potrzebuję mieć zapytanie z kilkoma złączeniami, limitem, sortowaniem, funkcjami specjalnymi typu CONCAT, funkcjami agregującymi itp? Mam wtedy dla takiego zapytania zrobić perspektywę i użyć wzorca Active Record do opisania tej perspektywy? Niby tak można ale wtedy w bazie będę miał 10 razy więcej perspektyw niż tabel...


ormy obsluguja transakcje,rozne rodzaje fetchingu etc... btw , zawsze mozesz zrobc RAW SQL jesli jakies zapytania przez orm robia sie bardzo uciazliwe..

Napisany przez: XvZOK 30.07.2007, 15:53:15

A jak Propel radzi sobie z dziedziczeniem w klasach ?

Przykladowo mam klase
Contractor i dziedziczy po niej Client oraz Supplier

Dostawca i klient maja wiele wspolnych pol wiec warto by bylo
zastosowac tu relacje 1-1.
W efekcie mamy 3 klasy w tym 2 dziedziczace i odpowiadajace im tabele.

O ile nie ma problemu z np.: wstawieniem listy transakcji
do klienta (ralacje 1-n) to nie wiem czy propel
poradzi sobie w sytuacji kiedy to 1 klasa bedzie de facto zapisywac do 2 tabel ?

Jakies doswiadczenia w tym temacie ?
Moze inne ORM niz propel ?




2 temat to kwestja konwersji UML do schematu bazy danych.
Googluje juz od kilku dni ale jedyne co znalazlem to MetaL.
Nie dziala on jednak rewelacyjnie i konwertuje to swojego formatu a nie do schema.xml znanego z propela.

Napisany przez: Sedziwoj 31.07.2007, 18:56:32

Cytat(XvZOK @ 30.07.2007, 16:53:15 ) *
2 temat to kwestja konwersji UML do schematu bazy danych.
Googluje juz od kilku dni ale jedyne co znalazlem to MetaL.
Nie dziala on jednak rewelacyjnie i konwertuje to swojego formatu a nie do schema.xml znanego z propela.

A może coś opisanego http://www.gajdaw.pl/bd/dbdesigner-propel.html ?

Napisany przez: splatch 31.07.2007, 20:14:53

Cytat(XvZOK @ 30.07.2007, 16:53:15 ) *
A jak Propel radzi sobie z dziedziczeniem w klasach ?

Propel radzi sobie z dziedziczeniem w klasach, aczkolwiek nie jest to "wypasiona" opcja.

Gdyby nazywać to zgodnie z nomenklaturą jest to dziedziczenie zorganizowane na jednej tabeli z dyskryminatorem, czyli kolumną której wartości wskazują z czym mamy do czynienia. Opis wraz z diagramem UML - http://martinfowler.com/eaaCatalog/singleTableInheritance.html.
Dokumentacja Propela:
http://propel.phpdb.org/docs/user_guide/chapters/AdvancedObjectModel.html.

Przykładowy kod:
Kod
            Client
         /         \
    Enterprise       PrivateClient
                       \
                      CompanyWorker



  1. <table name="client" abstract="true">
  2. <column name="client_type" type="INTEGER" inheritance="single">
  3.   <inheritance key="0" class="PrivateClient" extends="nazwabazydanych.Client"/>
  4.   <inheritance key="1" class="CompanyWorker" extends="nazwabazydanych.PrivateClient"/>
  5.   <inheritance key="2" class="EnterpriseClient" extends="nazwabazydanych.Client"/>
  6. </column>
  7. <column name="title" type="VARCHAR" size="100"/>
  8. </table>

Napisany przez: XvZOK 27.11.2007, 00:15:41

Ponownie wróciłem do tematu.
Widzę, że tutaj nie za dużo się wydarzyło.

Ostatnio zrobilem release tematu podczas tworzenia
abstrakcyjnego kontrolera CRUD do ZF.
Dziwi mnie fakt ze podczas dyskusji o ORM
nikt nie wspomniał o wygodzie przy tworzeniu warstwy widoku.

Przykładowo bibloteka patForms potrafi na podstawie obj. propela
wygenerować nam formularz do wpisywania/edycji danych.
Możemy oczywiście go dowolnie edytować w pliku XML.

Obecnie stosuje zestaw Zend Framework + Propel + Smarty.
Zastanawiam się jednak nad PEAR::DBObject

Testowaliście obydwa pod względem wydajności, wygody użycia ?

Wspomnę jeszcze o DataGrid.
Co polecacie ? Propel dostarcza niby klasę pozwalającą na
integrację z DataGrid z PEAR ale od razu mówie.. wersja jest przestarzała
i lepiej wogóle jej nie ruszać. Ja straciłem 3 h, poznałem dokładnie budowę
DataGrid iw końcu napisałem prawie od nowa klasę integrującą.
Ale teraz efekt jest bardzo przyjemny.

Napisany przez: athabus 27.11.2007, 10:59:33

Myślę, że o widoku nikt nie wspomniał, bo temat nie dotyczy widoku :-)

A tak na serio to jeśli już mówimy o wygodzie projektowania aplikacji działających w oparciu o ORM to dla mnie nic nie przebije generacji paneli administracyjnych w symfony

http://www.symfony-project.org/screencast/admin-generator

Kilka linii w pliku konfiguracyjnym i masz wszystko - przeglądanie, dodawanie danych, walidację danych, łączenie danych z wielu tabel po kluczach obcych itd itp.
Jak to pierwszy raz zobaczyłem to się popłakałem, że tyle czasu traciłem na takie bzdety ;-) Zwykły crud to przy tym zabawka.

Inny przykład też z symfony to umieszczenie danych testowych w tabeli z pliku yml - piękna sprawa przy robieniu pierwszych testów.

Napisany przez: splatch 27.11.2007, 11:55:44

Kwestia ORM i widoku nie wiąże się pośrednio, ponieważ kluczowe są tu metadane i informacje o strukturach z których ORM korzysta.
Propel ułatwia nam zadanie ponieważ mamy wygenerowany kod z informacjami na temat powiązań itp (bodajże katalog metadata obok innych wygenerowanych klas).
W przypadku ActiveRecord informacje te są zapisane jako fragment definicji w modelu (has_many, many_to_many itp).

Wystarczy zatem bezpośrednio podpiąć się pod metadane i umiejętnie je wykorzystać a nie będziemy potrzebowali generatorów.

Kiedyś dawno, dawno temu dopisywałem adaptery wiążące Propel-Agavi-Smarty tak by tworzyć nowe widoki i wyszukiwarki możliwie łatwo. Dodatkowo powiązałem sobie etykiety z klas z i18n, przez co przy polach wyszukiwania nie musiałem męczyć się z dorzucaniem labeli. Robiły to za mnie po prostu pluginy dopisane do smarty.
Kod, który nie jest wierną kopią tego co napisałem aczkolwiek prezentuje zbliżoną funkcjonalność.

  1. {search for='NazwaKlasy' action=jakiś_url}
  2.  
  3. {field for=id} <- pole z mo&#380;liwo&#347;ci&#261; wpisania tylko intów
  4.  
  5. {field for=foreign} <- tu mi si&#281; pokazywa&#322; np select
  6.  
  7. {field for=someDate fromTo=true} <- a tu para data od, data do
  8. {/search}


Dodatkowym elementem, który sobie wytworzyłem było wiązanie np inputów z wartościami niektórych pól. Dzięki temu nie trzeba podawać atrybutu value, id i tak dalej, ponieważ wszystko to można wyciągnąć dynamicznie z requestu w samym pluginie.
  1. {input for=text}


Po stronie PHP dodałem jeszcze element który nazwałem, może niezbyt trafnie, wrapperem. Jego użycie było bardzo proste i sprowadzało się w poszczególnych akcjach do podobnego kodu:
  1. <?php
  2. $wrapper = new PropelWrapper($this->getAgaviContext());
  3. try {
  4. if ($mode == 'new') {
  5. $object = $wrapper->createAndBindObject('Invoice');
  6. } else {
  7. $object = $wrapper->readAndBindObject('invoice', 'nazwa_pola_z_id_obiektu');
  8. }
  9. // tu otwarcie transakcji 
  10. $object->save();
  11. // i zamknięcie
  12. return 'Success';
  13. } catch (WrapperException $e) {
  14. handleWrapException($e);
  15. } catch (PropelException $e) {
  16. handlePropelException($e);
  17. } catch (Exception $e) {
  18. handleException($e);
  19. }
  20.  
  21. ?>

Przy odrobinie wysiłku akcja mogła by sprowadzać się tylko do:
  1. <?php
  2. // tym kodem załatwiamy edycję
  3. class InvoiceEditAction extends InvoiceInnerAction {
  4.  
  5. }
  6.  
  7. // tym kodem dodawanie
  8. class InvoiceAddAction extends InvoiceInnerAction {
  9. }
  10.  
  11. // klasa bazowa dla operacji z fakturą
  12. class InvoiceInnerAction extends WrapperAction {
  13. // jedyna rzecz jakiej wymaga od nas wrapper
  14. protected function getClassName() {
  15. return 'Invoice'
  16. }
  17. }
  18.  
  19. // tym kodem listowanie
  20. class InvoiceListAction extends ListAction {
  21. protected function getClassName() {
  22. return 'Invoice'
  23. }
  24. }
  25. ?>



Napisanie takiego "czegoś" to na prawdę ciekawe zadanie a integracja z zewnętrznymi bibliotekami może dać na prawdę sporo możliwości. Np kod, który udało mi się stworzyć w końcu zaczęła używać osoba, która nie była programistą tworząc widoki od ręki bazując tylko na strukturze bazy danych. Jedyna rzecz jaką musiała potrafić to dobrze sklecić szablon Smarty. Programista wówczas pisał logikę i nie zawracał sobie głowy resztą.

Napisany przez: Martio 26.02.2008, 00:54:43

Używam Zend Frameworka. Chciałbym oddzielić warstwę logiki biznesowej od warstwy dostępu do danych. Dla warstwy logiki biznesowej najlepiej pasowałoby zastosować wzorzec "Domain Model". Jak wykorzystać "Zend_Db_Table" wraz z "Zend_Db_Table_Row" jako warstwy dostępu do danych? Mogę prosić o praktyczne zastosowanie?

Napisany przez: regis87 26.02.2008, 20:05:52

Testowałem różne dostępne rozwiązania ORM, najlepiej moim zdaniem wypada DoctrinePHP. Jest bardzo prosty w implementacji, wygodny, ma ogromne możliwości. Także jeżeli komuś zależy na takich "ułatwieniach" to zdecydowanie polecam. Ja jednak zostanę przy pisaniu zapytań i "czystym" PDO. Powód? Pod koniec moich testów odpaliłem sobie Apache Benchmark.

Na bazie testowej (tabele: artykuly, users, tagi, artykuly_x_tagi - jakie tu panują relacje chyba widac smile.gif ) porównałem wydajność dwóch aplikacji:
1) w moim frameworku (prosty mvc, sesje, pare bibliotek, widok obsluguje TemplateLite) prosta aplikacja pobierająca rekordy z bazy, zapytania w SQL poprzez PDO;
2) te same zapytania w Doctrine i wyniki wyprintowane, bez żadnej "obudowy" w postaci frameworka, także teoretycznie powinno być wydajniej

Wyniki - prawie czterokrotnie większa wydajność pierwszej opcji. Wniosek - ORM to piękna rzecz, ale w dużych projektach gdzie wydajność to priorytet, lepiej sobie darować.

Napisany przez: Sedziwoj 27.02.2008, 10:37:16

@regis87

I moim zdanie się mylisz, jak jest duży projekt bez ORM to masakra.
A co do wydajności, to jak masz wiele do wielu to tak zawsze jest, ale pamiętaj że korzystając z ORM najbardziej zachłanne rzeczy można przepisać na niższy poziom, czyli wykorzystując tylko abstrakcję bazy danych.

Do tego tak często nie doceniane widoki (przez większość zwane perspektywami) się przy stosowaniu ORM bardzo przydają.

Bo nie można zaprzeczyć, że ORM jest bardziej obciążający niż prosty dostęp, ale tak samo programowanie obiektowe (w tym wspomniane MVC) też jest wolniejsze od proceduralnego, jednak jakoś nikt na to nie zwraca zbytniej uwagi, chyba że jest jakiś punkt gdzie wydajność siada, ale to się małe fragmenty kodu zmienia, nie całą aplikację.
"Nie używajmy ORM", to prawie jakby mówić "piszmy w asemblerze". Może trochę przesadzam, ale jak się nie przestawia korzyści, i gada głupoty że w dużych projektach to lepiej bez... to mnie to irytuje.
Oczywiście zawsze się znajdzie coś co musi być napisane w asemblerze, ale to są na prawdę specyficzne rzeczy, a nie typowe aplikacje.

Napisany przez: Cysiaczek 27.02.2008, 10:52:09

W 100% popieram. Za całą obiektową otoczką takiego Propela lecą zwykłe zapytania SQL, a jedynie konieczność utworzenie obiektów ze zwracanego wyniku lekko spowalnia. Lepiej zatem (jak mówi Sedziwoj) pisać z użyciem ORM, a potem jedynie odnaleźć bardzo czasochłonne operacje i je przepisać. Zauważ, że jak coś jest bardzo zasobożerne, to jest to zazwyczaj operacja na ogromnych ilościach danych na raz. Z autopsji powiem, bo dziś w nocy troszkę potestowałem, że operacje z wyszukiwaniem LIKE %xxx% na 250 000 rekordach to 3.49 s gołe zapytanie i 3.6 s Propel (wliczam utworzenie paczki z danymi).

Pozdrawiam.

Napisany przez: splatch 27.02.2008, 12:09:19

Może w kwestii dużych projektów. Panowie nie zapominajmy, że duże projekty zazwyczaj stoją na dedykowanych maszynach, gdzie nie martwimy się tym, że nasz dostawca odetnie vhosta z racji na generowane obciążenie. Z drugiej strony - jakie są różnice czasowe, bo procentowo jest to dużo, ale czy będzie to odczuwalne dla użytkownika?
Nie pracowałem może w największych projektach, ale ilość linii kodu szła w tysiące czy też dziesiątki tysięcy. Gdyby każdy miał klepać zapytania, bo "tak jest wydajniej" to stracili byśmy na tym zbyt wiele czasu. Podstawą w takich wypadkach jest ORM i dobrze skonstruowane DAO, tak by nie pojawiały się metody duplikujące swe działania (pytanie - które DAO co może odczytywać). Zaoszczędzasz czas upraszczając sobie pracę z pozyskanymi danymi - w dalszym ciągu masz obiekty, w których możesz zawrzeć jakieś w miarę proste operacje, a nie półśrodki w postaci tablic bądź map. Chodzi o to, że gdy ORM stworzy Ci obiekt powiedzmy faktury - tworzysz metodę isPaid a w niej masz jakiś warunek. Normalnie, pisząc strukturalnie - ten warunek przerzuciłbyś do kontrolera bądź, co gorsza, widoku. Gdy coś się zmienia w sposobie uznawania płatności i masz ORM modyfikujesz tylko jedną metodę. Nie szukasz wszystkich warunków, gdzie dany typ danych się przewija.

Popatrzcie proszę na ORM przez perspektywę tego, co może dać nam obiekt smile.gif.

Napisany przez: regis87 27.02.2008, 17:22:42

Może źle to ująłem. Mówiąc o dużych projektach nie mam na myśli bardzo rozbudowanych aplikacji z ogromną funkcjonalnością. Chodzi mi raczej o serwisy, które wystawione są na działanie bardzo dużej liczby użytkowników, a więc wywołań. Sam rozmiar bibliotek ORM daje do myślenia - po skompilowaniu DoctrinePHP do pojedyńczego pliku, zajmuje on prawie 700KB. Bez kompilacji jest jeszcze gorzej, bo wszystko rozbite jest na nie dziesiątki, ale setki plików klas. Z tego co wiem podobnie wygląda to w przypadku Propela.

Ale... jakiś czas temu trafiłem na bibliotekę realizującą wzorzec ORM, o nazwie Pork. Jest bardzo mała, szybka... trzeba to przetestować smile.gif

http://www.schizofreend.nl/Pork.dbObject

Napisany przez: Cysiaczek 27.02.2008, 17:27:41

W przypadku Propela masz kilka plików + te, które sam wygenerujesz.
Rozumiemy, o co chodzi z dużą ilością odwiedzin, ale w którym momencie upatrujesz koniec sensowności ORM? Ile odwiedzin dziennie?

Napisany przez: regis87 27.02.2008, 17:55:22

Nie potrafię tego oszacować. Ale kiedy wydajność staje się problemem, w ORM w pierwszej kolejności szukałbym oszczędności...

Napisany przez: Cysiaczek 28.02.2008, 00:47:10

Jeśli dysponujesz dedykowanym serwerem, to moim zdaniem problemy zaczną się gdzieś w okolicach kilkudziesięciu tysięcy odsłon dziennie. Bardzo mało serwisów osiąga takie liczby. Ja bym w tym wypadku zainwestował w jakiś cache dla modelu danych, czy nawet w cachowanie całych stron www. Dopiero gdyby to nie pomogło, szukałbym optymalizacji zapytań. Nie będę rzucał liczbami, ale np. forum.php.pl mimo, że jest popularnym, średniej klasy forum nie osiąga jeszcze pułapu, przy którym zdycha sprzęt ;p

Pozdrawiam

Napisany przez: Martio 28.02.2008, 18:36:04

Cytat(Martio @ 26.02.2008, 02:54:43 ) *
Używam Zend Frameworka. Chciałbym oddzielić warstwę logiki biznesowej od warstwy dostępu do danych. Dla warstwy logiki biznesowej najlepiej pasowałoby zastosować wzorzec "Domain Model". Jak wykorzystać "Zend_Db_Table" wraz z "Zend_Db_Table_Row" jako warstwy dostępu do danych? Mogę prosić o praktyczne zastosowanie?


W sumie jakby nie było, to połączenie Zend_Db_Table_Row z DomainModel to wzorzec wypisz wymaluj.... ActiveRecord smile.gif

Mam pytanie do osób, które korzystają z wzroca Active Record. Czy implementujecie w nim logikę biznesową?

Przykład:

  1. <?php
  2. class Produkt extends ActiveRecord {}
  3. class Zamowienie extends ActiveRecord {
  4. public function obliczWartoscZamowienia() {
  5.  $produkty = $this->pobierzZamowioneProdukty();
  6.  
  7.  $wartosc = 0
  8.  
  9.  foreach ($produkty as $produkt) {
  10. $wartosc += $produkt->pobierzCene() * $produkt->pobierzIlosc();
  11.  }
  12.  
  13.  return $wartosc;
  14. }
  15. }
  16. ?>

Napisany przez: menic 28.02.2008, 18:40:32

@up: TAK

Napisany przez: regis87 2.03.2008, 22:49:39

Skończyłem testy, http://www.schizofreend.nl/Pork.dbObject. Jest imponujący pod względem wydajności i małych rozmiarów, ale ma ten mankament, że aby obsługiwać relacje pola w tabelach muszą być nazywane według ustalonego schematu. Ten schemat tak naprawdę wymusza PRAWIDŁOWE nazewnictwo pól: pole primary nazywa się ID_obiekt, pola będące kluczami relacji mają nazwy odpowiadających kluczy primary itd... ale wiadomo jak to wygląda w praktyce, rzadko zdarzają się tak ładnie skonstruowane bazy smile.gif
Autor mówi, że to właśnie takie ograniczenie pozwala na tę oszczędność kodu. Ale w planach ma dodanie funkcjonalności tworzenia relacji "ręcznie".

Napisany przez: Strzałek 14.03.2008, 23:52:02

To może ja coś skrobnę od siebie, o moich doświadczeniach z ORM, a konkretnie z http://www.phpdoctrine.org/. Obok wcześniej wspominanego Propela jest to jedeno z najpopularniejszych narzędzi tego typu. Doctrine przeciwieństwie do Propela nie generuje żadnego kodu. Oraz właściwie nie uwalnia nas do końca od pisania SQL. Jednak MASYMALNIE go uprasza i przyśpiesza. Mianowicie, w Doctrine definuje się każdą tablę np. tak (przykłady będą z dokumentacji)

  1. <?php
  2.  
  3. class Article
  4. {
  5. public function setTableDefinition()
  6. {
  7. $this->hasColumn('name', 'string');
  8. $this->hasColumn('content', 'string');
  9.  
  10. $this->index('content', http://www.php.net/array('fields' => 'content',
  11. 'type'  => 'fulltext'));
  12. }
  13. }
  14.  
  15. ?>
  16.  
  17. <?php
  18.  
  19. class Product extends Doctrine_Record
  20. {
  21. public function setTableDefinition()
  22. {
  23. $this->hasColumn('id', 'integer', 4, 'primary');
  24. $this->hasColumn('price', 'decimal', 18, http://www.php.net/array('min' => 0, 'max' => 1000000));
  25. }
  26. }
  27.  
  28. ?>


W metodzie setUp ustawia się relacje do innych Rekordów (czyli klas "odpowiadających" tabelom w db). Przykładowe wyciąganie z bazy danych wygląda tak:

  1. <?php
  2. $q = new Doctrine_Query();
  3. $q->from('User u')
  4. ->leftJoin('u.Group g')
  5. ->innerJoin('u.Phonenumber p WITH u.id > 3')
  6. ->leftJoin('u.Email e');
  7.  
  8. $users = $q->execute();
  9.  
  10. //używanie danych, przykładowo ilustruje jak to wygląda. Nie wiem jakie są pola w 
    bazie dancyh. 
  11. $users[0] -> name;
  12. $users[0] -> Phonenumber -> number;
  13. ?>


Gdzie zamiast nazw tabel podaje się nazwy rekordów. To jest właśnie DQL - Doctrine Query Language. Zapytanie zostaje parsowane do zwykłego zapytania SQL a następnie zostaje zwrócona tablica z obiektami rekordów wcześniej zadeklarowanych. Wreszcie możemy zapomnieć o babraniu się z wyciąganiem danych zwróconych przez zapytanie. Wystarczy takie zapytanie jak powyżej i mamy wszystko z głowy. Dostajemy tablicę z ładnymi obiektami. DQL dodatkowo oferuje inne możliwości jak np. INDEXBY.

Gdyby jednak okazało się że nie da rady wykonać zapytanie przez DQL. Mamy wtedy 2 możliwości. Użyć Doctrine_RawSql, gdzie piszemy właściwie normalne zapytanie, a na końcu podpinamy obiekty. Albo możemy po prostu z Doctrine wziąć obiekt PDO i użyć go jak za starych (dobrych) czasów winksmiley.jpg Ja jak narazie tylko raz użyłem RawSql, a PDO? Szczerze to już nie pamiętam jak się z tego korzysta winksmiley.jpg

Tyle jeżeli chodzi o wyciąganie. Tworzenie i update rekordów jest również banalny i oczywiście odbywa się przez obiekty rekordu. Dodatkowo Doctrine posiada kilka pluginów które są naprawdę bardzo użyteczne i przydatne. Po więcej informacji odsyłam do dokumentacji.

Zaraz padną głosy że doctrine to krowa. Owszem, trochę to wszystko waży. Jeżeli chodzi jednak o wydajność nie poczułem żadnych niedogodności, więc to wszystko mi odpowiada (kolega mówił że jeden projekt składający się z 35 tabel napisał na doctrine smile.gif. Projekt się szybko rozwija. Autorzy zapowiadają że niedługo pojawi się nowa wersja z nowym parserem DQL, który ma być szybszy, chyba ma posiadać nawet jakieś nowe możliwości.

Generalnie, polecam Doctrine. Warto zainteresować się tym ORM.

Napisany przez: Sedziwoj 15.03.2008, 08:49:26

Cytat
$users[0] -> Phonenumber -> number;


Czyli mam rozumieć, że on korzysta z stdClass? Czy działa podpowiadanie składni? Bo jak nie to zupełnie niewygodne jest takie coś w porównaniu do Propela.
Do tego trzeba się nauczyć dodatkowej składni DQL. Pisać mimo wszystko w PHP, w Prpelu jest to za darmo generowane, nie wiem czemu ale czuję że ludzie uciekają od złożoności działania, tracąc prostotę użytkowania.

Jakoś nadal nie widzę aby Doctrine był w czymś lepszy od Propela (wydajność nie biorę jako składową oceny)
Może ktoś mi napisze dlaczego miałby być lepszy od Propela, jest na pewno lepszy od ręcznego klepania, ale chyba szuka się najlepszych rozwiązań.

Napisany przez: Strzałek 15.03.2008, 11:33:06

Cytat
Czyli mam rozumieć, że on korzysta z stdClass?


Nie rozumiem? Czemu niby? $users jest obiektem Doctrine_Colletion. Doctrine_Collection posiada kolekcje obiektów User (wcześniej zdefiniowanych przez nas rekordów). User natomiast ma zdefiniowane przykładowo relację do Phonenumbers. Właściwość Phonenumber obiektu user przechowuje obiekt Phonenumber. Wszystko bardzo logiczne.

Cytat
Do tego trzeba się nauczyć dodatkowej składni DQL.


No cóż. Nie przesadzajmy. Czy naprawdę musisz się uczyć całkowicie nowej składni? Po tyg. użytkowania wszystko staje się proste. Tworzysz łańcuszej jak zwykły SQL. Ba, lepiej. Masz mniej pisania, bo nie musisz przy joinach pisac ON ... bo relacje masz wczesniej zadeklarowane i same są dołączane przez parser DQL.


NIe napisałem że Doctrine jest lepsze od Propela. Sam przy wyborze ORM, przeczytałem trochę dokumentacji Propela i Doctrine i wybrałem opcje drugą. Nie mogę sie do końca wypowiadać o Propelu bo go nie używałem i nie znam. Wiem jednak (od samych użytkowników propela) że np. jakieś większe JOINY to już problem. Dodatkowo dla mnie pomyłką jest coś takiego:


  1. person.gender = 'M' AND (person.location IN ('Birmingham', 'Coventry') OR person.location = 'Manchester') AND (person.enabled <> 0) AND person.age > 16


W propelu żeby uzyskać coś takiego trzeba napisać:

  1. <?php
  2. $c = new Criteria();
  3. $crit0 = $c->getNewCriterion(PersonPeer::GENDER, 'M');
  4. $crit1 = $c->getNewCriterion(PersonPeer::LOCATION, http://www.php.net/array('Birmingham', 'Coventry'), Criteria::IN);
  5. $crit2 = $c->getNewCriterion(PersonPeer::LOCATION, 'Manchester');
  6.  
  7. // Perform OR at level 1 ($crit1 $crit2 )
  8. $crit1->addOr($crit2);
  9. $crit3 = $c->getNewCriterion(PersonPeer::ENABLED, 0, Criteria::NOT_EQUAL);
  10. $crit4 = $c->getNewCriterion(PersonPeer::AGE, 16, Criteria::GREATER_THAN);
  11.  
  12. // Perform AND at level 0 ($crit0 $crit1 $crit3 $crit4 )
  13. $crit0->addAnd($crit1);
  14. $crit0->addAnd($crit3);
  15. $crit0->addAnd($crit4);
  16.  
  17. // Remember to change the peer class here for the correct one in your model
  18. $c->add($crit0);
  19. $result = TablePeer::doSelect($c);
  20. ?>


Kod wygenerowany przez: http://propel.jondh.me.uk/ Halo? Mieliśmy sobie ułatwiać pracę i skracać czas.

Ale tak jak mówię. Nie używałem Propela więc cieżko jest mi coś więcej powiedzieć. Używam natomiast Doctrine i uważam to za świetne narzędzie. Polecam zerknąć do dokumentacji, poczytać.

Napisany przez: athabus 15.03.2008, 12:31:26

Doctrine nie używałem więc trudno mi porównać prostotę pisania. Ale skłonię się ku opinii Sedziwoja. Dla mnie w Propelu największym plusem są właśnie klasy "szkieletowe" z możliwością ich rozbudowania. Najwięcej czasu w projekcie zawsze traciłem na tworzeniu prostych zapytań. Jest to (obok formularzy) jedna z najbardziej monotonnych części projektu.
Propel generuje w zasadzie wszystko co się da zrobić z automatu, a programiście pozostaje tylko dopisanie ewentualnych nakładek i dodatków.

Genialną zaletą Propela jest właśnie podpowiadanie składni (propel pozwala opcjonalnie nawet na dodanie komentarz phpDoc więc w PDT podpowiadanie działa nawet do zagnieżdżonych obiektów). Dzięki podpowiadaniu składni, nawet po powrocie do projektu po kilku miesiącach łatwo jest ogarnąć operacje na bazie.

Wady propela jak dla mnie są dwie:
- dosyć skomplikowane tworzenie niektórych zapytań (np. gdy przychodzi do łączenia Criterion'ów to do tej pory muszę czasami zaglądać do manuala)
- wydajność (chodzi o samo php, bo zapytania są raczej standardowe) - choć tak na prawdę wydajność to taki problem "urojony", bo w przeciętnej wielkości stronie, i tak nie ma to aż tak dużego znacznie. Gdybym pisał aplikację pod bardzo duże obciążenie to może bym się tym przejmował.

Napisany przez: Cysiaczek 15.03.2008, 13:16:35

Nie używałem Doctrine, ale Propela owszem i rzeczywiście - bardziej złożone zapytania wyglądają jeszcze bardziej zawile w propelu niż w gołym SQL. Trzeba jednak zauważyć dwie rzeczy
1. Bardzo złożone zapytania można również napisać ręcznie, a potem na podstawie wyniku wypełniać obiekty. Propel ma do tego wsparcie.
2. Złożone zapytania stanowią w większości systemów margines. Są to wszelkiego rodzaju wyszukiwania wg. złożonych kryteriów, którym nie podoła żadna forma obiektowa (w sensie zachowania prostoty).

Mitem jest, że Propel ma słabą wydajność. Relacje są ustawiane sztywno w wygenerowanych klasach, a wysyłane zapytania niczym sie nie różnią od normalnych zapytań. Późniejsze wypełnienie obiektów trwa tyle samo, ile by zajęło zrobienie tego ręcznie. Można jednie polemizować, czy operacje na 1000 rekordów należy wykonywać z pominięciem kreacji obiektów, czy nie.

Wadą, którą widzę w Doctrine jest to, że trzeba pisać kod php dla każdej tabeli. Nie ma żadnego generatora? Naprawdę bardzo fajnie koduje się strukturę z XML, czy nawet w YAML (o to nawet polubiłem). Już nie wspomnę i łatwiejszej edycji takiej struktury:)

Pozdrawiam.

Napisany przez: athabus 15.03.2008, 13:28:09

No niestety sama wydajnośc propel to nie do końca mit. Popatrz chociażby na ilość kodu klas generowanych przez propela. Samo załadowanie takiej ilości kodu to już niezłe obciążenie. Niektórych przypadkach propel też nie grzeszy wydajnością np. http://blog.dywicki.pl/2006/09/21/propel-12-przyspiesz-go-nawet-do-2-razy/.

Ale tak jak pisałem wcześniej - to nie jest problem przy standardowej, dobrze napisanej stronie. Problemem może się natomiast okazać gdy na jednym hostingu próbujesz upchnąć 10-15 stron klientów itp., ale dla mnie to nie jest problem.

Napisany przez: destroyerr 15.03.2008, 13:37:16

Więc Doctrine ma możliwość definiowania schematu w pliku YAML (w przeciwieństwie do propela). Dodatkowo ma jeszcze wbudowany mechanizm migracji.
Tak jak pisał athabus, najwięcej czasu zajmuje napisanie tych prostych zapytań. Kiedyś sobie tesowałem, i wyszło mi, że szybciej (i krócej) jestem w stanie napisać takie zapytanie w Propelu niż w Doctrine.
Dodatkowo Propel (oczywiście w edytorze z podpowiadaniem składni) nie pozwala nam popełnić literówki, Doctrine jednak tak. Ale racją jest, że trudne zapytania w Propelu to duży problem.
Jeśli chodzi o wydajność to Propel 1.2 jest generalnie wolniejszy od Doctrine, ale już Propel 1.3 jest szybszy (oczywiście nikt nie musi zgadzać się z http://notjosh.com/blog/archives/34-Propel-1.3-beta-in-Symfony!.html benchmarkiem.

Napisany przez: splatch 15.03.2008, 14:25:39

Jeśli idzie o szybkość Propela w wersjach <= 1.2 to rzeczywiście nie było z nią najlepiej. Wszystko było spowodowane nienajlepszą konstrukcją "bindowania" z wyniku zapytania do obiektów. Zbędne iteracje i porównania robiły swoje, w wersji 1.3 całość wygląda znacznie lepiej.

Zapytania - Panowie zapominacie o najważniejszej zalecie Criterii. Można w bardzo prosty sposób stworzyć mechanizm tworzący na bazie wysłanego formularza kryteria do wyszukiwania i sortowania. Kiedyś taki mechanizm stworzyłem, wystarczyło stworzyć formularz a po stronie serwera powiedzieć które tabele będą używane. Mechanizm na podstawie nazw pól tworzył wyniki (porównania, mniejszy-większy, like, plus ograniczenia na relacje). Następnie warunki wędrowała do sesji (tablice o określonej strukturze), gdy ktoś wracał na stronę z wynikami trafiał dokładnie w to samo miejsce gdzie był np. przed edycją, bo stworzenie Criteria z tablicy było tylko formalnością. Z takim mechanizmem tworzenie widoków z listami zajmowało mi około 15 minut (formularze do wyszukiwania plus wyświetlanie wyników). Rezultatem tego było to, że później widoki (listy) mogła robić osoba, która miała pojęcie o html i smarty. smile.gif

Wykorzystajcie Criterię nie tylko do tworzenia zapytań, na prawdę warto zainwestować w jakiś automatyczny mechanizm jeśli jeszcze go nie macie. Parę komponentów do warstwy prezentacji, parę klas, kilka pętli a zysk czasowy na prawdę znaczny.

Napisany przez: Sedziwoj 15.03.2008, 17:42:22

Do tego skomplikowane zapytania można oprzeć na widokach, a zdefiniować takie tabele w XML/YAML jako tylko do odczytu. Wtedy nie ma tego kodu po stronie PHP. @splatch dokładnie, wystarczy mały generatorek Criteria i mamy właściwie od ręki listy z filtrowaniem i stronicowaniem. Wystarczy powiedzieć jakie pole odpowiada któremu w bazie i jakie warunek porównania.

Ale tak jeszcze podkreślę, pamiętajcie że baza ma też coś więcej niż tabelki, więc wykorzystujcie te mechanizmy aby ułatwić sobie życie.

Napisany przez: Strzałek 15.03.2008, 18:28:52

Cytat
Wadą, którą widzę w Doctrine jest to, że trzeba pisać kod php dla każdej tabeli. Nie ma żadnego generatora? Naprawdę bardzo fajnie koduje się strukturę z XML, czy nawet w YAML (o to nawet polubiłem). Już nie wspomnę i łatwiejszej edycji takiej struktury:)


Oczywiście że jest. Można zdefiniować to w http://www.phpdoctrine.org/documentation/manual/0_10?one-page#schema-files, albo http://www.phpdoctrine.org/documentation/manual/0_10?one-page#getting-started:working-with-existing-databases.

Czy mówiąc o prostych zapytaniach macie na myśli to http://www.phpdoctrine.org/documentation/manual/0_10?one-page#dql-doctrine-query-language:magic-finders ?

Polecam poczytać dokumentacje. Doctrine oferuje nam naprawdę bardzoooo dużo.

Napisany przez: Sedziwoj 15.03.2008, 19:49:46

@Strzałek tylko powiedz w czym to jest lepsze od Propela? Bo jak już mówiłem to porównanie jest ważne, aby wykazać co jest lepsze. Bo ciągle jako porównanie bierzesz system bez ORM (źle się pisze bez klawiatury)

Napisany przez: Cysiaczek 15.03.2008, 20:26:32

Uh, jak mówiłem - nie używałem Doctrine. Jak jest generator, to ok smile.gif. W takim wypadku kwestia wyboru pomiędzy Propelem, a Doctrine, to jak wybór pomiędzy różnymi systemami szablonów ;] Jak będę miał czasa to zerknę na Doctrine i zobaczę co tak wychwalacie ;p

Pozdrawiam.

Napisany przez: Sedziwoj 15.03.2008, 21:21:59

Cytat(Cysiaczek @ 15.03.2008, 20:26:32 ) *
Uh, jak mówiłem - nie używałem Doctrine. Jak jest generator, to ok smile.gif. W takim wypadku kwestia wyboru pomiędzy Propelem, a Doctrine, to jak wybór pomiędzy różnymi systemami szablonów ;] Jak będę miał czasa to zerknę na Doctrine i zobaczę co tak wychwalacie ;p


Cyba nie czytasz dokładnie, w Doctrine nie ma wsparcia do środowisk programistycznych, więc musisz pamiętać jakie masz pola w "tabelach"

(jeszcze raz rozbieram klawiaturę i czyszczę jeśli nie pomoze to kupuje nową, bo klawisze mi nie działają wszystkie )

EDIT:
No to będzie zakup nowej klawiatury :|

Napisany przez: Cysiaczek 15.03.2008, 22:22:26

Oj tam smile.gif
Mi podpowiadanie składni w eclipse działa jak mu się podoba i to w momentach, gdy nie jest mi potrzebne, więc nie przekonuje mnie ten argument. Bardziej patrzę na funkcjonalność samej biblioteki.

Pozdrawiam.

p.s
Ja pisze z nowej klawiatury - dwa dni temu kupiłem snitch.gif

Napisany przez: Sedziwoj 16.03.2008, 00:33:42

Cytat(Cysiaczek @ 15.03.2008, 22:22:26 ) *
Oj tam smile.gif
Mi podpowiadanie składni w eclipse działa jak mu się podoba i to w momentach, gdy nie jest mi potrzebne, więc nie przekonuje mnie ten argument. Bardziej patrzę na funkcjonalność samej biblioteki.


Tylko że to jest duże funkcjonalne udogodnienie, a z podpowiadaniem to było na którymś blogu, do tego Ctrl+Spacja zawsze zadziała. (tylko aby obiekty propela były w projekcie)

Cytat
p.s
Ja pisze z nowej klawiatury - dwa dni temu kupiłem snitch.gif


A pochwal się jaką? Bo ja nie mogę się zdecydować...

--- cysiaczek---
Wybacz, że tu, ale nie chce spamic
http://merlin.pl/Klawiatura-TRACER-Ibiza-TRK-9MTR-USB/browse/product/208,556750.html

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)