Jeszcze lepsza walidacja formularzy
Kilka miesięcy temu podjąłem się napisania mechanizmu tworzącego walidację JavaScript formularzy na podstawie tablicy walidacji tworzonej w modelu. Efekty opisałem w artykule “Automatyczna walidacja JavaScript w CakePHP“. Mechanizm ten wykorzystałem w kilku projektach i znakomicie się sprawdził. Przez ten czas Cake ewoluował do wersji 1.2.1 co przez co musiałem przygotować kolejną przeróbkę hepera form. Postanowiłem też przepisać kod JavaScript oraz nieco ulepszyć cały mechanizm.
Na początku wprowadziłem zmiany w mechanizmie walidacji Cake’a. W niektórych formularzach istniała potrzeba sprawdzenia np. kodu pocztowego, ale był on opcjonalny. Zmieniłem mechanizm walidacji tak, by sprawdzał pola jedynie gdy zostały wypełnione. W ten sposób można nadać polu np. maksymalną i minimalną długość, wymusić wpisywanie samych liczb i jednocześnie pole może być opcjonalne. Można to wykorzystać np. przy wpisywaniu numeru telefonu. Jeżeli pole maspełniać wszystkie powyższe reguły i być wymagane wystarczy dodać metodę required.
Dodałem także kilka nowych reguł:
- uniqueLogin – sprawdzenie czy jest unikalnym loginem
- uniqueEmail – podobnie jak wyżej
- confirmPassword – wymagane potwierdzenie hasła
- tags – takgi składające się z liter oddzielone przecinkami
- datatime – data i czas
- int – tylko liczby
- float – liczba zmiennoprzecinkowa
- postal – kodpocztowy
- phone – telefon 11to cyfrowy
Pierwsze dwie metody działają nieco inaczej od pozostałych, ale opiszę to później.
Przykład użycia w modelu:
class User extends AppModel {
var $name = 'User';
var $displayField = 'login';
var $validate = array(
'login' => array
(
'required' => array(
'rule' => array('required'),
'on'=>'create'
),
'between' => array(
'rule' => array('between', 6, 16),
'on'=>'create'
),
'login' => array(
'rule' => array('login'),
'on'=>'create'
),
'uniqueLogin' => array(
'rule' => array('uniqueLogin'),
'on'=>'create'
),
),
'email' => array
(
'required' => array(
'rule' => array('required'),
'on'=>'create'
),
'email' => array(
'rule' => array('email'),
'on'=>'create'
),
'uniqueEmail' => array(
'rule' => array('uniqueEmail'),
'on'=>'create'
),
),
'password' => array
(
'required' => array(
'rule' => array('required'),
'on'=>'create'
),
'minLength' => array(
'rule' => array('minLength', 6),
),
),
'confirm_password' => array
(
'required' => array(
'rule' => array('required'),
'on'=>'create'
),
'minLength' => array(
'rule' => array('minLength', 6),
),
'confirmPassword' => array(
'rule' => array('confirmPassword'),
),
),
);
}
Następnie wprowadziłem wprowadziłem zmiany w helperze form. Podobnie jak poprzednia wersja, w metodzie end dodaje on kod JavaScript dodający do formularza metody jego walidacji. Istotną zmianą jest to, że bierze on pod uwagę atrybut “on” danej metody walidacji. atrybut ten został niedawno wprowadzony i może przyjmować wartości create lub update. Więcej o tym można przeczytać w dokumentacji: http://book.cakephp.org/view/127/One-Rule-Per-Field. Tak więc helper form bierze pod uwagę czy dana metoda ma być brana pod uwagę w danym formularzu.
Największe zmiany wprowadziłem w JavaScripcie. Do jego użycia wymagane jest dołączenie biblioteki MooTools lub jQuery. Skrypt zawiera obiekt Validation. Metoda add dodaje reguły do poszczególnych pól. Wyświetlaniem i ukrywaniem komunikatów zajmują się metody showMessage i hideMessage. Można je prosto zmodyfikować by wyświetlać komunikaty w inny sposób, np. z efektem slideOut.
Opisując ten obiekt wrócę do metod walidacji uniqueLogin i uniquEmail. W tracie wypełniania formularza sprawdzają one czy w bazie danych już jest użytkownik o podanym loginie czy adresie email. Odbywa się to za pomocą AJAX’a. Do tego wymagane są metody w kontrolerze. Wygląda ją one następująco:
function check_login($data)
{
$this->layout='ajax';
if ($this->User->findByLogin($data))
$this->set('response', 'err');
else
$this->set('response', 'ok');
}
function check_email($data)
{
$this->layout='ajax';
if ($this->User->findByEmail($data))
$this->set('response', 'err');
else
$this->set('response', 'ok');
}
Sprawdzają jedynie czy w bazie istnieją już podane wpisy i zwracają OK lub ERR.
Obiekt walidacji został wzbogacony również o możliwość sprawdzania nie tylko inputów typu text czy textarea ale również pozostałych typów oraz selectów. Potrafi także sprawdzić pole daty składające się z 3 lub 5ciu selectów oraz grupę radio buttonów.
Kody źródłowe można pobrać stąd:
http://www.reboo.pl/files/download/validation-v2.zip wersja wykorzystująca MooTools
http://www.reboo.pl/files/download/validation-v2j.zip wersja wykorzystująca jQuery
a demo można zobaczyć pod adresem:
http://www.reboo.pl/files/demos/cake/www/users/add
Proponuję jako login wpisać np. reboo13, ponieważ taki już istnieje.
czwartek, 26 Luty 2009

Facebook
GoldenLine
LinkedIn
czwartek, 21. Maj 2009
Fajnie działa ta walidacja. Ale jest jeden denerwujący bug. Jeśli na stronie pojawią się dwa formularze to walidacja ich nie odróżnia.
Np.
1) Strona z logowaniem i belka logowania. Klikamy submit na stronie a sprawdza nam dane z belki.
2) Teraz też obserwuje problem z modalboxem, jeśli mam okienko z logowaniem w modalboxie, a pod spodem jest strona z rejestracją. To po klinięciu w submit z modalboxa, wyświetla błędy i w modalboxie i na stronie tej pod spodem z rejestracją.
niedziela, 24. Maj 2009
Wiem, że niestety tak to działa, bo nie miałem też takiej potrzeby, żeby umieszczać i sprawdzać kilka formularzy na stronie. Jeśli jest na niej formularz logowania, używam do niego prostego skryptu, który tylko sprawdza tylko, czy oba pola są wypełnione.
Postaram się to uwzględnić w następnej wersji.
piątek, 29. Maj 2009
Rozwiązanie problemu kilku formularzy:
validation.js
for (it in Validation.formFields)
{
if (Validation.formFields[it][0])
{
if (Validation.formFields[it][0]["tag"])
{
// efik begin
validationAction = Validation.formFields[it][0]["params"].param1;
commonId = formId.slice(0,-4);
if(validationAction == commonId)
{
// efik end
for(var i=0; i array
(
‘required’ => array( ‘rule’ => array(‘required’) ),
‘between’ => array( ‘rule’ => array(‘between’, 2, 20) ),
‘username’ => array( ‘rule’ => array(‘username’) ),
‘uniqueUsername’ => array( ‘rule’ => array(‘uniqueUsername’) ),
),
‘email’ => array
(
‘required’ => array( ‘rule’ => array(‘required’) ),
‘maxLength’ => array( ‘rule’ => array(‘maxLength’, 60) ),
‘email’ => array( ‘rule’ => array(‘email’) ),
‘uniqueEmail’ => array( ‘rule’ => array(‘uniqueEmail’) ),
),
app_model.php
function setValidateRules($validate_fields = null, $controller = null, $action = null)
{
if($validate_fields)
foreach ($validate_fields as $field)
if (isset($this->validateRules[$field]))
{
$model = substr($controller, 0, strlen($controller) – 1);
$model_action = Inflector::camelize($model . ‘_’ . $action);
$this->validate[$field]['action'] = array( ‘rule’ => array(‘action’, $model_action) );
foreach($this->validateRules[$field] as $k=>$v)
$this->validate[$field][$k] = $this->validateRules[$field][$k];
}
}
app_controller.php
function setValidateRules($validate_fields = null)
{
$this->User->setValidateRules($validate_fields, $this->params['controller'], $this->params['action']);
}
Użycie users_controller.php
function register($referrer = null)
{
// ustawiamy które pola idą do tablicy walidacji
$this->setValidateRules(array(‘username’, ‘email’))