A Ty w jaki sposób łączysz się z bazą danych?

Tytuł zabrzmiał jak w Matrik­sie. Chodzi oczy­wi­ście o łącze­nie apli­ka­cji PHP z bazą danych. Dzisiaj pokażę w jaki sposób w niewiel­kich projek­tach radzę sobie z przy­go­to­wa­niem obiektu PDO do pracy z bazą danych. Trudno żebym w niewiel­kiej „stronce” zaprzę­gał jakiś Zend Framework.

Napi­sa­łem sobie dawno temu klasę narzę­dziową do tworze­nia obiektu PDO. Imple­men­tuję w niej wzorzec projek­towy single­ton, a więc mam pewność, że gdzie­kol­wiek w kodzie żądam PDO, zawsze dostaję ten sam obiekt. Jeżeli chodzi o sam single­ton, to na jego temat można prze­czy­tać zarówno we Wzor­cach Projek­to­wych1 jak i w Design Patterns.2 Zresztą to w Googlu wysko­czy pier­dy­lion wyników ;-)

Używa­nie klasy jest dzie­cin­nie proste. Należy sobie jedno­ra­zowo prze­edy­to­wać stałe klasy doty­czące połą­cze­nia z bazą, a następ­nie w kodzie wywo­ły­wać metodę DBHandler::getPDO()

Poni­żej podaję kod klasy. Bierz­cie i jedzcie ;-)

<?php
class DBHandlerException extends PDOException {
}
 
/**
 * @author Dawid 'Spiechu' Spiechowicz
 * @license see http://spiechu.pl/o-publikowanym-kodzie/
 */
class DBHandler {
 
  /**
   * Dane bazy danych
   */
  const DB_HOST = 'localhost';
  const DB_NAME = 'nazwa bazy';
  const DB_USER = 'nazwa usera';
  const DB_PASS = 'haslo';
 
  /**
   * Sterownik bazy danych
   */
  const DB_DRIVER = 'mysql';
 
  /**
   * Czy wyswietlac dokladne komunikaty bledow
   */
  const DEBUG_MODE = true;
 
  /**
   * @var PDO singleton PDO
   */
  private static $pdo = null;
 
  /**
   * Zwraca singleton PDO lub wyswietla komunikat bledu i zwraca null.
   * @return PDO|null
   */
  public static function getPDO() {
    try {
      if (self::$pdo === null) {
        self::$pdo = self::createPDO();
      }
      return self::$pdo;
    }
    catch (DBHandlerException $e) {
      echo $e->getMessage();
      return null;
    }
  }
 
  /**
   * @return PDO zwraca nowa instancje PDO
   * @throws DBHandlerException
   */
  private static function createPDO() {
    if (!extension_loaded('PDO')) throw new DBHandlerException('Brak modulu PDO');
    try {
      $pdo = new PDO(
         self::DB_DRIVER . ':host=' . self::DB_HOST . ';dbname=' . self::DB_NAME, 
         self::DB_USER, 
         self::DB_PASS,
         array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
      $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
      return $pdo;
    }
    catch(PDOException $e) {
      if (self::DEBUG_MODE == true) {
        throw new DBHandlerException("Blad bazy danych : {$e->getMessage()}");
      }
      else {
        throw new DBHandlerException('Blad bazy danych');
      }
    }
  }
 
  /**
   * Zapobiega tworzeniu obiektu.
   */
  private function __construct() {
    throw new Exception('Nie mozna stworzyc tego obiektu!');
  }
 
  /**
   * Zapobiega klonowaniu obiektu.
   */
  private function __clone() {
    throw new Exception('Nie mozna klonowac tego obiektu!');
  }
}

Powy­żej widać kilka sztu­czek. Przede wszyst­kim konstruk­tor ma zasięg prywatny, co zapo­biega stwo­rze­niu instan­cji klasy z zewnątrz. Mało tego, próba wywo­ła­nia go z wnętrza klasy spowo­duje wyrzu­ce­nie wyjątku. To samo z metodą __clone().

Przy konfi­gu­ra­cji obiektu PDO usta­wiam tryb błędów na wyjątki, które wyła­puję i w zależ­no­ści od usta­wio­nej stałej DEBUG_MODE wyświe­tlam komu­ni­katy błędów PDO lub nie. Frag­ment $pdo->query('SET NAMES utf8') usta­wia kodo­wa­nie znaków na Unicode. Niestety nie znala­złem lepszej metody. Rezul­taty zapy­tań domyśl­nie będą dostępne w postaci tablicy asocjacyjnej.

  1. E. Gamma (i in.) : Wzorce projek­towe. Elementy opro­gra­mo­wa­nia obiek­to­wego wielo­krot­nego użytku. Gliwice : Helion, 2010, s. 130–136.
  2. E. Freeman (i in.) : Head First Design Patterns. Gliwice : Helion, 2005, s. 197–216.

Podobne wpisy:

  1. PDO poprzez Depen­dency Injec­tion Conta­iner [cz. 1/2]
  2. PDO poprzez Depen­dency Injec­tion Conta­iner [cz. 2/2]
  3. XHTML 2 — jaki będzie?
  4. Wzorzec projek­towy memento w PHP

25 Comments

  • krzotr
    10 kwietnia 2011 - 19:39 | Permalink

    Nie znala­złeś innego sposobu na usta­wie­nia kodowania ?

    http://www.php.net/manual/en/ref.pdo-mysql.php

    Ustaw PDO::MYSQL_ATTR_INIT_COMMAND na „SET NAMES utf8”

  • Śpiechu
    10 kwietnia 2011 - 20:21 | Permalink

    @krzotr
    Rozwią­za­nie lepsze od mojego. Bardziej zgodne ze sztuką. W prak­tyce efekt będzie taki sam jak mój.
    Popra­wiam i dzięki

  • 10 kwietnia 2011 - 20:28 | Permalink

    Trochę obok tematu, ale jeśli po angiel­sku piszesz „@license see http://spiechu.pl/o-publikowanym-kodzie/”, to może na tej stro­nie warto by też wsta­wić angiel­ską wersję tekstu? :-)

  • Śpiechu
    10 kwietnia 2011 - 20:40 | Permalink

    @Malin
    Rzeczy­wi­ście przy­da­łoby się prze­tłu­ma­czyć. W ogóle to chyba zmie­nię treść na New-BSD i tyle. Najbar­dziej mi odpowiada.

  • Artur Świerc
    10 kwietnia 2011 - 20:51 | Permalink

    - extension_loaded(‚PDO’) zwraca wyją­tek DBHan­dle­rE­xcep­tion który od razu jest prze­chwy­ty­wany i znów zwra­cany. Lepiej go wycią­gnąć przed try/catch i po prostu wyrzu­cać.
    – po co robić catch na DBHan­dle­rE­xcep­tion skoro i tak robisz później throwa na DBHan­dle­rE­xcep­tion
    – echo w getPDO nie jest dobrym rozwią­za­niem. Metoda powinna zwra­cać wyją­tek DBHan­dle­rE­xcep­tion, który powi­nie­neś prze­chwy­cić w później­szej części i wyświe­tlić info o błędzie w zależ­no­ści od tego, czy to serwer produk­cyjny, testowy etc. W końcu użyt­kow­nika serwisu nie inte­re­suje napis na samej górze strony ‚Blad bazy danych’ :)

    Gene­ral­nie zaczą­łeś od wyjąt­ków, a skoń­czy­łeś na zwró­ce­niu nulla i wyświe­tle­nia błędu. Pozdr. :)

  • 10 kwietnia 2011 - 21:08 | Permalink

    A nie lepiej byłoby zapro­gra­mo­wać sobie jakiś najbar­dziej trywialny Depen­dency Injec­tion Conta­iner i prze­ka­zy­wać go gdzie potrzeba? Użycie Single­tona to chyba najbar­dziej leniwy sposób na osią­gnię­cie takiego celu, jaki mogę sobie wyobra­zić. Rozu­miem, że to pewnie prosty projek­cik, ale nawet w takich trzeba się trochę posta­rać, żeby potem nie popra­wiać kilka razy. Co, jeśli będziesz potrze­bo­wał drugiego połą­cze­nia do bazy danych? Napi­szesz sobie drugiego Singletona?

  • 10 kwietnia 2011 - 21:23 | Permalink

    Nie to żebym się czepiał, ale czemu dane do połą­cze­nia z bazą danych wpisane w klasę jako stałe? Przez to trzeba tworzyć nowy kod klasy dla każdego połą­cze­nia z bazą danych co jest lekko mówiąc przesadą.

    Ja w swojej wersji klasy PDO doda­łem funk­cjo­nal­ność zlicza­nia ilości zapy­tań oraz usta­wia­nia kodo­wa­nia przez metodę (domyśl­nie utf-8), ale istnieje opcja poda­nia kodo­wa­nia jako parametr.

  • Śpiechu
    10 kwietnia 2011 - 21:31 | Permalink

    @Artur Świerc
    Z try-catch lepiej prze­su­nąć wyżej, zgadzam się (i popra­wiam).
    Jeżeli system nie może połą­czyć się z bazą danych to zazwy­czaj strona jest całko­wi­cie kaput. Pamię­tajmy, że mówię tutaj o prostych projektach.

    @Tomasz Kowal­czyk
    Po co mam potrze­bo­wać drugiego połą­cze­nia? Stosuję takie rozwią­za­nie od co najmniej trzech lat i nic nigdy nie nawa­liło.
    W zasa­dzie to wystar­czy createPDO() zamie­nić na public i za każdym razem będzie zwra­cała nowy obiekt PDO.
    Robi­łeś kiedyś stronę z 5 podstro­nami + gale­rią zdjęć do każdej z nich? Tam nie potrzeba żadnych ORMów, cacheów i tego typu rzeczy.
    Ostat­nio zauwa­żam, że ruch przeciw-singletonowy rośnie w siłę! ;-)

    Dzięki za uwagi, pozdro.

  • 11 kwietnia 2011 - 06:37 | Permalink

    Wybacz drogi auto­rze ale to chyba najgor­sze rozwią­za­nie jakie widzia­łem od 2 lat.
    1. Jak mi się zmie­nią dane do BD to co zrobię ? Będę edyto­wał plik ? Jak pracuje u siebie a serwer klienta jest gdzie indziej to co ? Nie prze­rzucę plików podmie­nia­jąc konfi­gu­ra­cję tylko będę edyto­wał klasę ?
    2. Ty właści­wie nic tam nie zrobi­łeś jeżeli dobrze zwró­ci­łem uwagę. Obudo­wa­łeś tylko PDO i po ptakach. Więc nie rozu­mie po co cały wpis na to robić. Chyba że chcia­łeś zwró­cić porów­na­nie jakieś.
    3. Jak ja to robię ? Stosuję PDO z Adap­te­rem, prawie jak Ty ale nie robię single­tona i jakiś dziw­nych sztu­czek. Zbudo­wa­łem sobie adap­ter który obsłu­guje:
    ~ getAll()
    ~ getRow()
    ~ getOne()
    ~ insert($source, array $data)
    ~ update($source, array $data)
    ~ delete($source, array $data)
    ~ select($source, array $data)
    ~ save($source, Data­Object $Data) (ta metoda jest połą­cze­niem insert i update)

    Połą­cze­nie nawią­zuję poprzez prze­ka­za­nie para­me­trów do konstruk­tora a w środku siedzi po prostu PDO. Ot robię po prostu w obiek­cie wstępną konfi­gu­ra­cję PDO jak Ty teoretycznie.

    Po co tak ? Już zdarzało mi się że projekt (nawet nieduży) współ­pra­co­wał z 2 bazami danych. Metody które widzisz wyżej dzia­łają zarówno przy inte­gra­cji z bazą danych jak i zewnętrz­nym serwe­rem, plikami (pobierz cały plik, pobierz wiersz, pobierz pierw­sze słowo itp… z para­me­trem $data gdzie znaj­dują się dane bądź kryte­ria wyszu­ka­nia, aktu­ali­za­cja odbywa się po kluczach głów­nych gdzie tabele mają go mieć obowiąz­kowo).
    Obec­nie mam adap­tery na bazą danych, pliki i face­book (jest taka zabawka jak face­book sql).

    Wybacz ale o ile to Twoje rozwią­za­nie jest akcep­to­walne przy malut­kiej stronce o tyle wszystko inne leży. A to że musiał bym trzy­mać osobny plik z klasą tylko dlatego że klient na serwe­rze ma inne dane do sql to już zakrawa na żart.

  • Śpiechu
    11 kwietnia 2011 - 07:31 | Permalink

    @Dariuszp
    1. Konfi­gu­ra­cję mody­fi­ku­jesz tak czy siak podmie­nia­jąc plik. Chcąc mieć wszystko w jednym miej­scu można po lekkich prze­rób­kach zrobić klasę Config, w której oprócz danych nt. połą­cze­nia z bazą danych będą trzy­mane pozo­stałe rzeczy.
    2. Przy­po­mi­nam, że blog ma charak­ter hobby­styczny, a jego odbior­cami są również ludzie dopiero rozpo­czy­na­jący przy­godę z PHP. Podczas analiz kodu innych nie raz natkną­łem się na kwiatki w stylu poda­wa­nia haseł do bazy w 20 miej­scach wszę­dzie tam gdzie PDO było potrzebne. Mój sposób jest próbą uporząd­ko­wa­nia tego.
    3. Można napi­sać sobie „ułatwia­cze” albo lepiej użyć goto­wego narzę­dzia jak choćby phpDa­ta­Map­per lub NotORM

    Przy­sto­so­wa­nie klasy do współ­pracy z dwiema bazami raczej nie powinno być trudne.

  • 11 kwietnia 2011 - 11:01 | Permalink

    Auto­rze, a jak sobie wyobra­żasz Twoją wspa­niałą klasę zapi­saną w na jakimś dowol­nym repo­zy­to­rium SVN/GIT/… gdzie jest kilku­dzie­się­ciu deve­lo­pe­rów i każdy ma własną dev bazę, poza tym jest jesz­cze serwer testowy wewnętrzny, serwer testowy dla klienta i oczy­wi­ście serwer stabilny klienta.
    Konfi­gu­ra­cja bazy wewnątrz to się nadaje — dla księgi gości, czy „MyOwn­Su­pa­Hi­paCMS”.
    Naprawdę, jeśli już coś wypusz­cza­cie w sieć z myślą „może się innym przyda”, popa­trz­cie na to coś od strony poten­cjal­nego „wykorzystywacza” :)

  • Śpiechu
    11 kwietnia 2011 - 11:18 | Permalink

    @scanner
    Nikt Cię nie zmusza do używa­nia. Jest to pewna propo­zy­cja.
    Może jak Twoja strona wyjdzie z prze­rwy tech­nicz­nej to pochwa­lisz się jakimś konkret­nym kodem? Też sobie chęt­nie trochę pojeżdżę.

  • 11 kwietnia 2011 - 11:28 | Permalink

    @Śpiechu, ale zauważ że pliku konfi­gu­ra­cyj­nego NIE MUSZĘ prze­rzu­cać. Konfi­gu­ra­cja systemu i kod to dwie różne rzeczy które nawet nie muszą być ze sobą powią­zane. Bo w momen­cie jak wywalę bezczel­nie konfi­gu­ra­cję to po prostu system działa na domyśl­nej (w wypadku bd to np local­host + root + brak hasła).
    I tak mogę praco­wać z kodem, z mojej biblio­teki korzy­sta 4 różne osoby w jednym momen­cie i ŻADNA nie ma proble­mów bo każdy ma inny plik konfi­gu­ra­cyjny.
    Przy zasto­so­wa­niu tego co Ty zapro­po­no­wa­łeś mieli byśmy przede wszyst­kim poważny problem przy pracy grupo­wej albo po prostu wymu­sił byś stoso­wa­nie na nas jedna­ko­wej konfi­gu­ra­cji serwera bd. Gdzie wszy­scy siedzimy na gicie + serwer z projek­tem a każdy ma skon­fi­gu­ro­wane własne izolo­wane środo­wi­sko na swojej maszy­nie.
    Nie mówiąc o tym że twoja klasa W OGÓLE nie nadaje się do użytku wtór­nego co jest jej najwięk­szym grzechem.

    —————————————————————

    Co do phpDa­ta­Map­per to wybacz ale dla mnie jest to BARDZO złe rozwią­za­nie. Bo skoro mam pisać:

    $posts = $postMapper->select()
    ->from(‚mytable’)
    ->where(array(‚user_id’ => ‚5’))
    ->orWhere(array(‚account_id’ => array(1, 2, 3, 6, 12, 82)));

    to równie dobrze mogę wsadzić bezczel­nie SQL’a w kodzie. I będzie to szyb­sze, i się pewnie mniej spisze niż przy tym cudzie. A teraz popatrz na to:

    $User = new User();
    $User->name = ‚tester’;
    $User->password = encodePassword(‚hello kitty’);
    if($UserMapper->find($User)) {
    echo Mozna logo­wac, aktu­alne id to $User->id
    }
    else {
    echo ‚ni huhu!’;
    }

    1. Nie trzy­mam SQL w kodzie ani normal­nie ani „phpowo„
    2. Nie obcho­dzi Cie gdzie trzy­mam użyt­kow­ni­ków (Mapper może odwzo­ro­wy­wać bazę danych, zewnętrzny serwer obsłu­gi­wany przez soap czy nawet face­bo­oka i jego „face­book sql”)
    3. Kod jest dość czytelny i odporny na wszel­kie mody­fi­ka­cje na pozio­mie źródła danych (czyli nie bolą go zmiany struk­tury bazy danych, nazwy i ilości pól itp itd etc).

    —————————————————————

    Wiem że to jest blog ale kiedy dajesz wpis na sieć to spodzie­waj się komen­ta­rzy ;-) Nie ganię tylko zwra­cam uwagę jak inni. Zwłasz­cza że lata temu sam robi­łem takie potworki (no może nie aż takie ale zawsze).

  • 11 kwietnia 2011 - 11:39 | Permalink

    @Dariuszp: no to prawie zrobi­łeś Zend_Db ;)

  • Crozin
    11 kwietnia 2011 - 11:47 | Permalink

    > Trudno żebym w niewiel­kiej „stronce” zaprzę­gał jakiś Zend Framework.

    Proszę podaj jeden konkretny argu­ment dlaczego nie.

  • 11 kwietnia 2011 - 12:09 | Permalink

    @matipl, no właśnie nie do końca. Inter­fejs bazy danych który wypi­sa­łem tam wyżej jest prawie że pełny. Zend_db również ma kwiatki takie jak np:

    $select = $db->select()
    ->from( array(‚p’ => ‚products’) );

    a jest to jedna z form które stara­łem się unikać bo właści­wie znowu piszesz sql tylko ‚inaczej’. Zwłasz­cza że obiekt bd siedzi u mnie ZAWSZE POD mappe­rem i właści­wie sam z niego nie korzy­stam z palca. Kiedyś w jednej pracy kolega rzucił pomysł żeby progra­mi­sta mógł mieć mecha­nizm w którym nie ba bladego poję­cia z jakiego źródła danych on korzy­sta. I wg tego zapla­no­wa­łem powyż­szy inter­fejs. Sam mapper jest właści­wie tylko adap­te­rem do obiektu który obsłu­guje źródło danych. Jak na razie testo­wa­łem go z:

    1. Bazą danych
    2. Plikami
    3. Klien­tem soap
    4. zewnętrz­nym serwe­rem za pomocą socke­tów (w ramach jednego projektu dla pewnej firmy)
    5. facebookiem

    W prak­tyce wygląda to tak;

    $User­Map­per = new \Module\User\data\UserMapper(new Database(‚wiadomo…’));
    $User­Map­per = new \Module\User\data\UserMapper(new File(‚./users’));
    $User­Map­per = new \Module\User\data\UserMapper(new Server(‚ip’, ‚port’, itp… ));
    $User­Map­per = new \Module\User\data\UserMapper(new mySoap(‚wiadomo’));
    $User­Map­per = new \Module\User\data\UserMapper(new Facebook(‚itp…’));

    nieza­leż­nie który z warian­tów użyjesz to:

    $User = new User();
    $User->name = ‚tester’
    $List = $UserMapper->find($User);

    Zawsze zwróci Ci taką samą listę użyt­kow­ni­ków którzy mają nazwę ‚tester’. Oczy­wi­ście można sobie skon­fi­gu­ro­wać mapper by zwró­cił Ci obiekt user (czy tez obiekty user) albo tablicę itp. Jeżeli potrzebne mi jest jakieś skom­pli­ko­wane zapy­ta­nie w stylu getRe­gU­ser­Stats() albo coś takiego to mapper odstaje po prostu nową metodę. Klasa bazowa dla mappera ma taką skromną metodę returnData($data) która w zależ­no­ści co dosta­nie za para­metr, prze­tłu­ma­czy dane na to co mapper powi­nien zwró­cić wg konfi­gu­ra­cji. Pełna automatyka.

    Zalety ?:
    1. Bladego poję­cia nie masz gdzie zapi­sy­wane są dane i nie jest ci to do szczę­ścia potrzebne
    2. Jak „skom­pli­ko­wane zapy­ta­nie które trzeba było wpisać z palca w mapper db np” zwraca nie to co trzeba to nie rozgrze­bu­jesz kodu apli­ka­cji szuka­jąc gdzie to trzeba popra­wić tylko edytu­jesz mapper który jest odpo­wie­dzialny za dany podmiot (w tym wypadku użyt­kow­nika)
    3. Nieza­leż­nie z czym pracu­jesz, zawsze masz te same metody i ten sam inter­fejs :P Ekstra metody i tak są dopi­sy­wane do mappera więc IDE Ci je podpo­wie.
    4. Nie piszesz SQL’a w kodzie.
    5. Niech progra­mi­sta który przy­go­to­wuje mapper się martwi jak zapi­sy­wać dane użyt­kow­ni­ków do plików i jak mapper ma je obsłu­gi­wać. Klienci takiego kodu mają o tym nawet nie myśleć.

  • leszlo
    11 kwietnia 2011 - 12:17 | Permalink

    @matipl: Dariuszp pisze o rozwią­za­niu używa­nym w całko­wi­cie innej warstwie apli­ka­cji (http://martinfowler.com/eaaCatalog/dataMapper.html)
    W tym rozwią­za­niu Zend_Db byłby odpo­wie­dzialny tylko za dostęp źródła danych (obsługa połą­cze­nia, gener­wa­nie zapy­tań).
    Używa­jąc:
    $user = $userMapper->find($id);
    albo:
    $UserMapper->save($user);
    nie wiesz nawet skąd pocho­dzą dane ani jak są zapi­sy­wane. Dosta­jesz gotowy obiekt $user który nie musi imple­men­to­wać żadnej obsługi zapisu.
    Dariu­szu skąd pomysł na takie rozwiązanie?

  • Śpiechu
    11 kwietnia 2011 - 12:30 | Permalink

    @Crozin
    A chociażby dlatego, że ZF to olbrzy­mia biblio­teka rozpar­ce­lo­wana na kilka­set plików, z której zyski odczu­wasz dopiero wtedy gdy jest potrzebna, tzn. masz kilka­set tysięcy UU, masz wiele tabel, niezau­fani użyt­kow­nicy mają tam konta i testują na wszel­kie sposoby zabez­pie­cze­nia witryny. Mnie chodzi o stronę dla firmy Kazio & Stefan roboty budow­lane sp. nawet nie z o.o..
    Dla takich potrzeb jest chociażby np. MeekroDB — lekka biblio­teka w jednym pliku.

    Nie mówcie mi, że wyko­nu­je­cie same systemy dla banków.

  • 11 kwietnia 2011 - 12:38 | Permalink

    Racja, chodziło mi o to że pisząc całe rozwią­za­nie nie widzia­łem sensu żeby stoso­wać Zend_db gdyż imple­men­ta­cja tego była jednym małym ekspe­ry­men­tem. Więc wola­łem go zrobić cało­ściowo. Nie mówiąc o tym że za Zendem akurat niezbyt prze­pa­dam.
    Inter­fejs rozpla­no­wa­łem tak by można go było łatwo zasto­so­wać nie tylko do Db. Bo inaczej całą koncep­cję by mi szlag trafił.
    A pomysł częściowo wynio­słem z mojej pierw­szej pracy. Mieli tam w syste­mie Data Mapper wyko­rzy­stany. Przy okazji dorwa­łem się też do książki „Archi­tek­tura syste­mów zarzą­dza­nia przed­się­bior­stwem” (głupie tłuma­cze­nie z ang ale co tam) Problem w tym że współ­pra­co­wał on tylko z bazą danych MySQL. Kolega który go wyko­nał powie­dział że chciał ukryć źródło danych tak by progra­mi­sta nie musiał się inte­re­so­wać „co tam jest pod spodem”.
    No i tak zrodził się mój chory pomysł któremu poświę­ca­łem wolny czas (pomi­ja­jąc resztę projek­tów).
    Chodziło głów­nie o to że imple­men­ta­cja którą stoso­wano w pracy korzy­stała tylko z bd. Chcia­łem tego uniknąć.

    I tak masz obiekt mappera który właści­wie jest tylko adap­te­rem. Obiekt który łączy się ze jakimś źródłem danych jak poda­łem wyżej i obiekty danych które są ustan­da­ry­zo­wane dla cało­ści (znaczy zmie­nia im się tylko zestaw pól).

    Sprawa była łatwa w wypadku baz danych, face­bo­oka i klienta soap. Nad plikami i socke­tami się nasie­dzia­łem. To ostat­nie jest bezu­ży­teczne z uwagi na to że mapper był dedy­ko­wany rozwią­za­niu firmy gdzie to zasto­so­wa­łem, a ci nie korzy­stali z żadnego proto­kołu (własne rozwiązanie).

  • 11 kwietnia 2011 - 13:38 | Permalink

    Poza tym zauważ że kolega porów­nał rozwią­za­nie do Zend_db więc do tego się odniosłem :-)

  • Artur Świerc
    11 kwietnia 2011 - 19:24 | Permalink

    @Dariuszp; rozwią­za­nie opie­ra­jące się o fluent inter­face jest o tyle dobre, że nie musisz później konka­to­wać strin­gów. Wyobraź sobie sytu­ację, w której za doda­wa­nie filtrów, grupo­wa­nie czy sorto­wa­nie odpo­wia­dają różne metody. Wtedy String SQL lata po całej klasie i rozpo­czyna się sklejanie.

    Co do samego rozwią­za­nia z active records, osobi­ście stosuję rozwią­za­nie z DDD, encje, repo­zy­to­ria itp. Czyli Twoje DAO/Mapper + encje, tyle że nie ma tyle getterów/setterów, a jest więcej opera­cji na pełnych obiek­tach, dzięki czemu nie piszesz strukturalnie:

    user = new user();
    user.name =
    user.lastname =
    user.address =
    user.ulubiona_zupa = …

    Za dużo pisania.

    Pozdr.

  • 11 kwietnia 2011 - 21:49 | Permalink

    @Artur Świerc, z DDD jesz­cze się tak dobrze jak bym chciał nie zapo­zna­łem ale czy przy­pad­kiem DAO które stosuje nie podcho­dzi pod Encje ? Zauważ że w przy­kła­dzie który poda­łem masz obiekt User który jest rozwi­nię­ciem DAO i może swobod­nie imple­men­to­wać metody które na nim operują. Gettery i settery się śmieje, są jak prezer­wa­tywa. Lepiej je mieć i nie potrze­bo­wać jak potrze­bo­wać i nie mieć.
    Z uwagi na swoje zbocze­nie mam w nich zaim­ple­men­to­wane gettery i settery + magię tylko dlatego że różni ludzie prefe­rują różne podej­ścia.
    Chęt­nie bym się gdzieś przyj­rzał Twojemu rozwiązaniu.

    Pozdra­wiam

  • 11 kwietnia 2011 - 22:17 | Permalink

    Arggggg­ghhhhhh.… magia, single­ton, miesza­nie odpo­wie­dzial­no­ści klasy. Sam sobie utrud­niasz życie w tych prostych projek­tach, bo skon­fi­gu­ro­wa­nie PDO do dzia­ła­nia to są całe trzy linijki kodu, a konfi­gu­ra­cję możesz w takim prościut­kim skryp­cie wrzu­cić do pliku typu config.php w postaci tablicy.

    Co do tych trzech linijek:

    1. Utwo­rze­nie obiektu PDO i wczy­ta­nie warto­ści argu­men­tów z tablicy
    2. Zmiana rapor­to­wa­nia błędów na wyjątki.
    3. Usta­wie­nie kodo­wa­nia (w przy­padku MySQL-a).

  • thek
    12 kwietnia 2011 - 13:06 | Permalink

    Pozwo­lisz, że sobie żartem odpo­wiem na pyta­nie… „Telepatycznie” ;)

    A poważ­nie: plik konfigu z przy­go­to­wa­nymi już tam iden­ty­fi­ka­to­rami połą­czeń i wszyst­kimi danymi jako tablica. Dołą­czam i już wiem do jakiego obiektu lub zmien­nej połą­cze­nia się odno­sić dla każdej z baz, bo każda ma inny obiekt/identyfikator tworzony. Z leni­stwa mi sie po prostu nie chce tworzyć tego w osob­nych plikach. Jeden config i wsio. Choć można by dla czytel­no­ści wydzie­lić osobne pliki dla róznych typów połą­czeń, a więc rawmysql.php, pdophp itp :)

  • MNK
    23 sierpnia 2011 - 22:08 | Permalink

    @krzotr
    PDO::MYSQL_ATTR_INIT_COMMAND na „SET NAMES utf8” jakoś znik­nęło d PHP5.3 … Zaleca się używa­nia sposoby poka­za­nego w przykładzie :)

  • Dodaj komentarz

    Twój adres e-mail nie zostanie opublikowany.

    Możesz użyć następujących tagów oraz atrybutów HTML-a: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <p> <pre lang="" line="" escaped=""> <q cite=""> <strike> <strong>