Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Db layer
Forum PHP.pl > Forum > PHP > Object-oriented programming
pies
Nie wiem, czy może się to do czegoś przydać, napisałem warstwę DB dla PHP5, używa jej się tak:

  1. <?php
  2.  
  3. // CREATE TABLE users (id int, login varchar(32), password varchar(32), sex char(1), age int(1));
  4.  
  5. $db = new StraightDB('nazwa_bazy');
  6.  
  7. // wszystkie rekordy
  8. print_r $db->users->value;
  9.  
  10. // rekord o id 5
  11. print_r $db->users->id(5)->value;
  12.  
  13. // pojedyncze pole rekordu o id 5
  14. print $db->users->id(5)->login->value;
  15.  
  16. // wszystkie kobiety pow. 30 lat
  17. print_r $db->users->sex('f')->age(30, '>')->value;
  18.  
  19. // zapis pola do bazy
  20. if ($db->users->id(5)->sex = 'm') print 'OK';
  21.  
  22. // zapis array do bazy
  23. if ($db->users->id(5) = array('login'=>'Foo', 'password'=>'Bar')) print 'OK';
  24.  
  25. ?>


To tylko proof of concept (bo nie widziałem jeszcze takiego sposobu na dostęp do bazy danych), ale działa zgodnie z oczekiwaniami. Zapytania do bazy są robione leniwie, czyli połączenie do bazy (przy pierwszym zapytaniu) i samo zapytanie wykonywane jest na samym końcu (przy odczytaniu 'value'). Każdy z powyższych przykładów wykorzystuje jedno zapytanie SQL.

Kod jest nieokomentowany ale czysty, licencja Public Domain, obsługuje MySQL i SQLite, więc można się pobawić. Kod natywny dla baz danych (np. myslq_connect()) Chce ktoś?

UPDATE: Umieściłem archiwum do ściągnięcia pod adresem http://sputnik.pl/dev/releases/metabox-0.1-dev.zip.

Archiwum zawiera rozgrzebaną wersję developerską frameworku Metabox (którego częścią ma być StraightDB), uruchamianą z pliku test.php w głównym katalogu. W miarę łatwo powinno być wyciągnąć z frameworku samą bibliotekę, co postaram się zrobić w wolnej chwili. POLECANE TYLKO DLA NAPRAWD ZAINTERESOWANYCH, DOŚWIADCZONYCH PROGRAMISTÓW php.
NuLL
Chętnie bym się przyjrzał temu narzędziu smile.gif
dr_bonzo
Moze bys zaprezentowal kod, dal do niego linka.

PS> Widziales Creole?

---------
LOL, pomylil mi sie Propel z Creole smile.gif
M4chu
Ja tez chce winksmiley.jpg
A jak sie ma sprawa z bardziej skomplikowanymi zapytaniami: chociazby (a AND b ) OR (c AND d), joiny.
PS> Widziales Propela (dr_bonzo ;>)
pies
Cytat(M4chu @ 2005-09-12 12:31:07)
Ja tez chce winksmiley.jpg
A jak sie ma sprawa z bardziej skomplikowanymi zapytaniami: chociazby (a AND b ) OR (c AND d), joiny.

Nie zaimplementowałem jeszcze joinów, trudno będzie jednak opracować wygodny interface powyżej podstawowego poziomu joina. Zamierzam zacząć tak:
  1. <?php
  2. $db->users->sex('f')->with('posts')->value
  3. ?>

...i linkować automatycznie tablice po domyślnych kluczach (tj. np. posts.users_id => users.id). To nie będzie trudne. Problem może powstać przy wielokrotnych zagnieżdżeniach.

Swoją drogą powyższy ciąg można rozpisać:
  1. <?php
  2. $users = $db->users;
  3. print_r ($users->value); // wszyscy uzytkownicy
  4. $female_users = $users->sex('f');
  5. print_r ($female_users->value); // wszystkie kobiety
  6. $females_with_posts = $female_users->with('posts');
  7. print_r ($females_with_posts->value); // wszystkie kobiety LEFT JOIN posts
  8.  
  9. ?>


Cytat
PS> Widziales Propela (dr_bonzo ;>)


Obejrzałem, rzeczywiście trochę podobne do mojego (lub, raczej, moje do ich). Jedna z większych różnic mojego rozwiązania, to że nie wymaga ono żadnej konfiguracji -- podajesz ustawienia połączenia z bazą danych i reszta śmiga sama. W Propelu trzeba stworzyć plik XML z opisem bazy (czyli w pewnym sensie zdenormalizować strukturę bazy).
SongoQ
Moje zdanie jest takie ze nie powinno sie az tak przenoscic na php, lepiej i wydajniej jest oprzec wiekszosc mechanizmow na bazach danych (jesli pozwalaja) a nie takie rzeczy pisac. Chociaz, jak kto woli.

Ale bezpieczniej, wydajniej jest przeniesc wiekszosc mechanizmow na baze. Bo implementacja czegos takiego nie zawsze jest oplacalna i nie zawsze sie da.
pies
Cytat(SongoQ @ 2005-09-12 20:58:41)
Ale bezpieczniej, wydajniej jest przeniesc wiekszosc mechanizmow na baze. Bo implementacja czegos takiego nie zawsze jest oplacalna i nie zawsze sie da.

Przeniesienie ciężaru z webserwerów na bazę danych spowoduje problemy z wydajnością przy skalowaniu. Frontend skaluje się dużo łatwiej (włącza się kolejne komputery do balansera) do niż bazę danych (najczęściej chyba replikacja, ale to nie moja działka).

Mamy taki problem w jednym serwisie klienta -- przy dużym ruchu na serwerze bazy danych (Postgres) kończą się wolne procesy bazy danych i następne Apacze nie mogą się połączyć. Cały czas staramy się zmniejszać obciążenie bazy. Serwis chodzi na 4 front + 1 db, o ile się nie mylę front-endy Sun Fire v490 i coś mocniejszego na bazę, ale nie wpuścili nas nigdy do serwerowni.
splatch
W propelu jest to zrobione nieco inaczej. Wzoruje się on na podobnych rozwiązaniach wykorzystywanych w Javie, gdzie definiuje się przy pomocy XMLa relacje pomiędzy encjami/tabelami.
  1. <?php
  2. $c = new Criteria();
  3. // Szuka wszystkich autorow o imieniu Karl
  4. // wyłączajac tych o nazwisku Marx
  5. $c->add(AuthorPeer::FIRST_NAME, "Karl");
  6. $c->add(AuthorPeer::LAST_NAME, "Marx", Criteria::NOT_EQUAL);
  7. $res = AuthorPeer::doSelect($c); // wyniki
  8. // Szuka wszytkich autorów o nazwisku Tolstoy, Dostoevsky, bądź Bakhtin
  9. $c2 = new Criteria();
  10. $c2->add(AuthorPeer::LAST_NAME, array("Tolstoy", "Dostoevsky", "Bakhtin"), Criteria::IN);
  11. $res = AuthorPeer::doSelect($c2); // wyniki
  12. ?>

Złączenie realizuje się poprzez:
  1. <?php
  2. // czyste złączenie na podstawie relacji określonej w XMLu
  3. AuthorPeer::doSelectJoinBook(new Criteria()); 
  4. ?>

Myślę, że warto się zainteresować mapowaniem obiektowo relacyjnym. Ma ono tą przewagę, że z raz opisanej bazy możemy korzystać do oporu, podczas gdy rozwiązanie przedstawione powyżej wymaga każdorazowego przepisywania części kodu.

@SongoQ biorąc przykład z Javy - dbanie o spójność danych jest często przenoszone na aplikację. Stąd popularność Hibernate czy Castro. Nie da się zaprzeczyć, że takie rozwiązanie spowalnia aplikację, ale "coś za coś"
pies
Cytat
  1. <?php
  2. $c = new Criteria();
  3. // Szuka wszystkich autorow o imieniu Karl
  4. // wyłączajac tych o nazwisku Marx
  5. $c->add(AuthorPeer::FIRST_NAME, "Karl");
  6. $c->add(AuthorPeer::LAST_NAME, "Marx", Criteria::NOT_EQUAL);
  7. $res = AuthorPeer::doSelect($c); // wyniki
  8. ?>


  1. <?php
  2. $res = $db->authors->first_name('Karl')->last_name('Marx', '!=')->value;
  3. ?>


Cytat
Myślę, że warto się zainteresować mapowaniem obiektowo relacyjnym. Ma ono tą przewagę, że z raz opisanej bazy możemy korzystać do oporu, podczas gdy rozwiązanie przedstawione powyżej wymaga każdorazowego przepisywania części kodu.


Nie bardzo wiem czy to argument za czy przeciw mojemu rozwiązaniu, ale jeden z powodów dla których nie używam rozwiązań w rodzaju Propel jest właśnie to: moje rozwiązanie, raz napisane, może być wykorzystywane do oporu, podczas gdy w przypadku Propela za każdym razem muszę przepisać ten XML.

Każde rozwiązanie ma swoje dobre strony. Propel, jak rozumiem, zapewnia bardziej formalne traktowanie bazy danych i dużo większe możliwości budowania złożonych zapytań. StraightDB zapewnia szybkie tworzenie aplikacji i dużą czytelność kodu.

Przypuszczam, że wybór jest kwestią zastosowań, ale do aplikacji internetowych, które zwykle często i szybko się zmieniają, stosowanie zdenormalizowanego opisu bazy danych może być złym pomysłem. Struktura bazy danych może być całkiem wydajnie odczytana z samej bazy, więc zapisywanie jej osobno to moim zdaniem strata czasu.

Co więcej, bardzo wiele informacji można przyjąć domyślnie -- np. wszystkie pola kończące się na "_id" możemy uznać za obce klucze, a początek ich nazwy za nazwę tabeli do której się odnoszą (np. "users_id" odnosi się do "users.id"). Przy takim założeniu automatyczne tworzenie joinów jest dość proste.

Rozwiązanie zastosowane w Rails (i skopiowane w Cake) to sposób na rozszerzenie funkcjonalności joinów bez stosowania dodatkowych plików. Rodzaj joina definiuje się w Modelu (MVC), np:

  1. <?php
  2. class Posts extends Model
  3. {
  4.  var $belong_to = 'users';
  5.  var $have_many = 'comments';
  6. }
  7.  
  8. ?>


Składnia jest oczywiście umowna, staram się tylko żeby rozwiązania były łatwe w użyciu, wymagały jak najmniej pisania i dobrze się czytały. Większość strat wydajnościowych wynika ze złych algorytmów, a zwięzły i czytelny kod pozwala na lepsze zrozumienie algorytmu i szybsze jego zmiany.

Cytat
@SongoQ biorąc przykład z Javy -  dbanie o spójność danych jest często przenoszone na aplikację. Stąd popularność Hibernate czy Castro. Nie da się zaprzeczyć, że takie rozwiązanie spowalnia aplikację, ale "coś za coś"


To pewnie kwestia zastosowań, ale wolę obciążać fronty (czyli zwykle aplikację) niż bazę, bo fronty się łatwiej skaluje.
splatch
Propel potrafi wygenerować opis XML z istniejącej struktóry. Także nie ma przymusu "uczenia się" tego. Bazę można wymodelować w jakimś programie.
Nie rozumiem jednak zdania "stosowanie zdenormalizowanego opisu bazy danych".

Założenie z kluczami obcymi - myślę, że jest ono dobrym pomysłem, ale pojawi się problem gdy zmieni się nazwę kolumny. Tzn. mam kolumnę users.id_user bądź users.user_id. Teraz system musi rozpoznać to czy chodzi o usersid.user czy usersuser.id. Zatem użytkownik musi zacząć nazywać kolumny w określony sposób, a na to nie każdy przystanie.
pies
Cytat
Propel potrafi wygenerować opis XML z istniejącej struktóry. Także nie ma przymusu "uczenia się" tego. Bazę można wymodelować w jakimś programie.
Nie rozumiem jednak zdania "stosowanie zdenormalizowanego opisu bazy danych".


Nie wiem jak dokładnie opisana jest struktura bazy w pliku XML Propela, ale jeżeli pokrywa się ona z opisem zawartym w samej bazie (np. nazwy, typy pól) to zmiana struktury bazy wymaga zmiany pliku XML. Jest to forma denormalizacji i trzeba pamiętać o uaktualnianiu, w przeciwnym przypadku mogą wystąpić dziwne błędy.

Cytat
Założenie z kluczami obcymi - myślę, że jest ono dobrym pomysłem, ale pojawi się problem gdy zmieni się nazwę kolumny. Tzn. mam kolumnę users.id_user bądź users.user_id. Teraz system musi rozpoznać to czy chodzi o usersid.user czy usersuser.id. Zatem użytkownik musi zacząć nazywać kolumny w określony sposób, a na to nie każdy przystanie.


Cóż, stosowanie metody opierającej się na przyjęciu pewnych założeń wymaga przyjęcia pewnych założeń.
splatch
Myślę, że na tym etapie prac porównywanie Propela i StraightDB jest pomyłką. Propel to gotowe rozwiązanie, podczas gdy StraightDB jest w fazie intensywnego rozwoju.
W StraightDB brakuje między innymi obsługi prostego zapytania typu DELETE, chyba, że coś przeoczyłem. Problematyczna jest również sprawa złączeń, ponieważ trudno bez jakiejkolwiek podpowiedzi (czy. informacji na temat relacji) to zrealizować. Czy złączenia wielokrotne będą realizowane poprzez $db->forum->with(posts)->with(body)->with(authors) czy w inny sposób?
Tak jak wspominał Michu brakuje obsługi bardziej złożonych warunków WHERE (..) OR (.. AND ..).
Brakuje mi również jakiegoś prostego interfejsu do obsługi stronicowania (wiem, że można określić limit i offset, ale chodzi o liczenie ilości stron itp.). W propelu jest to folder util. No i możliwości definiowania sortowania. Warto o tym pomyśleć. Przydatną funkcją w Propelu jest również możliwość zdefiniowania walidatorów, które sprawdzają poprawność danych przed dodaniem ich do bazy.

Cytat
Przypuszczam, że wybór jest kwestią zastosowań, ale do aplikacji internetowych, które zwykle często i szybko się zmieniają, stosowanie zdenormalizowanego opisu bazy danych może być złym pomysłem. Struktura bazy danych może być całkiem wydajnie odczytana z samej bazy, więc zapisywanie jej osobno to moim zdaniem strata czasu.

Zgadzam się. Wszystko zależy od tego, jak bardzo mamy złożoną aplikację. Co do zmian w bazie danych - przeważnie projekt zaczyna się od projektu bazy danych. Źle zaprojektowana baza utrudnia rozwijanie aplikacji. Czasami trzeba coś zmienić żeby uzyskać porządany efekt. W propelu to nie jest problem. Można spokojnie wygenerować XML z istniejącej bazy. Właśnie ten XML daje funkcję, na którą warto się skusić - możliwość migracji z jednego systemu bazodanowego na drugi. Fakt - struktura tabeli możę być odczytana z bazy, ale narzuca to pewne ograniczenia - które zaczną się robić niewygodne. StraightDB korzysta z własnej warstwy abstrakcji. To błąd. Istnieją już gotowe, sprawdzone rozwiązania - jako, że biblioteka jest przeznaczona dla PHP5 można skorzystać z PDO bądź Creole. Czy jest sens pisać na nowo kolejny interfejs, skoro istniejące są bardzo dobre? To tak jakby w Javie pisać kolejne JDBC.
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.