Zend Framework 2表单的自定义验证器

时间:2012-11-20 15:12:37

标签: php validation zend-framework2

我正在尝试制作一个用户注册表单,用于检查密码字段的复杂程度。我根据documentation编写了一个自定义验证器。该文件位于User \ src \ User \ Validator的“用户”模块中。

<?php

namespace User\Validator;

use Zend\Validator\AbstractValidator;

class PasswordStrength extends AbstractValidator {

const LENGTH = 'length';
const UPPER  = 'upper';
const LOWER  = 'lower';
const DIGIT  = 'digit';

protected $messageTemplates = array(
    self::LENGTH => "'%value%' must be at least 6 characters long",
    self::UPPER => "'%value% must contain at least one uppercase letter",
    self::LOWER => "'%value% must contain at least one lowercase letter",
    self::DIGIT => "'%value% must contain at least one digit letter"
);

public function isValid($value) {
    ... validation code ...
}
}

我的问题出现在我的用户注册表单中尝试使用此验证器。我尝试通过在Module.php中配置验证器来将验证器添加到ServiceManager中。

public function getServiceConfig() {
    return array(
        'invokables' => array(
            'PasswordStrengthValidator' => 'User\Validator\PasswordStrength'
        ),
    );
}

然后我将它添加到User.php中的输入过滤器。

public function getInputFilter() {
    if (!$this->inputFilter) {
        $inputFilter = new InputFilter();
        $factory     = new InputFactory();

        $inputFilter->add($factory->createInput(array(
            'name'     => 'username',
            'required' => true,
            'validators' => array(
                array(
                    'name'    => 'StringLength',
                    'options' => array(
                        'encoding' => 'UTF-8',
                        'min'      => 1,
                        'max'      => 100,
                    ),
                ),
            ),
        )));

        $inputFilter->add($factory->createInput(array(
            'name'     => 'password',
            'required' => true,
            'validators' => array(
                array(
                    'name'    => 'PasswordStrengthValidator',
                ),
            ),
        )));

        $this->inputFilter = $inputFilter;
    }

    return $this->inputFilter;
}

但是,当我访问表单并点击提交按钮时,我收到ServiceNotFoundException。

Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for PasswordStrengthValidator

我的ServiceManager配置有问题吗?我甚至不确定这是否是首先使用自定义验证器的合适方式。我发现了很多使用ZF1的例子,但是我发现的ZF2的文档和示例从未超出验证器的编写范围,以解决它与表单等的集成。任何建议都将不胜感激。

5 个答案:

答案 0 :(得分:6)

你可以尝试这种解决方法...... 在Module.php中注册您的验证器,但函数 getValidatorConfig 或在关键'验证器'下的module.config.php中注册。

public function getValidatorConfig() {
  return array(
    'invokables' => array(
        'PasswordStrengthValidator' => 'User\Validator\PasswordStrength'
    ),
  );
}

然后在你的User.php中试试这个: (但您必须有权访问服务定位器,您可以从UserFactory等注入它。)

$validatorManager = $this->getServiceLocator()->get('ValidatorManager');
// here you can test $validatorManager->get('PasswordStrengthValidator');

$validatorChain = new ValidatorChain();
$validatorChain->setPluginManager($validatorManager);

$inputFilter = new InputFilter();   
$inputFilter->getFactory()->setDefaultValidatorChain($validatorChain);

这适合我。

马丁

答案 1 :(得分:4)

您尝试在示例中使用的“短名称”验证程序仅在您首先使用验证程序插件管理器(Zend\Validator\ValidatorPluginManager)注册该短名称/别名时才有效。

对此(以及我的方式)的一种替代方法是在创建表单过滤器对象时注入必要的自定义验证器的实例。这是ZfcUser的方式:

// Service factory definition from Module::getServiceConfig
'zfcuser_register_form' => function ($sm) {
     $options = $sm->get('zfcuser_module_options');
     $form = new Form\Register(null, $options);
     $form->setInputFilter(new Form\RegisterFilter(
         new Validator\NoRecordExists(array(
             'mapper' => $sm->get('zfcuser_user_mapper'),
             'key'    => 'email'
         )),
         new Validator\NoRecordExists(array(
            'mapper' => $sm->get('zfcuser_user_mapper'),
            'key'    => 'username'
         )),
         $options
     ));
     return $form;
},

来源:https://github.com/ZF-Commons/ZfcUser/blob/master/Module.php#L100

这里,两个ZfcUser\Validator\NoRecordExists验证器实例(一个用于电子邮件,一个用于用户名)被注入到注册表单(ZfcUser\Form\RegisterFilter)的输入过滤器对象的构造函数中。

然后,在ZfcUser\Form\RegisterFilter类中,验证器被添加到元素定义中:

$this->add(array(
    'name'       => 'email',
    'required'   => true,
    'validators' => array(
        array(
            'name' => 'EmailAddress'
        ),
        // Constructor argument containing instance of the validator
        $emailValidator
    ),
));

来源:https://github.com/ZF-Commons/ZfcUser/blob/master/src/ZfcUser/Form/RegisterFilter.php#L37

我相信另一种选择是使用完全限定的类名作为验证器名称(即:“User \ Validator \ PasswordStrength”而不仅仅是“PasswordStrengthValidator”),尽管我自己从未尝试过。

答案 2 :(得分:3)

删除您的可调配置。

并将验证器设置修改为:

  $inputFilter->add($factory->createInput(array(
            'name'     => 'password',
            'required' => true,
            'validators' => array(
                array(
                    'name'    => 'User\Validator\PasswordStrength',
                ),
            ),
        )));

为我工作。

答案 3 :(得分:1)

Rufinus解决方案就像魅力一样。我使用自定义验证器的步骤是(在我的情况下是一个URL验证器,用于检查Web是否确实存在):

1)在module.config.php

'validators' => array(
     'invokables' => array(
         'UrlValidator' => 'Application\Validators\UrlValidator'
     ),
 )

2)在路径Application / src / Application / Validators / UrlValidator.php中

namespace Application\Validators; 
use Zend\Validator\AbstractValidator;                     
class UrlValidator extends AbstractValidator{
    const NOTURL = 'NOTURL';

    protected $messageTemplates = array(
        self::NOTURL => 'Value should be a valid URL',
    );

    public function __construct(array $options = array()){
        parent::__construct($options);
    }

    public function isValid($value){
        $this->setValue($value);       
        if (!$this->validateurl($value)) {
            $this->error(self::NOTURL);
            return false;
        } 
        return true;
    }
    private function validateurl($url) {
        $ch = curl_init(); // initialize curl handle
        curl_setopt($ch, CURLOPT_URL, $url); // set url to post to
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        $result = curl_exec($ch);

        $info = curl_getinfo($ch);
        $code = $info['http_code'];
        curl_close($ch);

        if ($code == substr($code, 0, 1) || substr($code, 0, 1) == '4' || substr($code, 0, 1) == '5') {
            return false;
        } else {
            return true;
        }
   }
}

3)表格

  $inputFilter->add($factory->createInput(array(
                    'name' => 'url',                       
                    'validators' => array(
                        array(
                            'name' => 'NotEmpty',
                            'options' => array(
                                'messages' => array(
                                    'isEmpty' => 'URL is required'
                                )
                            )
                        ),
                        array(
                            'name'=>'Application\Validators\UrlValidator'
                        )
                    )
        )));

额外)如果您想在应用程序的任何位置使用它(即在控制器操作中),您可以从ValidatorManager插件中检索:

$urlValidator = $this->getServiceLocator()->get('ValidatorManager')->get('UrlValidator');

答案 4 :(得分:0)

是的,它可以按照Conti或工厂的说明调用,以防您需要注入服务管理器,例如,在下面的示例中注入Doctrine实体管理器。这是非常优雅的解决方案:

criteria: "Event1"