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
Прошу задавать свои вопросы, если что не понятно. Если есть какие-то дополнения, то я буду рад исправить.
Posted in Без рубрики |