Autor wpisu: Damian Tylczyński, dodany: 09.06.2009 03:36, tagi: php, php6
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
Jakiś 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
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?