Пользовательские валидаторы Zend Framework 2 для форм

Я пытаюсь создать регистрационную форму пользователя, которая проверяет сложность поля пароля. Я написал специальный валидатор, чтобы сделать это в соответствии с документацией . Этот файл находится в модуле User в 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 ... } } 

Моя проблема возникает при попытке использовать этот валидатор в моей регистрационной форме пользователя. Я попытался добавить валидатор в ServiceManager, настроив его в Module.php.

 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, которые я нашел, никогда не распространяются за рамки написания валидатора, чтобы рассмотреть вопрос о его интеграции с формами и т. Д. Любые советы будут очень признательны.

Загружаемое вами «валидатор короткого имени», которое вы пытаетесь использовать в вашем примере, работает только в том случае, если вы сначала зарегистрируете это короткое имя / псевдоним с помощью диспетчера плагинов-валидаторов ( 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

Я считаю, что другой альтернативой является использование полностью квалифицированного имени класса в качестве имени валидатора (то есть: «Пользователь \ Validator \ PasswordStrength» вместо «PasswordStrengthValidator»), хотя я никогда не пытался этого сам.

вы можете попробовать это обходное решение … зарегистрировать свой валидатор в 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); 

Это работает для меня.

Мартин

Удалите введенную конфигурацию.

И измените настройки валидатора на:

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

Работайте со мной.

Решение 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'); 

Да, он может быть invokable, как указано 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; }, ), ),