Ajax Form Validation in Zend Framework

июля 30, 2007 by admin

Долго искал реализацию Ajax-валидации формы для Zend Framework. В нете очень много статей, но многие оставляют желать лучшего. Единственное очень грамотное решение, имхо, это - fValidator. Но, мне было в лом разбираться в коде, да и расширять его сложно. Поэтому, собрав со всех статей по кусочку идеи (ну и по кусочку кода :) ), решил написать свое решение.

Структура приложения должна быть примерно такая.

Для начала вы должны скачать последние версии библиотек Prototype.JS и Zend Framework.

Итак, серверная часть. index.php

<?php

error_reporting(0);date_default_timezone_set(’Asia/Almaty’);

set_include_path(’.’ . PATH_SEPARATOR . ‘../library/’. PATH_SEPARATOR . get_include_path() );

require_once(’Zend/Loader.php’);require_once(’Zend/View.php’);require_once(’Zend/Registry.php’);require_once(’Zend/Controller/Action/Helper/ViewRenderer.php’);require_once(’Zend/Controller/Action/HelperBroker.php’);require_once(’Zend/Controller/Router/Rewrite.php’);require_once(’Zend/Controller/Front.php’);

$view = new Zend_View(array(’encoding’ => ‘UTF-8′));$view->setScriptPath(’../application/views/’);Zend_Registry::set(’view’, $view);

$options = array(’viewSuffix’ => ‘tpl.php’);

$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view, $options);

Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);

$frontController = Zend_Controller_Front::getInstance();$frontController->setControllerDirectory( array(‘ajaxFormValidate’ => ‘../application/controllers’));$frontController->throwExceptions(true);$frontController->dispatch();

?>

Файлы header.tpl.php

<html><meta http-equiv=”Content-Type” content=”text/html; charset=utf-8;”><link rel=”stylesheet” type=”text/css” media=”screen”href=”<?php echo $this->baseUrl;?>/styles/site.css” />

<head><script type=”text/javascript” src=”/js/prototype.js”></script><script type=”text/javascript” src=”/js/validator.js”></script>

<title><?php echo $this->escape($this->title); ?></title></head><body><div id=”content”>

и footer.tpl.php

</div></body></html>

Скрипт самой формы. _form.php

<script type=”text/javascript”>

window.onload = function() {$(’fname’).focus();}

function submitForm(form) {validator = new Validator(form,”<?=$this->url(array(’controller’ => ‘register’,'action’=>’validate’));?>”);return validator.validate();}</script>

<div id=”errorDiv”style=”display: none;”></div>

<fieldset><legend>Signup Form</legend><formaction=”<?=$this->url(array(’controller’ => ‘register’,'action’=>’success’));?>”name=”registerForm” id=”registerForm” method=”POST”onSubmit=”return submitForm(this);”><table style=”width:100%;”><tr><td><label for=”fname”><b>First Name:</b></label></td><td><?=$this->formText(’fname’,null,array(’size’=>30,’id’=>’fname’));?></td></tr><tr><td><label for=”lname”><b>Last Name:</b></label></td><td><?=$this->formText(’lname’,null,array(’size’=>30));?></td></tr><tr><td><label for=”email”><b>Email Address:</b></label></td><td><?=$this->formText(’email’,null,array(’size’=>30));?></td></tr><tr><td><label for=”password”><b>Password:</b></label></td><td><?=$this->formPassword(’password’,null,array(’size’=>30));?></td></tr><tr><td align=”right”><?=$this->formSubmit(’signup’,'Sign Up’);?></td><td colspan=”2″ align=”right”> </td></tr></table></form></fieldset>

В форме на событие onSubmit срабатывает handler, который грузит функцию submitForm().

В свою очередь, функция создает класс нашего валидатора и передает ей указатель на нашу форму и урл для валидации, а затем запускает метод validate().

Ну а теперь сам validator.js

var Validator = Class.create();

Validator.prototype = {form: ”,url: ”,

initialize: function(form,url) {this.form = $(form);this.url = url;},

validate: function() {var params = Form.serialize(this.form);var req = new Ajax.Request(this.url,{method : ‘POST’,parameters : params,onSuccess : this.processForm.bind(this)});return false;},

processForm: function(xhr) {

var errors = eval( ‘(’ + xhr.responseText + ‘)’ );this.errors = errors;if(!errors) {this.form.submit();} else {this.showErrors(errors);}},

showErrors: function(errors) {

var elementList = Form.getElements(’registerForm’);for ( var i=0; i< elementList.length; i++) {if ( $(’err_’+elementList[i].name) != null )Element.remove(’err_’+elementList[i].name);}

for ( var i = 0; i < errors.length; i++ ) {

var el = Element.up(errors[i].field);var err = “<div class=’error’ id=’err_”+errors[i].field+”‘>”+errors[i].value+”</div>”;

el.update(el.innerHTML + err);}}}

Метод validate() создает Ajax-запрос на урл для валидации и получает назад данные (об ошибках). Если респонс пустой, он отправит форму на submit(), в противном случае запускается метод showErrors(), который отображает все ошибки. С отображением ошибок я мучился целый день, так как никогда не работал с DOM. В конце концов, почитав api Prototype.JS у меня получилось с его помощью добавлять информацию об ошибках. Конечно, можно было бы использовать скрытые div-ы, но я счел этот выход не самым лучшим.

Теперь RegisterController.php
Основной скрипт серверной части нашего примера.

<?php

require_once(’Zend/Json.php’);require_once(’Zend/Filter/Alnum.php’);

class RegisterController extends Zend_Controller_Action {

function init() {

$view = Zend_Registry::get(’view’);$view->baseUrl = $this->_request->getBaseUrl();}

public function validateAction() {

$errors = $this->getErrors($_POST);if(count($errors) == 0) $errors = false;//print_r($errors);echo Zend_Json::encode($errors);}

public function successAction() {$view = Zend_Registry::get(’view’);}

function indexAction() {

$view = Zend_Registry::get(’view’);$view->title = ‘Регистрация’;}

protected function getErrors($values) {

$errors = array();if(!preg_match(’/^[a-z]+[a-z 0-9-_]*$/i’,$values[’fname’])) {$errors[] = array(’value’ => ‘First Name is required and may only contain letters, numbers, and spaces’, ‘field’ => ‘fname’);}if(!preg_match(’/^[a-z]+[a-z 0-9-_]*$/i’,$values[’lname’])) {$errors[] = array(’value’ => ‘Last Name is required and may only contain letters, numbers, and spaces’, ‘field’ => ‘lname’);}if(!preg_match(’/^[_a-zA-Z-]+[._a-zA-Z0-9-]+@[a-zA-Z0-9-]+\.[.a-zA-Z0-9]+$/’,$values[’email’])) {$errors[] = array(’value’ => ‘Email is required and must be a valid email address’, ‘field’ => ‘email’);}Zend_Filter_Alnum::__construct();if(!Zend_Filter_Alnum::filter($values[’password’]) || (strlen($values[’password’]) < 6) || (strlen($values[’password’]) > 12)) {$errors[] = array(’value’ => ‘Password must consist of only letters and numbers and must be between 6 and 12 characters’, ‘field’ => ‘password’);}return $errors;}

public function noRouteAction() {

echo “404, yo.  That’s not a valid URL”;}

}?>

Как вы видите, запрос валидатора обрабатывает метод validateAction(). Проверив значения полей и получив ошибки, если такие существуют, он кодирует данные в формат JSON и возвращает их клиенту.

Теперь файлы view-шек.

index.tpl.php

<?php echo $this->render(’header.tpl.php’); ?><h1><?php echo $this->escape($this->title); ?></h1><?php echo $this->render(’register/_form.php’); ?><?php echo $this->render(’footer.tpl.php’); ?>

success.tpl.php

<html><head><title>Success!</title></head><body>

Ok! <a href=”<?=$this->url(array(’controller’ => ‘register’,'action’=>”));?>”>Back</a>

<body></html>

К сожалению, я пока не смог настроить noRender, поэтому тупо создал пустой файл

validate.tpl.php

Файл стилей site.css

body,html {font-size:100%;margin: 0;font-family: Verdana,Arial,Helvetica,sans-serif;color: #000;background-color: #fff;}.error {background-color: rgb(244, 225, 225); border: 1px solid rgb(204, 0, 0);padding: 0.2em; color: rgb(204, 0, 0);}h1 {font-size:1.4em;color: #800000;background-color: transparent;}#content {width: 770px;margin: 0 auto;}label {width: 100px;display: block;float: left;}#formbutton {margin-left: 100px;}a {color: #800000;}

В результате получается примерно вот это:

Ой, забыл!

В папке www .htaccess

RewriteEngine OnRewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

Прошу задавать свои вопросы, если что не понятно. Если есть какие-то дополнения, то я буду рад исправить.

Статьи по теме: Ajax Form Validation Zend Framework

Posted in Без рубрики |

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.