-
Notifications
You must be signed in to change notification settings - Fork 0
Tutorial.Form Generation and Validation III.zh_cn
- 自定义表单验证
Zend自带了一些常用的表单验证类,放在Zend\Validator目录下,但有些情况下,这些验证类并不能满足我们的要求,比如用户名重名的检验,需要与数据库关联。在这种情况下,我们就需要扩展Validator来满足我们的要求。
4.1 配置Filter
同样以用户注册页面为例,我们在Form目录下创建RegisterFilter.php文件,并添加如下代码:
路径:usr/module/member/src/Form/RegisterFilter.php
Code 3.4.1
<?php
namespace Module\Member\Form;
use Zend\InputFilter\InputFilter;
class RegisterFilter extends InputFilter
{
public function __construct()
{
$this->add(array(
'name' => 'username',
'required' => true,
'filters' => array(
array(
'name' => 'StringTrim',
),
),
'validators' => array(
array(
'name' => 'Regex',
'options' => array(
'pattern' => '/^[a-zA-Z0-9][a-zA-Z0-9_]{4,24}$/',
),
),
new \Module\Member\Validator\DuplicateUsername(),
),
));
$this->add(array(
'name' => 'password',
'required' => true,
'filters' => array(
array(
'name' => 'StringTrim',
),
),
));
$this->add(array(
'name' => 'repeat-password',
'required' => true,
'filters' => array(
array(
'name' => 'StringTrim',
),
),
));
}
}
在RegisterFilter里,我们为username表单配置两个验证类,一个为用户名格式的检查,另一个为检查用户名是否重复。用户名格式的检查运用了Zend自带的Validator - Regex类,这是一个可以定义正则表达式的Vlidator,这里我们定义用户名必须为5-25位、以字母和数字开头、且只能包含字母,数字和下划线。
另一个Vlidator就是我们自定义的,我们直接实例化这个对象,并赋值给validators数组。这样程序就会调用DuplicateUsername类里的isValid()方法来验证用户名是否重复。从类的路径也可以看出,DuplicateUsername类定义在member/src/Validator目录下。
4.2 自定义Vlidator类
根据RegisterFilter里的配置,我们需要在src目录下创建Validator目录,并添加DuplicateUsername类:
member
|- src
|- Validator
|- DuplicateUsername.php
在DuplicateUsername.php里添加如下代码:
路径:usr/module/member/src/Validator/DuplicateUsername.php
Code 3.4.2
<?php
namespace Module\Member\Validator;
use Zend\Validator\AbstractValidator;
class DuplicateUsername extends AbstractValidator
{
const TAKEN = 'usernameExists';
protected $messageTemplates = array(
self::TAKEN => 'Username already exists',
);
public function isValid($value)
{
$this->setValue($value);
if (null !== $value) {
$username = array('admin', 'test123');
if (in_array($value, $username)) {
$this->error(self::TAKEN);
return false;
}
}
return true;
}
}
DuplicateUsername为验证类,因此它必须继承自AbstractValidator类。在类里,我们定义了一个常量和一个私有的$messageTemplates模板,这个模板存放的就是呈现给用户的错误消息,而常量的值就是这个模板数组里的键值。这种方式的定义保证了修改数组的键值时,只要改变常量的值,而不需要去代码里逐个修改。注意$messageTemplates这个变量的变量名不能更改。
接着我们定义了一个isValid()方法覆盖父类的相同方法。在isValid()方法里,判断用户是否填写的表单,如果填写了就判断这个值是否与已经定义的值重复,若重复,则调用error()方法并将错误消息传递给它,这样在action里调用isValid()时,错误消息就会写入该表单类的相关变量里。若验证没问题,就返回true。
4.3 在Action里完成验证
最后还需要在RegisterController的indexAction里添加表单提交后的处理代码,代码如下:
路径:usr/module/member/src/Controller/Front/RegisterController.php
Code 3.4.3
<?php
...
use Module\Member\Form\RegisterFilter;
class RegisterController extends ActionController
{
...
public function indexAction()
{
$form = $this->renderForm();
if ($this->request->isPost()) {
$post = $this->request->getPost();
$form->setData($post);
$form->setInputFilter(new RegisterFilter);
if (!$form->isValid()) {
$this->view()->assign('form', $form);
return ;
}
$data = $form->getData();
$this->view()->setTemplate('register-success');
$this->view()->assign('info', $data);
return ;
}
$this->view()->assign('form', $form);
$this->view()->assign('title', __('Register member'));
}
}
在代码里引用了RegisterFilter类,验证的代码和之前登陆页面的一致,需要把setInputFilter的参数改为RegisterFilter实例。若验证成功,则取出过滤后的数据,同时设置模板为register-success.phtml,并将过滤后的数据赋给模板的$info变量。其他验证逻辑比如重复密码的判断这里就不作赘述,开发者可以自己去完善。
图3-7 注册页表单验证
最后我们需要创建一个register-success.phtml模板来显示用户注册的信息,在template/front目录下添加register-success.phtml并添加如下代码:
路径:usr/module/member/template/front/register-success.phtml
Code 3.4.4
<h2><?php echo __('User info') ?></h2>
<ul>
<li><?php echo __('Username: ') . $info['username'] ?></li>
<li><?php echo __('Gender: ') . $info['gender'] ?></li>
<li><?php echo __('Country: ') . $info['country'] ?></li>
<li><?php echo __('Contact: ') . ($info['feedback'] ? 'Yes' : 'No') ?></li>
<li><?php echo __('Introduction: ') . $info['introduction'] ?></li>
</ul>
输入用户信息后,点击提交,将会出现下面的页面:
图3-8 注册成功页