Occupy Wall Street #occupywallstreet - protesty w New York City

Od 17 września, czyli kliku ładnych dni na ulicach Nowego Jorku mają miejsce zakrojone na sporą skalę protesty. Od wczoraj obserwuję relację na żywo (poniżej wpisu znajduje się player do oglądania "na miejscu"). Ludzi jest sporo, chodzą po ulicach, głównie na dolnym Manhatanie w okolicach Wall Street, czyli umownie finansowej stolicy świata.

Jak to bywa w protestach ostatnich miesięcy na świecie, hasła wolności gospodarczej mieszają się z hasłami o wyższej płacy i równości. Ale głównym przesłaniem protestów jest sprzeciwienie się polityki rządu/prezydenta Stanów Zjednoczonych głównie w sprawie (do)finansowania korporacji kosztem ludzi (jakby ktoś nie wiedział dlaczego kosztem ludzi, odsyłam: podatek inflacyjny i dług publiczny, który spłacają w końcowym efekcie obywatele).

Najbardziej uderza mnie to, że w tak wielkim mieście odbywa się tak duży protest w tak istotnych sprawach, a media milczą. O zamieszkach w Europie też dużo się nie mówiło, więc to w sumie taki trend, ale dla mnie przerażający.

A z ciekawostek ogranizacyjnych - często zamiast megafonów jedna osoba mówi po kilka wyrazów, a każdy kto słyszy krzyczy na całe gardło to samo, żeby jak najdalej się niosło. Niesamowite.

Watch live streaming video from globalrevolution at livestream.com
wykop.pl facebook.com twitter.com

Nowe profile facebooka (Timeline) na moim przykładzie

Mam możliwość podejrzeć swój profil Facebooka w nowym stylu, który był ogłoszony w czwartek na f8. Nazwa nowego profilu to Timeline (moje tłumaczenie - Linia czasu, zobaczymy jakie będzie oficjalne po polsku). Nazwa dobrze oddaje rolę spełnianą przez profil - pokazane są na osi wszystkie zdarzenia użytkownika z wybranego miesiąca (domyślnie oczywiście bieżącego). Na końcu jest nawet podsumowanie ile było stron i osób dodanych do znajomych (like, to też dodanie do znajomych). Po kliknięciu dostępny jest pełny zrzut ekranu z profilu.

Nowy Timeline Facebook na moim profilu

W tej chwili nowy profil jest w trybie podglądu developerskiego, czyli nawet na moim profilu mogą obejrzeć to tylko developerzy. Opt-in i oglądanie dla wszystkich będzie z tego co wiem 1 października. Dużo jeszcze przede mną do przeklikania na tym profilu, za co za chwilę się biorę. Jeśli ktoś chce wiedzieć więcej o tym, jak działa któraś funkcja - zapraszam do komentarzy. Kliknę i postaram się opisać. :)

wykop.pl facebook.com twitter.com

Modele i formularze Zend Framework - automatyzacja zapisu

Edycja artykułu w serwisie wołomiński.netNa codzień pracuję w Zend Framework. Praca jest bardzo przyjemna, framework jest fajnie napisany, obiektowo, elastycznie (wiele klas można rozszerzyć, jest wiele miejsc, w których domyślne klasy są gotowe do uruchomienia naszego kodu, itp.). Ale ma też wiele wad i braków, które często są rozwiązane w innych frameworkach. Twórcy ZF wiedzą o wielu z nich i obiecują, że szykowana wersja 2.0 będzie lepiej przemyślana i napisana. Ale póki nie mamy wersji 2.0 (a nawet jak będzie, nie wiadomo, czy wszystkie problemy zostaną weliminowane) trzeba sobie jakoś radzić. Jednym z problemów, które spotykam w niemal każdym projekcie, jest mechanizm zapisywania danych wysłanych przez użytkownika.

Generalnie zapisywanie informacji w większości przypadków wygląda bardzo podobnie: po wejściu na stronę użytkownik otrzymuje formularz, który wypełnia i zatwierdza; jeśli dane przesłasne są poprawne są zapisywane do bazy (tworzony jest nowy obiekt lub aktualizowany istniejący); jesli niepoprawne - użytkownik otrzymuje ten sam formularz z wpisanymi już wcześniej danymi i komunikatami o błędnych danych. Bardzo często powtarzający się schemat. Czemu więc nie ułatwić sobie życia?

Co jest potrzebne? Formularz, widok, kontroler i model.

Formularz powinien zapewniać (poza wyświetlaniem formularza) pełną walidację i filtrowanie danych. Np. edycja danych kotantaktowych, która zawiera między innymi email i telefon powinna sprawdzać oba pola. Do emaila jest klasa w Zendzie, numer telefonu może być np. wyrażeniami regularnymi. Pola obowiązkowe, listy (np. państw czy województw) itp. - to wszystko sprawa formularza i wiele narzędzi przydatnych w tym temacie jest już w Zendzie. Klasę formularza do kontrolera można tworzyć osobno albo korzystać z plików konfiguracyjnych (ini, xml) na podstawie których Zend potrafi taki formularz przygotować (niżej opisany kontroler korzysta z pierwszego sposobu).

Widok - tu wystarczy

<?php echo $this->form; ?>

jeśli pod form przypisany jest obiekt klasy Zend_Form. To co przed i po formularzu można dopisać. Za wyświetlanie/renderowanie formularza powinnien odpowiadać obiekt i jego dekoratory. W ostateczności można uciec się do dekoratora ViewScript, ale nadal w widoku akcji kodu formularza nie ma.

Jeżeli w całej aplikacji będziemy stosowali podobne nazewnictwo akcji i parametrów, to każdy kontroler może dziedziczyć wszystko po jednym - wspólnym. Ja polecam napisanie takiego kontrolera abstrakcyjnego, który będzie działał z domyślnymi akcjami create i update, a w kluczowych miejscach będzie wykonywał opcjonalne metody, które w konkretnych kontrolerach można rozszerzać: (1) przed edycją, (2) po edycji z sukcesem, (3) po edycji z błędami.

Przykład kontrolera:

<?php
 
abstract class Application_Controller_Action extends Zend_Controller_Action
{
    /**
     * @var string
     */
    protected $_suffixNameByController;
 
    /**
     * @return string 
     */
    protected function _getSuffixNameByController()
    {
        if(null === $this->_suffixNameByController) {
          $controllerName = $this->getRequest()->getControllerName();
          $filter = new Zend_Filter_Word_UnderscoreToCamelCase();
          $this->_suffixNameByController = $filter->filter($controllerName);
        }
        return $this->_suffixNameByController;
    }
 
    /**
     * @param array $nameParts 
     * @return string 
     */
    protected function _getPrefixedNameByController($nameParts)
    {
        $nameParts = (array)$nameParts;
        $nameParts[] = $this->_getSuffixNameByController();
        return implode('_', $nameParts);
    }
 
    /**
     * @return string 
     */
    protected function _getDbTableNameByController()
    {
        return $this->_getPrefixedNameByController(array('Application', 'Model', 'DbTable'));
    }
 
    /**
     * @return Application_Model_DbTable
     */
    protected function _getDbTableByController()
    {
        $dbTableClass = $this->_getDbTableNameByController();
        return new $dbTableClass;
    }
 
    /**
     * @return string 
     */
    protected function _getFormNameByController()
    {
        return $this->_getPrefixedNameByController(array('Application', 'Form'));
    }
 
    /**
     * @return Zend_Form 
     */
    protected function _getFormByController()
    {
        $formClass = $this->_getFormNameByController();
        return new $formClass;
    }
 
    /**
     * @param $row Application_Model 
     * @return void 
     */
    protected function _afterSave($row = null)
    {
        if(null === $row) {
            $url = $this->view->url(array(
                'action' => 'index',
                'id' => null
            ));
        }
        else {
            $url = $this->view->url(array(
                'action' => 'read',
                'id' => $row->getId()
            ));
        }
        $this->_redirect($url, array('code' => 303));
    }
 
    /**
     * @return Application_Model 
     */
    protected function _loadObjectFromId()
    {
        $id = (int)$this->_getParam('id');
        if($id < 1)
            throw new Zend_Exception('No valid ID found');
        $table = $this->_getDbTableByController();
        return $table->find($id)->current();
    }
 
    /**
     * @return void 
     */
    public function createAction()
    {
        $form = $this->_getFormByController();
 
        if($this->getRequest()->isPost()) {
            if($form->isValid($this->getRequest()->getPost())) {
                $dbTable = $this->_getDbTableByController();
                $row = $dbTable->createRow();
                $row->setFromArray($form->getValues());
                $row->save();
                $this->_afterSave($row);
            }
        }
 
        $this->view->assign(array(
            'form' => $form
        ));
    }
 
    /**
     * @return void 
     */
    public function updateAction()
    {
        $row = $this->_loadObjectFromId();
 
        $form = $this->_getFormByController();
 
        if($this->getRequest()->isPost())
        {
            if($form->isValid($this->getRequest()->getPost())) {
                $row->setFromArray($form->getValues());
                $row->save();
                $this->_afterSave($row);
            }
        } else {
            $form->populate($row->toValues());
        }
 
        $this->view->assign(array(
            'row' => $row,
            'form' => $form
        ));
    }
}

Klasa "zgaduje" nazwę formularza i modelu tabeli na podstawie nazwy kontrolera w zapytaniu, więc używając standardowych nazw i operacji, akcje create i update można w końcowych kontrolerach pominąć. Służą do tego pierwsze metody w klasie. Są rozbite na mniejsze, ale zawsze uważam, że dobrze być przygotowanym - sama nazwa klasy formularza może też być potrzebna.

Przy edycji obiektu, ID należy przekazać w parametrze id, np. http://www.example.com/article/update/id/563.

Na koniec zostaje jeszcze model.Powyższy kontroler wykorzystuje standardowe metody ZF - createRow() i setFromArray(array()). W klasie wiersza można nadpisać metodę setFromArray() gdyby np. było potrzeba zapisać dane z innych tabel (połączenie z inną tabelą, itp.) - rzeczy, które wyświetla i sprawdza formularz, a kontroler nie musi nie powinien się już tym zajmować.

Co po zapisaniu danych? Uruchamiana jest metoda _afterSave(), która domyślnie przekierowuje do akcji read z ID ustawionym na ID zapisanego właśnie wiersza (wymaga w nim metody (getId()), ale jest przygotowana na bycie nadpisaną i wykonanie cokolwiek będzie potrzebne w danym projekcie/kontrolerze.

Jak tego użyć? Jeżeli będziemy trzymali się w projekcie kilku zasad (dziedziczenie odpowiednich elementów po odpowiednich klasach) w naszym kontrolerze do edycji danego elementu (typu PostsController, UsersController, BooksController) możemy całkiem pominąć akcje create i update używając generycznych. W razie potrzeby poprawki - zmiany dokonujemy w jednym miejscu. Magia programowania obiektowego. Miłego używania!

wykop.pl facebook.com twitter.com

dekoderek-jogg