Uwaga, blog przeniesiony

Posty na tym blogu już nie będą się pojawiać. Zapraszam gorąco pod nowy adres: blog.grzegorzpawlik.com



Subskrybuj ten blog...

sobota, 22 marca 2008

"Sprytny" redirect (cakePHP 1.2)

Załóżmy, że mamy mały system bloga (posty + komentarze).
Cake upiekł za nas widoki i metody. No i powiedzmy, że teraz w post/view/[id_posta] chcesz umieścić możliwość dodania komentarza. Oczywiście tworzysz formularz, którego action='/comments/add' i w CommentsController::add() wpisujesz na sztywno (hard-coding) $this->redirect('/posts/view/'.$comment['post_id']).

Wszystko pięknie i ładnie działa, ale powiedzmy teraz chciałbyś w widoku posts/list_all, w którym wyświetlasz skrócone wersje wszystkich postów dać możliwość szybkiego dodania komentarza. No i znów pakujesz do środka formularz z action='/comments/add' i fajnie działa, ale redirect jest do jakiegoś jednego konkretnego posta, a nie listy w której szanowny user kliknął 'submit'. Niby nic złego się nie dzieje, ale szanowny user odczuwa dyskomfort, jest wręcz zagubiony.

Ostatnio wymyśliłem i z powodzeniem zastosowałem mały trik, który ten problem rozwiązuje w sposób uniwersalny i (w miarę) elegancki.
Zazwyczaj, jeśli tworzę formularz do innego kontrolera, to najczęściej wtedy wiem, gdzie po przerobieniu tych danych powinien się odbyć redirect... najczęściej z powrotem. Zatem preparuję parametr action w następujący sposób:

action=<?php echo $html->url('/comments/add') ?>?r=/posts/list_all/"

A w AppController
    function beforeRender(){        if(isset($this->params['url']['r'])){             $this->redirect($this->params['url']['r']);          }     }

Prosta metoda, która zawsze sprawdzi mi czy przekazałem informację o przekierowaniu i w razie czego ustawi odpowiedni adres przekierowania. Nie muszę pamiętać o tym w każdej metodzie, w której jest prawdopodobne, że będę chciał zrobić redirect w różne miejsca. Po prostu implementuję to na początku projektu i cieszę się kolejnymi zaoszczędzonymi minutami :D

Smacznych jajec ;)

środa, 5 marca 2008

Less is better (o web usability słów kilka)

Wpadła mi do rąk książka Stevena Kruga pt. "Nie każ mi myśleć. O życiowym podejściu do funkcjonalności stron internetowych", którą gorąco wam polecam. Można ją "łyknąć" w jeden weekend i wiele się dowiedzieć ciekawego. Jeśli masz jakikolwiek wpływ na wygląd stron, które oprogramowujesz- warto znać konwencje, które sprawią, że Twoja strona będzie wygodniejsza w użyciu dla odwiedzających.

Czy wiedziałeś, że nawet zmiana nazwy "szukaj" (która jest znana użytkownikom) na "Szybkie wyszukiwanie" może mieć wpływ na odbiór (nie pozytywny) Twojej strony? To drobnostka, ale jeśli takich będziesz miał więcej na stronie- użytkownik może nie wrócić do Twojej witryny i wybrać konkurencję, której w internecie nie brakuje.

Oto link do strony autora tej książki http://www.stevekrug.com/

Preload obrazków w cakePHP

Dla tych, dla których DRY nie jest tylko angielskim słowem napisanym z niewiadomych przyczyn wielkimi literami.
Usprawnienie preloadu obrazków w cakePHP może przydać się, gdy chcesz wyświetlić typową galerię: miniaturki + duży obraz zmieniający się po kliknięciu w miniaturkę. Kiedy zaimplementujesz preload obrazków, to znaczy, że jesteś świadomym budowniczym stron internetowych. Wiesz, że możesz wykorzystać przeglądarkę do przyśpieszenia działania Twojej strony, a nie tylko jej biernego wyświetlania. Zatem do dzieła!

Moje podejście obiera się na tzw. elemencie. Element to (wg. manuala CakePHP) "częściowy layout". Czyli cegiełki, z których możesz stworzyć swoje strony.

app/views/elements/image_preload.thtml:
<?php $images_count = count($images); $i = 0;?>  <script type="text/javascript"> //<![CDATA[  var _images = new Array();  <?php $i=0; foreach($images as $image): ?>    _images[<?= $i ?>] = new Image();   _images[<?= $i++ ?>].src = '<?= 'http://'.$_SERVER['SERVER_NAME'].$this->webroot.'img/'.$subdir.$image['filename'] ?>';     <?php endforeach; ?>       //]]> </script>
O co chodzi? Wpisz w google "javascript image preload" to się dowiesz :)
Jak z tego skorzystać? Już śpieszę z wyjaśnieniami:
W pliku Twojego layoutu, na samym końcu (przed </body> ofcoz) dodaj:
 <?php if(isset($images_to_preload) && isset($images_to_preload_subdir)): ?>   <?= $this->renderElement('image_preload', array('images'=>$images_to_preload, 'subdir'=>$images_to_preload_subdir)); ?>  <?php endif; ?>
A w metodzie odpowiedniego kontrolera wygeneruj tablicę z nazwami plików, które chcesz załadować do cache przeglądarki i przekaż do layoutu:
   $this->set('images_to_preload', $content['Photo']);    $this->set('images_to_preload_subdir', 'photos/'); 
U mnie akurat model Photo ma pole filename, więc tak napisałem sobie element. Do tego dodałem możliwość przekazania z kontrolera podkatalogu w którym są obrazki w /app/webroot/img (teraz już nie wiem dlaczego, ale jak to pisałem, na pewno było to uzasadnione ;))

wtorek, 4 marca 2008

webservices cakePHP pogryzły się z serwerem SOAP

W poprzednich postach pokazałem sposób na stworzenie serwera soap we frameworku CakePHP, a ten po pewnym czasie przestał działać. Okazało się, że włączenie webserwices w /app/config/core.php spowodował problem. Otóż po tej operacji link_do_aplikacji/soap nie oznaczał już linku do SoapController::index(), ale do Controller::index().
Po prostu po właczeniu webservices oczekiwał czegoś w stylu:
link_do_aplikacji/soap/stuff, który wywołał by StuffController::index() i wyrenderował widok w /app/views/stuff/soap/index.thtml.
Niby nic, a może życie uprzykrzyć.

Uwaga! blog przeniesiony

Posty na tym blogu już nie będą się pojawiać. Zapraszam gorąco pod nowy adres: blog.grzegorzpawlik.com
Komentowanie artykułów możliwe jest pod nowym adresem.