10

我正在尝试制作一个用户注册表单来检查密码字段的复杂性。我已经根据文档编写了一个自定义验证器来执行此操作。该文件位于我的“用户”模块中,位于 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 的文档和示例从未超出验证器的编写范围以解决其与表单的集成等问题。任何建议将不胜感激。

4

5 回答 5

6

您可以尝试此解决方法...在 Module.php 中注册您的验证器,但使用函数getValidatorConfig或在 module.config.php 中的键“validators”下注册。

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);

这对我有用。

马丁

于 2013-03-22T02:10:22.377 回答
5

您尝试在示例中使用的“短名称”验证器加载仅在您首先使用验证器插件管理器 ( 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”),尽管我自己从未尝试过。

于 2012-11-21T19:21:05.037 回答
3

删除您的可调用配置。

并将您的验证器设置修改为:

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

为我工作。

于 2012-11-24T13:34:23.690 回答
1

Rufinus 解决方案就像魅力一样。我使用自定义验证器的步骤是(在我的例子中是一个 URL 验证器来检查网络是否真的存在):

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');
于 2014-02-06T07:59:42.593 回答
0

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

 'validators' => array(
        'invokables' => array(
            //'emailExist' => 'Application\MyValidation\EmailExistValidator',
        ),
        'factories' => array(
            'emailExist' => function ($vm) {
                $serviceLocator = $vm->getServiceLocator();
                $emailExistValidator = new \Application\MyValidation\EmailExistValidator();
                $doctrineEntityManager = $serviceLocator->get('Doctrine\ORM\EntityManager');
                $emailExistValidator->setObjectManager($doctrineEntityManager);
                return $emailExistValidator;
            },
        ),
    ),
于 2017-09-23T19:05:21.907 回答