Aplikacje internetowe

Bełdziowe spojrzenie na aplikacje internetowe

Praca z formularzami

Wraz z wersją 2.2 Kohany zniknął moduł Forge ułatwiający pracę z formularzami (generowanie / walidacja). Niestety na jego miejsce nie pojawiło się nic co mogłoby go zastąpić. Powstałą lukę bardzo sprawnie możemy załatać przy pomocy nieoficjalnego modułu o nazwie Formation, którego autorem jest twórca bloga Learning Kohana. Dobra wiadomość jest taka, że aktualnie ów moduł znajduje się na SVN’ie Kohany, tak więc można się spodziewać, że w przyszłych wersjach będzie on domyślnie dołączany do frameworka.

Instalacja

  1. Pobieramy moduł z Google Code bądź też z SVN Kohany
  2. Wrzucamy go do katalogu modules
  3. Dodajemy obsługę modułu w pliki konfiguracyjnym – tak samo jak w poprzedniej części aktywowaliśmy moduł Auth

Poprawka

Przed rozpoczęciem pracy z modułem musimy poprawić w nim pewne pozostałości po Kohanie 2.1. Mianowicie w pliku Validation.php oraz Formation.php musimy zamienić Log::add na Kohana::log oraz Config::item na Kohana::config (błąd może występować także w innych plikach tak więc najlepiej wykonać te zamiany w obrębie całego katalogu modułu).

PS. Zalecam korzystanie z modułu dołączonego na końcu notki. Wersja dostępna na stronie nie jest w pełni zgodna z wersją 2.2 Kohany i generuje wiele brzydkich słów z ust osoby, która z nią pracuje :-)

Walidacja

Niestety Formation wykorzystuje własną klasę walidacji danych, której składnia różni się od tej wbudowanej w Kohane, przez co musimy zapoznać się z nowymi metodami. Poniżej znajduje się przerobiony kod odpowiedzialny za walidacje formularza rejestracyjnego.

$post = new Validation( $_POST );
$post -> add_pre_filter( 'trim' )
      -> add_pre_filter( 'htmlentities' );
$post[ 'username' ] -> add_rule( 'Rule_Required' )
                    -> add_rule( 'Rule_Length', array( 3, 32 ) )
                    -> add_callback( array( $this, '_unique_username' ) );
$post[ 'password' ] -> add_rule( 'Rule_Required' )
                    -> add_rule( 'Rule_Min_Length', 6 );
$post[ 'password2' ] -> add_rule( 'Rule_Matches', $post[ 'password' ] );
$post[ 'email' ] -> add_rule( 'Rule_Required' )
                 -> add_rule( 'Rule_Email' );

Dodatkowo musimy przerobić funkcje sprawdzającą czy podany login jest wolny.

public function _unique_username( $field )
{
   if( ORM :: factory( 'user' ) -> username_exists( (string)$field ) )
      $field -> add_error( 'Callback', 'user_exists' );
}

Przerobienie aktualnych formularzy

Poprzednio obsługa formularzy przebiegała w trzech krokach:

  1. ręczne stworzenie formularza oraz obsługa błędów
  2. walidacja danych
  3. zapis danych

Moduł Formation bierze na swoje barki punkt 1. dzięki czemu możemy skupić się na ważniejszych rzeczach niż HTML :-) Weźmy się za przerobienie formularzy z poprzedniej notki.

Poniżej kod przerobionego formularza rejestracyjnego.

$form = new Formation;
$form -> legend = '';
$form -> set_language_file( 'pl_PL' );

$form -> add_element( 'input', 'username' ) -> set_screen_name( 'Login: ' )
                                            -> add_rule( 'Rule_Required' )
                                            -> add_rule( 'Rule_Length', array( 3, 32 ) )
                                            -> add_callback( array( $this, '_unique_username' ) );
$form -> add_element( 'password', 'password' )  -> set_screen_name( 'Hasło: ' )
                                                -> add_rule( 'Rule_Required' )
                                                -> add_rule( 'Rule_Min_Length', 6 );
$form -> add_element( 'password', 'password2' ) -> set_screen_name( 'Powtórz hasło: ' )
                                                -> add_rule( 'Rule_Matches', $form[ 'password' ] );
$form -> add_element( 'email', 'email' ) -> set_screen_name( 'Adres e-mail: ' )
                                         -> add_rule( 'Rule_Required' );
$form -> add_element( 'submit', 'Rejestruj' );

$form -> add_pre_filter( 'trim' );
$form -> add_pre_filter( 'htmlentities' );

Jak widać powyższy listing ma wiele wspólnych cech z listingiem walidującym dane, a to dlatego, że klasa Formation rozszerza klasę Validation.

ModelToForm

Moduł Formation zawiera w sobie jeszcze jedną ciekawą klasę – ModelToForm. Dzięki niej możemy prawie całkowicie zapomnieć o obsłudze formularzy.

Po pierwsze musimy przenieść reguły walidacji do modelu (na pierwszy rzut oka – na drugi też :) – może to wyglądać skomplikowanie).

<?

class User_Model extends Auth_User_Model
{
    protected $validate = array( 'username' => array( 'rules' => array( 'Rule_Required',
                                                                         array( 'Rule_Length', array( 3, 32 ) ) ),
                                                      'callbacks' => array( array( User_Model, '_unique_username' ) ) ),
                                 'password' => array( 'rules' => array( 'Rule_Required',
                                                                        array( 'Rule_Min_Length', 6 ) ),
                                                      'type' => 'password'),
                                 'email'     => array(  'rules' => array( 'Rule_Required' ),
                                                        'type' => 'email' ) );

    public function _unique_username( $field )
    {
        if( ORM :: factory( 'user' ) -> username_exists( (string)$field ) )
            $field -> add_error( 'Callback', Kohana :: lang( 'validation.user_exists' ) );
    }
} 

?>

Zmienna $validate zawiera wszelkie reguły walidacji, które stworzyliśmy wcześniej. Następnie musimy stworzyć nowy plik – application/libraries/Register_Form.php – będzie on zawierał wszystkie informacje jakie potrzebne są do wygenerowania formularza.

<?php
    class Register_Form_Core extends Model_Formation
    {
        protected $exclude=array( 'id','logins', 'last_login' );
        protected $form_fields=array();
        protected $_model='User_Model';

        public function __construct( $model=false,$build=true )
        {
            parent :: __construct( $model, $build );

            $this -> legend = '';

            $this -> add_element( 'password', 'password2' )  -> set_screen_name( 'Powtórz hasło: ' )
                                                             -> add_rule( 'Rule_Matches', $this[ 'password' ] )
                                                             -> set_order( 3 );;

            $this -> add_element( 'submit', 'Rejestruj' );

            $this[ 'username' ] -> set_screen_name( 'Login:' )
                                -> set_order( 1 );
            $this[ 'password' ] -> set_screen_name( 'Hasło:' )
                                -> set_order( 2 );
            $this[ 'email' ]    -> set_screen_name( 'Adres e-mail:' )
                                -> set_order( 4 );

            $this -> add_pre_filter( 'trim' );
            $this -> add_pre_filter( 'htmlentities' );
        }
    }
?>

Jak widać większość kodu jest kopią z poprzedniego punktu. Poniżej objaśnienie zmiennych klasy:

  • exclude – nazwy kolumn, które mają się nie pojawiać w formularzu
  • form_fields – przeciwieństwo powyższej zmiennej – lista kolumn, które mają być zawarte w formularzu
  • _model – nazwa modelu, z którym ma współpracować formularza
  • dodatkowo możemy umieścić zmienną disabled – kolumny w jej zawarte będą się wyświetlały lecz nie będzie możliwa ich edycja.

Ostatnia zmiana odnosi się do pliku application/controllers/register.php, w którym musimy wygenerować formularz.

$form = new Register_Form;

if( $form -> save( ) )
{
   if( $form -> model( ) -> add( ORM :: factory( 'role', 'login' ) ) )
      $msg = Kohana :: lang( 'register.successful' );
   else
      $msg = Kohana :: lang( 'register.error' );

   Session :: instance( ) -> set_flash( 'flash', $msg );
   url :: redirect( '/' );
}

Dodatkowo możemy usunąć plik application\libraries\MY_ORM.php, ponieważ kod w nim zawarty dołączony jest do modułu Formation.

Zobacz także:


Tagi: , , ,
Kategoria: Kohana, Tutorial


8 komentarzy

  1. No Bełdziu, a podziękowania gdzie? :P Kto Ci po nocy siedział i próbował uruchomić, co? :P
    a poza tym great job, podoba mi się :D opisz jeszcze czy i jak obsługiwać dodatkowe pola w stylu select dla wybierania danych z innej tabeli, uploadowanie plikow itp i bedzie super :) co nie zmienia faktu ze to i tak ladnie ulatwia formularze, ktorych za nic recznie by mi sie nie chcialo …

  2. he he :-) co do selectow / uploadu etc będzie :-) zapewne w kolejnej notce jak będzie dodawanie fotek :)

  3. Pięknie, tylko informacyjnie – jeśli chcesz dać możliwość edycji danego rekordu z bazy, to konstruktor formularza musi wyglądać następująco:

    public function __construct( $model=false,$build=true )
    {
    parent :: __construct( $model, $build );
    // ustalanie nazw pol itp
    }

  4. a jeszcze zapomniałbym, żeby edycja działała trzebaby podać id rekordu, trzymać ją w polu hidden … w powyższym kodzie na __construct dopisać należy

    if ($model)
    $this -> add_element( ‚hidden’, ‚id’ ) -> load_value ( $model -> id );

  5. poprawione, thx :-)

  6. Przy pracy z ModelToForm nad formularzami do edycji danych (choćby rekordów) stwierdziłem że przydałaby się możliwość ukrywania pewnych pól w formularzu (ukrywania! nie „usuwania” ich z formularza) – np takich jak id rekordu (choć w moim przypadku było ich sporo więcej) – więc stworzyłem dwulinijkową modyfikację do ModelToForm

    plik modules/formation/libraries/Model_Formation.php

    1. linia 13 ” protected $disabled=array(); ”

    ponizej dopisujemy :

    protected $hidden = array();

    2. linie 120 – 123:
    if(isset($property[‚format’])&&$property[‚format’]==’0000-00-00 00:00:00′)
    {
    $type=’input’;
    }

    ponizej dopisujemy

    if (in_array($name, $this->hidden)) $type = ‚hidden’;

    teraz wystarczy w wlasnym formularzu dopisac protected $hidden = (‚id’) i tak oto mamy ukryte pole id :)

  7. cooltang napisał(a):

    Twoja klasa ‚Model_Formation’ dziedziczy po ‚Model_Formation_Core’. Masz u siebie funkcje ‚save’, ktora ,jeżeli sie nie myle usuwa pola wylączone. Co robi funkcja ‚as_array()’ i ‚populate()’ ?

    Pozdrawiam

  8. as_array – zwraca wartości pól formularza jako tablicę
    populate – ustawia wartości pól w modelu na podstawie przekazanej tablicy

Dodaj komentarz