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
- Pobieramy moduł z Google Code bądź też z SVN Kohany
- Wrzucamy go do katalogu modules
- 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:
- ręczne stworzenie formularza oraz obsługa błędów
- walidacja danych
- 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:
- Dokumentacja modułu Formation
- Dokumentacja modułu ModelToForm
- Aktualny kod
Tagi: formation, formularze, Kohana, modeltoform
Kategoria: Kohana, Tutorial
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 …
he he :-) co do selectow / uploadu etc będzie :-) zapewne w kolejnej notce jak będzie dodawanie fotek :)
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
}
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 );
poprawione, thx :-)
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 :)
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
as_array – zwraca wartości pól formularza jako tablicę
populate – ustawia wartości pól w modelu na podstawie przekazanej tablicy