Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php][database] Abstrakcje
Forum PHP.pl > Forum > PHP
Vengeance
Rozmyslam nad pewną sprawą. Pewnie samym rozwiązaniem ameryki nie odkryłem, pewnie są już jakieś implementacje tego, jednak chodzi mi o to co o tym szanowne jury myśli ;]

Ostatnio popularny jest temat abstrakcji na bazy danych ;]
Jednak rozwiązanie w stylu
  1. <?php
  2. $db->connect();
  3. $db->query('SELECT * FROM talbe WHERE cos=1');
  4. ?>

jest dla mnie niesatysfakcjonujące. Dlaczego?
Jakbym chciał "przestawić" aplikację aby dane czerpała z plików txt, czy np. z SOAP ( blink.gif ) musialbum obsłużyć jakimiś pregami składnie SQL.

Mój pomysł jest taki
  1. <?php
  2. $db->connect();
  3. $db->query(new InsertQuery(<gdzie>, <co>));
  4. $db->query(new DeleteQuery(<gdzie>, <where>, <limit>));
  5. ?>

Itd. ;] Klasy xxxQuery przygotowywały by co trzeba, jak trzeba itp.
Tworzyłby by odpowiednie zapytania do MySQL czy PgSQL a potem byłby
to wykonywane. Jednak takim sposobem nie obsłużę takiego "złożonego"
zapytania jak np.
SELECT * FROM table LEFT JOIN cos ON cosik=2 LIMIT 4

Co w tym momencie ? Ano użytkownik (czyli ja) tworzył by sobie
własną klase xxxQuery której zadaniem byłoby obslużenie tego jednego konkretnego zapytania. Potem w skrypcie tylko
  1. <?php
  2. $db->query(new MyQuery(<mozeJakisParamter>));
  3. ?>

i wszystko by grało.

Teraz gdybym np. z MySQL chciał przejść do plików TXT wszystko polegalo by na przepisaniu podstawowych klas InsertQuery, SelectQuery, UpdateQuery itd.
by obsługiwały owe pliki teksowe oraz tych "własnych" klas xxxQuery.

Czy coś takiego ma jaki kolwiek sens ? Jakie są ewentualne wady a jakie zalety?
Proszę o pomoc smile.gif
squid
ja robie cos takiego:
  1. <?php
  2.  
  3. $db = new dbManage();//tu mi sie laczy z serwerem i wybiera baze
  4.  
  5. $db->insert ('nazwa_tabeli', 'kolumna lub lista kolum oddzielona przecinkami albo tablica kolumn', 'wiersze jakie chce dodac moze byc jeden albo wiecej');
  6.  
  7.  
  8. ?>


podobnie mam dla innych instrukcji jak delete, update i select (to jest najtrudniejsze), napisalem tu o insercie bo od niego zaczolem.

Caly czas to rozwijam ale chodzi mi o to zeby oberaowac zmiennymi przekazywac z obiektu do obiekty z metody do metody a zapytania robi tylka warstwa abstrakcji
Vengeance
czyli to samo u mnie ;] tylko ze ja bym przekazywal do query() obiekt.
czemu ?

wykonaj na tym swoim select jakies baardzo rozbudowane zapytanie ;]
moze sie nie udac snitch.gif musialbys ingerowac w kod klasy dbManage.

U mnie zas dopisalbys wlasna klase do obslugi tego jednego konkretnego zapytania.
squid
moj glowny select obsluguje cala skladnie selecta z sql92 i zadnych problemow nie ma nic nie musze ingerowac, ma tylko spora liste parametrow ale ze sa domyslne to nie wszystkie trzeba wypelniac, zrobilem sobie tez prostrza wersje metody pt. simpleSelect ktora obsluguje najpopulaniejsze slowa kluczowe, poza tym metody sa inteligentne i same rozpoznaja zapodane parametry i dopisuja sobie reszte, mi dodatkowe obiekty nie sa potrzebne a juz kilka projektow na tym zrealizowalem alej jesli twierdzisz ze nie mozesz bez nich zyc...
Vengeance
a no to teraz rozumiem ;] skoro tak to nie sa ci potrzebne ;]
jednak mnie chyba nie chce sie robic obslugi calego sql snitch.gif

pozatym dzieki tym moim obiektom moge jeszcze wstepnie obrabiac pobrane dane.
pozdrawiam smile.gif
squid
no calego sql nie bylo potrzeby implementowac ale zgodnie ze specyfikacja mam:
select, insert, update, delete
innych nie potrzebuje
dorobilem sobie dodatkowe metody np. do sprawdzania czy wartosc jest w tabeli jesli tak zwraca te wartosc jak nie to false itp.

osobiscie nie widze potrzeby obrabiania danych w warstwie abstrakcji u mnie wszelikmi obrobkami zajmuje sie warstwa logiki biznesowej ale jestem ciekaw jak to tealizujesz, opowiedz o swoim rozwiazaniu wiecej
Vengeance
nie no chodzilo mi oto ze user moze sobie jakby "rozszerzać jezyk sql" ;]
w takim adodb o ile sie nie myle tez sa jakies pluginy (nigdy nie uzywalem adodb). U mnie user moglby sobie stworzyc wlasna klase dla zapytania, ona pobrala by jakies dane, obrobila wg przekazanych paramterow i zwrocila to co potrzebne. Taka klasa mogla by na raz robic od razu jakis select potem update, delete i cos tam jeszcze ;]
Cos jak procedury w sql.
hawk
Idea uniezależnienia się od źródła danych jest szczytana, ale dlaczego wpychać to do klasy obsługującej bazę danych? Jeżeli robisz $db->query(...), to widać na pierwszy rzut oka, że za tym stoi baza danych, a nie SOAP. To nie jest warstwa, w której można wprowadzać abstrakcję. Za późno na to. Co innego, jeżeli masz UserManager->getInstance()->getUserByName('foobar'). Tutaj jesteś w stanie napisać implementacje klasy UserManager operujące na DB, SOAP czy czymkolwiek. Ale nie ma poziomie zapytania SQL, bo trzeba wtedy - co sam widzisz - interpretować składnię SQL lub zastępować czymś innym.

Spójrz na to tak: musisz wyciągnąć artykuł. Masz napisany kod, który wie, jakie zapytanie SQL stworzyć i przekazuje to do jakiegoś managera db. Teraz chcesz napisać kod, który "odkręci" to zapytanie SQL i przełoży na coś abstrakcyjnego... a potem kod który przetłumaczy to abstrakcyjne zapytanie np. na SQL.
Vengeance
Czyli jak to "wykończyć". W takim getUserByName() powinny być czyste zapytania SQL dostosowane pod konkretną baze danych? i w razie
chęci przestawienia się na pliki TXT miałbym robić "nowe implementacje" tej metody? Tak by wykorzystywała ów pliki? (sądze ze nie o to chodziło)

Jeśli miałbyś czas to byłym wdzięczny za jakiś pseudo kod tego rozwiązania. Sam zarys. Łatwiej wtedy zrozumieć kod niż słowa winksmiley.jpg
Ale to jak ci sie zachce.

W każdym bądź razie dzięki za wypowiedzi.
squid
Cytat(Vengeance @ 2004-12-23 18:27:07)
Łatwiej wtedy zrozumieć kod niż słowa winksmiley.jpg

no to ja Cie podziwiam, jestes komputerem czy jak?

hawk dobrze prawi ale raczej nie bedzie tu prezentowal swojego kodu aczkolwiek dolaczam sie do prosby dalszego wytlumaczenia
Vengeance
hehe moze i jestem ;]
ale serio latwiej mi zawsze zrozumiec cos na przykladzie, nawet w jakims pseudo kodzie winksmiley.jpg (procz asm snitch.gif)

Bo slowo pisane mozna roznie interpretowac winksmiley.jpg to co napisal hawk to tez tak po troszku takie DAO ale pewnie i tu sie myle ;]
aleksander
Ja tu tak czytam, i czytałem coś podobnego w książce i mam jedno rozwiązanie w głowie:
Kod
| abstrakcja bazdy danych (jakis adodb, creole czy coś własnego)
|
| warstwa klas i metod typu User->getUserById, Auto->getAutoByRejestracja czyli takich, które ukrywają skąd są te dane, zwracają Ci same dane, dodatkowo mogą na nich operować)
|
| warstwa logiki czyli cały kod, który wszelkie dane wyciąga przez klasy/metody opisane w warstwie wyżej.

co Wy na to?
Vengeance
to jest standard. chodzi tylko o to ze gdy uzywasz tego adodb i chcesz teraz
przjesc na pliki txt to masz do zmiany wszystkie te twoje "warstwa klas i metod". Mi chodzi o napisanie wlasnej abstrakcji na baze danych aby te zmiany zmniejszych do minimum. Bo takie adodb przyjmuje tylko sql i tylko na bazach operuje o ile mi wiadomo.
DeyV
Cytat
chęci przestawienia się na pliki TXT miałbym robić "nowe implementacje" tej metody? Tak by wykorzystywała ów pliki? (sądze ze nie o to chodziło)


A ja myślę, że chodziło właśnie mniej więcej o to.
np.
  1. <?php
  2.  
  3. class User {
  4. function __construct () {
  5. ... 
  6. }
  7.  
  8. abstract function getById( $iId );
  9.  
  10. abstract function getByLogin( $sLogin );
  11. }
  12.  
  13. class UserDb extends User {
  14.  function getById( $iId ){
  15.  // SELECT FROM .. 
  16.  }
  17.  function getByLogin( sLogin ){
  18.  // SELECT FROM .. 
  19.  }
  20. }
  21.  
  22. class UserTxt extends User {
  23.  function getById( $iId ){
  24. fopen( ... );
  25.  }
  26.  function getByLogin( sLogin ){
  27. fopen( ... );
  28.  }
  29. }
  30.  
  31.  
  32. if( $Config->bDataFromTxt ) {
  33. $User = new UserTxt ( ... );
  34. }
  35. else {
  36. $User = new UserDb ( ... );
  37. }
  38.  
  39. ?>


życie można sobie jeszcze bardziej uproscić, tworząc klasę automatycznie zwracającą odpowiednią instancję, w zależności od tego, czy pracujemy na Db, czy na txt.

ps. soorki za php5, choć to nie to forum - wybaczcie, siła przyzwyczajenia.
Vengeance
a tak?
  1. <?php
  2. # plik db.class.php
  3. class User {
  4. function __construct () {
  5. ...
  6. }
  7.  
  8. public function getById( $iId )
  9. {
  10.  // table, where, limit
  11.  DB::query(new SelectQuery('users', 'id='.$iId, 1)
  12. }
  13.  
  14. public function getByLogin( $sLogin )
  15. {
  16.  DB::query(new SelectQuery('users', 'login='.$sLogin, 1)
  17. }
  18. }
  19.  
  20. class DB
  21. {
  22.  static function query($queryObject) {}
  23. }
  24.  
  25. # plik txt/querys.php
  26. class SelectQuery
  27. {
  28.  // fopen
  29. }
  30.  
  31. # plik sql/querys.php
  32. class SelectQuery
  33. {
  34.  // select ...
  35. }
  36. ?>
bela
@Vengeance mi sie w tym rozwiazaniu te statici nie podobają, czy nie lepiej stworzyc klase do budowanie zapytan i potem
  1. <?php
  2. $result = $db->query($dbQueryBuilder->select('tabela', 'limit', 'jakies pierdoly' ));
  3. ?>

?
aleksander
ja proponuję tak: (php5)
  1. <?php
  2.  
  3. interface UserI
  4. {
  5. public function __construct();
  6. public function getUserById( $userid );
  7. public function getUserByNick( $nick );
  8. public function updateUser();
  9. }
  10.  
  11. class UserMysql implements UserI
  12. {
  13. // ...
  14. }
  15.  
  16. class UserPGSql implements UserI
  17. {
  18. // ...
  19. }
  20.  
  21. class UserTxt implements UserI
  22. {
  23. // ...
  24. }
  25.  
  26. // i teraz
  27.  
  28. function getUserInfo( $type )
  29. {
  30. return new User$type();
  31. }
  32. ?>
bela
a nie return new User{$type}(); ?
Vengeance
po 1. wlasnie chcialem zapytac. jaka jest roznica (ale juz w php5) miedzy singletonem a 'static' ;] wydaje mi sie (pewnie zle) ze jesli cala klasa bedzie miala argumenty jak i metody okreslone jako static
to wykorzystywanie singletona nie ma sensu.

po 2. bela_666 w sumie to na jedno wychodzi ;] ja tam wole swoje nie wiem czemu. kazdy ma jakies fobie winksmiley.jpg tym bardziej ze jak chcialbys to swoje przerobic na obsluge plikow txt, lub SOAP-a ?


---edit---
hmm no nie wiem olo. w kazdym sposobie jest ciut poprawnosci. jednak zauwaz ze zwalasz tu na uzytkownika implementacje obslugi sql, txt i innych. Mi chodzi o to aby mozna bylo szybko sobie wybrac czy chce pliki czy sql czy co innego. Cos jak adodb. Ty piszesz zapytania ustawiasz w confie z jakiej bazy korzystasz i gra (przynajmniej powinno). A nie piszesz po 6 rodzajow wywolania funkcji po jednym na kazda baze danych smile.gif
bela
@Vengeance pisanie klas w ktorych sa same metody statyczne jest zle i tak B. Eckel mowi "nalezy wtedy przemyslec jeszcze raz klase" biggrin.gif

Singleton to jest wzorzec projektowy winksmiley.jpg static wiadomo ( pytales sie chyba )

a przeciez jak jest ten queryBuilder to mozesz ustawic jak chcesz generowac

tutaj masz queryBuiler z OPD http://bora.netburg.pl/oop/database/build/...ile=sql_builder
aleksander
singleton jest wtedy gdy masz metode, która za każdym razem zwraca tą samą instancję klasy. Masz tu prostego singletona:
  1. <?php
  2. class Singleton
  3. {
  4. private static $instance = null;
  5. public static function getInstance( $conf )
  6. {
  7. if ( Singleton::$instance == null)
  8. {
  9. Singleton::$instance = new singletonr();
  10. }
  11. return Singleton::$instance;
  12. }
  13. // ...
  14. }
  15. // i zamist robić:
  16. $obj = new Singletonn;
  17. //robisz
  18. $obj = Singleton::GetInstance();
  19. ?>

i $obj bedzie miał obiekt a gdybys wszystko miał jako statici to byś musiał sie odwoływać jak do statików.


@bela_666: pisałem na szybko - chodziło mi żeby zrozumieć działanie
Vengeance
"Singleton to jest wzorzec projektowy"
i chodzi oto aby byla jedna instancja klasy. kazda instancja powinna operowac na tych samych danych jakby.

Jak dla mnie static takze spelnia tę rolę więc? (oczywiscie nie tylko)

"a przeciez jak jest ten queryBuilder to mozesz ustawic jak chcesz generowac" yy ale "Builder" mowi samo za ciebie ze zwraca ono ZAPYTANIE Sql. Teraz do query() trafia ów zapytanie i idze do np. MySQL. Gdzie tu "podstawisz" pliki ? Od razu queryBuilder bedzie na nich operowac? to wtedy query() zgłupieje.

---edit---
Olo: Czym mniej wiecej singleton jest to wiem. Chodzi mi tylko o to ze moge zrobic takimi sposobami to:
1.
  1. <?php
  2.  
  3. $db = DB::getInstance();
  4. $res = $db->query(...);
  5.  
  6. ?>

2. (w php5)
  1. <?php
  2.  
  3. $res = DB::getInstance()->query(...);
  4.  
  5. ?>

to czemu nie zrobic:
1.
  1. <?php
  2.  
  3. $res = DB::query(...);
  4.  
  5. ?>


Chodzi mi o te subtelna roznice winksmiley.jpg

ps. zastanawiam sie czasem jak wesolo jest ludzia znajacym dobrze te wszystkie zasady OOP i czytającym moje niektore posty smile.gif
hawk
1) ad ostatni post Vengeance:
Tak dla formalności, DB::query to też jest wzorzec projektowy: chyba Monospace lub Monotype. Różnica jest istotnie subtelna. Raz: singleton można teoretycznie przerobić na nie-singletona, i można przekazywać sobie obiekt, robić jakieś dziedziczenie, itd. Dwa: użycie singletona sugeruje że obiekt ma wewnątrz jakiś stan, użycie monospace sugeruje że żadnego stanu nie ma (np Math::sin(2), Math:tongue.gifI, itd) - kwestia przyjętej konwencji.

2) Mi chodziło własnie o klasę User i dziedziczące z niej klasy z konkretną implementacją (SQL, txt, itd). Tak jak np. pokazał DeyV. A że to wymaga roboty? Nie powiedziałem że nie wymaga winksmiley.jpg. Ale tutaj rzeczywiście zaczynamy mówić o DAO, i dużo wysiłku idzie w stronę generowania tego automatycznie. Algorytmów skomplikowanych to tutaj nie ma.

Zauważ, że jeżeli jesteś w stanie zbudować klasę Query, która ci przetłumaczy zapytania na SQL lub na pliki, to jesteś w stanie wygenerować z jakiegoś abstrakcyjnego opisu implementacje klas TxtUser, SqlUser itd. W teorii jest to możliwe, w praktyce jest gorzej...

3) Była kiedyś na sitepoincie dyskusja na temat opakowywania bazy danych warstwą obiektową. Klasa User, klasa Query, różne DAO w rodzaju Propel, itd. I ktoś mądrze napisał, że RDBMS jest bardzo rozwiniętym i potężnym narzędziem, idealnie dopasowanym do zadania jakie wykonuje - skomplikowane zapytania. OOP nie jest do tego dostosowane. Dlatego wszystkie próby budowania zapytania SQL z obiektów są jakieś niewygodne w użyciu. Vengeance, twoja klasa SelectQuery będzie OK dopóki robisz proste zapytania. W momencie kiedy wrzucisz joina po kilku tablicach, agregację i sortowanie, to albo nie będziesz w stanie tego zrobić, albo twoja klasa stanie się niezrozumiałym potworkiem.

I tak naprawdę nie da się zamienić bazy danych na pliki tekstowe. Chyba że rezygnujemy z większości funkcjonalności, czyli zostajemy przy prostych selectach.
Vengeance
tego ze sie nie da wiem. choc przy prostrzych rzeczach sie da winksmiley.jpg

Ja po prostu lubie stawiac sobie jakies glupie cele i starac sie je realizowac smile.gif czemu? Czlowiek w trakcie tego wiele sie uczy. Po co robic ciagle cos co sie umie ;p

hawk: wiem ze te SelectQuery nie obsluzy kilku joinow sortowania i jakiegos grupowania przy tym. I tu wlasnie chcialem dac mozliwosc stowrzenia przez usera wlasnej klasy dziedziczacej z Query.
Np. MyQuery ktore ow skomplikowane zapytanie by wykonywala.
W koncu ja jeszcze tak wiele zapytan tak rozbudowanych nie wykonuje wiec widzialem w tym jakies rozwiazanie smile.gif

Dzieki za wypowiedzi i bynajmniej nie uwazam tematu za zakonczony ;]
jak ktos chce cos dodac to bardzo prosze smile.gif

Wesolych Swiat
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.