Skip to content

Tutorial.Form Generation and Validation III.zh_cn

Lin Liu edited this page Jul 24, 2013 · 2 revisions

English

  1. 自定义表单验证

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变量。其他验证逻辑比如重复密码的判断这里就不作赘述,开发者可以自己去完善。

fig3-7 1 fig3-7 2

图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>

输入用户信息后,点击提交,将会出现下面的页面:

fig3-8

图3-8 注册成功页

Clone this wiki locally