Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: Damian Tylczyński, dodany: 09.06.2009 05:02, tagi: php, php6

Informacja o artykule poświęconym refaktoryzacji kodu.

Autor wpisu: Damian Tylczyński, dodany: 09.06.2009 03:36, tagi: php, php6

Osobiste wrażenia po opublikowaniu propozycji zmian dla PHP 6.0.

Autor wpisu: eRIZ, dodany: 05.06.2009 15:10, tagi: php, skrypty

Jak wygląda życie zwykłego użytkownika Wordpressa…? Otwarcie przeglądarki, logowanie, napisanie notki, publikacja. Zaraz, a gdyby np. skorzystać w tym celu z jakiejś zewnętrznej aplikacji? Owszem, jest tego w pęczki, nie ma sensu wynajdywanie koła na nowo. Jednak protokół, z którego korzystają zewnętrzne aplikacje, może być wykorzystany także w naszych bibliotekach oraz z poziomu samego PHP.

Pomysł na dzisiejszy wpis podsunął mi ^lukjarz. ;]

Autor wpisu: Diabl0, dodany: 29.05.2009 22:25, tagi: zend_framework

nbpJakiś czas temu stworzyłem prostą klasę do pobierania kursów walut z NBP. Dla przyśpieszenia działania i odciążenia serwerów NBP wykorzystuje ona Zend_Cache do przechowywania danych po pobraniu. Niestety, ostatnio kilka razy zdarzyła się sytuacja że cache się już przeterminował, trzeba pobrać nowe dane a… serwer NBP odpowiada błędem. I wszyscy są wściekli. Pracownicy, bo nie mogą pracować, szefostwo, bo pracownicy nie pracują, oraz ja bo muszę tłumaczyć że nie mam na to wpływu… Jak się jednak okazało - mam :)

Jak zwykle, wystarczyła dokładniejsza lektura API i odkrycie że metoda Zend_Cache_Core::load ma kilka parametrów, w tym jeden bardzo nas interesujący:

@param  boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested

Wystarczyło teraz troszkę ruszyć palcami i:

        /* @var $cache Zend_Cache_Core */
        $cache = Zend_Registry::get ( 'cache' );

        // UWAGA - porównie z przypisaniem = TUTAJ MA BYĆ POJEDYŃCZY ZNAK RÓWNOŚCI
        if ($data = $cache->load ( 'Mao_Service_ExchangeRates_NBP' )) {
            // Pobrano dane z cache i dane są jeszcze aktualne
            $data = unserialize ( $data );
            $this->_dataDate = $data ['_dataDate'];
            $this->_data = $data ['_data'];
        } else {
            // Dane pobrane z cache są przeterminowane, próbujemy pobrać nowe
            try {
                $this->_fetchData ();

                $data = array (
                    '_dataDate' => $this->_dataDate,
                    '_data' => $this->_data
                 );

                $cache->save ( serialize ( $data ), 'Mao_Service_ExchangeRates_NBP', array (), 3600 );

            } catch ( Exception $e ) {
                // Nie udało się pobrać danych z źrudła (przyczyna nas na razie nie interesuje)

                // Pobieramy dane z cache nawet jeśli są przeterminowane.
                $old_data = $cache->load ( 'Mao_Service_ExchangeRates_NBP', true );

                if ($old_data) {
                    // Na szczęście mamy "stare" dane które możemy wykorzystać
                    $data = unserialize ( $old_data );
                    $this->_dataDate = $data ['_dataDate'];
                    $this->_data = $data ['_data'];

                    try {
                        // Próbujemy raportować możliwy problem do "systemowego" loggera
                        // Teoretycznie logger powinien być, ale kto wie czy kiedyś ktoś
                        // tego nie wykorzysta gdzieś indzie i będzie się zastanawiał czemu wyskakuje exception
                       $logger = Zend_Registry::get ( 'logger' );
                       $logger->warn ( 'Mao_Service_ExchangeRates_NBP old data used. Reason:' . $e->getMessage () );
                    } catch (Exception $e) {
                        // Uuuu... Problem z loggerem? co to za konfiguracja?
                        // Na szczęście to nie jest krytyczny problem więc ignorujemy
                    }
                } else {
                    // No to mamy spory problem, nie ma ani danych z źrudła, ani danych
                    // Nic więcej nie jesteśmy w stanie zrobić tutaj z tym problemem,
                    // więc wyrzucamy go wyżej
                    throw $e;
                }
            }

        }

Próbujemy wczytać dane z cache. Jeśli nie ma danych lub są przeterminowane ($cache->load zwraca false)  to próbujemy pobrać nowe dane z NBP. Jeśli z jakiegoś powodu nie uda się to nam, to ponownie próbujemy pobrać dane z cache tym razem nie zwracając uwagi na ich “przydatność do spożycia”. No i w ostateczności jeśli i to zawiedzie, to i tak jesteśmy na tyle głęboko w czarnej d… że możemy wyrzucić wyjątek wyżej i dać innym zająć się tym problemem. My zrobiliśmy wszystko co w naszej mocy.

Aby dopełnić arta zamieszczam również pełną klasę Mao_Service_ExchangeRates_NBP. Może się komuś przyda.

Autor wpisu: SongoQ, dodany: 28.05.2009 01:48, tagi: php, symfony, sql

W aplikacjach internetowych czasami musimy wykorzystać w jednym serwisie wiele baz danych, nieraz nawet wiele różnych baz danych. Mój wpis będzie prezentował proste przykłady użycia wielu baz z wykorzystaniem frameworka Symfony. Dla przykładu użyje bazy danych PostgreSQL oraz ORM Propela 1.3.

W przykładzie wykorzystam 2 tabele: “users” z bazy “db1″ (załóżmy, że to główna bazy serwisu z użytkownikami) i “requests” z bazy “db2″ (baza w której zapisywane są statystyki z żądań do aplikacji). Modele wygenerowane będą dla bazy PostgreSQL. W kolejnym etapie zaprezentuje w jaki sposób można załadować przykładowe dane pochodzące z data/fixtures.

Definiowanie baz w pliku databases.yml

Edytujemy config/databases.yml

all:
  propel:
    class:        sfPropelDatabase
    param:
      classname:  PropelPDO
      dsn:        pgsql:dbname=db1;host=panic user=db1 password=db1
      hostspec:   pgsql
      port:       5432
      encoding:   utf8

  stat:
    class:        sfPropelDatabase
    param:
      classname:  PropelPDO
      dsn:        pgsql:dbname=db2;host=panic user=db2 password=db2
      hostspec:   pgsql
      port:       5432
      encoding:   utf8

Pierwszym krokiem jest zdefiniowanie połączeń do baz danych. Główną nazwę połączenia będzie “propel” a drugą “stat”

Ustawienie pliku propel.ini

propel.database        = pgsql
propel.database.driver = pgsql
propel.database.url    = pgsql:dbname=db1;host=panic user=db1 password=db1

W pliku propel.ini ustawiamy połączenie z główną bazę danych. “propel.database” odpowiada za generowanie kodu SQL dla danych baz, np.: MySQL, PostgreSQL, Oracle. Jeśli chcemy generować SQL dla wybranego typu bazy, to musimy zmienić na odpowiednią wartość. Można to uzyskać z linii koment ustawiajac –phing-arg

Przykład dla MySQLa:

./symfony propel:build-all --no-confirmation --connection=stat --phing-arg="Dpropel.database=mysql"

Przykład dla Oracle:

./symfony propel:build-all --no-confirmation --connection=stat --phing-arg="Dpropel.database=oracle"

Definiowanie tabel w config/schema.yml

Jak w przykładzie z optymalizacją Propela dobrym nawykiem jest rozdzielenie różnego typu struktur na osobne pliki schema.yml. Główną definicja tabel można zapisać w pliku schema.yml a dodatkową strukturę bazy w osobnym pliku, np w pliku stat_schema.yml.

Plik config/schema.yml

propel:
  users:
    id:              { type: integer, required: true, primaryKey: true, autoincrement: true }
    created_at:      { type: timestamp }
    name:            { type: varchar, size: 255 }
    surname:         { type: varchar, size: 255 }

Plik config/stat_schema.yml

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Diabl0, dodany: 20.05.2009 14:59, tagi: sql, zend_framework

Czasami przy próbach zapisu danych do tabeli z referencjami wyskakuje wyjątek o niewiele mówiącej treści: “Cannot refresh row as parent is missing“. Ustalenie faktycznej przyczyny jest już trochę cięższe, ale da się to zrobić stosując lekką sztuczkę.

Sam wyjątek wygląda lakonicznie i nie dostarcza ciekawych danych:

Fatal error: Uncaught exception 'Zend_Db_Table_Row_Exception' with
message 'Cannot refresh row as parent is missing' in
E:\HTDOCS\recepcja\library\Zend\Db\Table\Row\Abstract.php:695
Stack trace:
#0 E:\HTDOCS\recepcja\library\Zend\Db\Table\Row\Abstract.php(429): Zend_Db_Table_Row_Abstract->_refresh()
#1 E:\HTDOCS\recepcja\library\Zend\Db\Table\Row\Abstract.php(372): Zend_Db_Table_Row_Abstract->_doInsert()
#2 E:\HTDOCS\recepcja\application\messages\controllers\IndexController.php(60): Zend_Db_Table_Row_Abstract->save()
#3 E:\HTDOCS\recepcja\library\Zend\Controller\Action.php(502): Messages_IndexController->addAction()
#4 E:\HTDOCS\recepcja\library\Zend\Controller\Dispatcher\Standard.php(293): Zend_Controller_Action->dispatch('addAction')
#5
E:\HTDOCS\recepcja\library\Zend\Controller\Front.php(914):
Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http),
Object(Zend_Controller_Response_Http))
#6 E:\HTDOCS\recepcja\public_html\index.php(153): Zend_Controller_Front->dispatch()
#7 {main} thrown in E:\HTDOCS\recepcja\library\Zend\Db\Table\Row\Abstract.php on line 695

Aby ustalić przyczynę musimy zagłębić się w wyrzucany wyjątek i odszukać w Stack trace miejsce w NASZYM kodzie gdzie ten wyjątek się zaczyna. Na powyższym przykładzie jest to #2

#2 E:\HTDOCS\recepcja\application\messages\controllers\IndexController.php(60): Zend_Db_Table_Row_Abstract->save()

Teraz musimy zajrzeć w ten kod i opatulić go własnym try/catch:

try {
     $someRow->save();
} catch ( Exception $e ) {
     echo '<pre>Data:      '; print_r( $someRow ); echo '</pre>';
     echo '<pre>Exception: '; print_r( $e ); echo '</pre>';
     exit();
}

Teraz zobaczymy znacznie więcej informacji:

Data:      Zend_Db_Table_Row Object
(
    [_data:protected] => Array
        (
            [patient_id] => Zend_Db_Statement_Exception Object
                (
                    [message:protected] => SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '34415-1' for key 2
---CUT---

I jak na dłoni widać faktyczną przyczynę wyjątku:  Integrity constraint violation: 1062 Duplicate entry ‘34415-1′ for key 2. A skoro wiemy gdzie jest problem, to możemy też jakoś mu zaradzić.

Autor wpisu: eRIZ, dodany: 17.05.2009 22:06, tagi: internet

W gąszczu matur i różnych inynch spraw, dosłownie cichaczem umknęła mi pewna rocznica. Część Czytelników pewnie wie, że jestem na Blipie. Jak ten czas zleciał… ;) Już ponad rok, jakoś nie czuć tego czasu.

Żałować poświęconego czasu na blipnięcia?

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.