Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

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?

Autor wpisu: SongoQ, dodany: 05.05.2009 14:00, tagi: php

Aktualizując ostanio serwer miałem problem z upgrade na nowszą wersje PostgreSQLa więc opiszę swoje rozwiązanie na blogu.

Jeśli mamy już zainstalowaną wcześniejszą wersje PostgreSQLa to robimy backup.

pg_dumpall > postgres-backup.dump

Następnie wrzucamy do /etc/portage/package.keywords wpisy w celu odblokowania wersji niestabilnych.

echo "dev-db/postgresql-base ~amd64" >> /etc/portage/package.keywords
echo "dev-db/postgresql-server ~amd64" >> /etc/portage/package.keywords
echo "virtual/postgresql-server ~amd64" >> /etc/portage/package.keywords
echo "virtual/postgresql-base ~amd64" >> /etc/portage/package.keywords
echo "app-admin/eselect-postgresql ~amd64" >> /etc/portage/package.keywords

Kolejnym etapem jest usunięcie dev-db/postgresql dev-db/libpq

emerge --unmerge dev-db/postgresql dev-db/libpq

I możemy instalować nową wersję PostgreSQLa

emerge virtual/postgresql-base virtual/postgresql-server
emerge --config =dev-db/postgresql-server-8.3.5

Zostaje tylko wystartowanie bazy i dopisanie do skryptów startowych.

/etc/init.d/postgresql-8.3 start
rc-update add postgresql-8.3 default

Jeśli z jakiś przyczyn php wyrzuca, że nie chce działać to musimy przekompilować.

Related Posts

Autor wpisu: WojciechNaruniec, dodany: 01.05.2009 17:22, tagi: php, zend_framework

Wczoraj w serwisie Zend Developer Zone ukazała się informacja, że dostępny jest już Zend Framework 1.8.0. Tę wersję można nazwać przełomową - w końcu pojawiły się narzędzia wspomagające szybkie tworzenie aplikacji (RAD). Teraz wywołaniem jednej komendy można utworzyć praktycznie całą strukturę projektu.
Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.