2012-11-20 6 views
9

Ich versuche, ein Benutzerregistrierungsformular zu machen, das auf die Komplexität des Passwortfeldes prüft. Ich habe einen benutzerdefinierten Validator geschrieben, um dies gemäß der documentation zu tun. Diese Datei befindet sich in meinem Benutzermodul unter Benutzer \ src \ User \ Validator.Zend Framework 2 Benutzerdefinierte Validatoren für Formulare

Mein Problem tritt auf, wenn ich versuche, diesen Validator in meinem Benutzerregistrierungsformular zu verwenden. Ich habe versucht, den Validator dem ServiceManager hinzuzufügen, indem ich ihn in der Module.php konfiguriere.

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

Dann habe ich es dem Eingabefilter in User.php hinzugefügt.

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

Wenn ich jedoch auf das Formular zugreifen und die Schaltfläche zum Absenden drücken, erhalte ich eine ServiceNotFoundException.

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

Gibt es ein Problem mit meiner ServiceManager Konfiguration? Ich bin mir nicht einmal sicher, ob dies der geeignete Weg ist, einen benutzerdefinierten Validator überhaupt zu verwenden. Ich habe viele Beispiele mit ZF1 gefunden, aber die Dokumentation und die Beispiele für ZF2, die ich gefunden habe, reichen nie über das Schreiben des Validators hinaus, um seine Integration mit Formularen usw. anzusprechen. Jeder Rat würde sehr geschätzt werden.

Antwort

3

Der "Kurzname" -Validator, den Sie versuchen zu verwenden, funktioniert in Ihrem Beispiel nur, wenn Sie zuerst diesen Kurznamen/Alias ​​mit dem Validator-Plugin-Manager (Zend\Validator\ValidatorPluginManager) registrieren.

Eine Alternative dazu (und die Art, wie ich es tue) besteht darin, Instanzen von erforderlichen benutzerdefinierten Validatoren beim Erstellen des Formularfilterobjekts zu injizieren. Dies ist die Art und Weise ZfcUser tut es:

// 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; 
}, 

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

Hier sind die beiden ZfcUser\Validator\NoRecordExists Validator Instanzen (eine für E-Mail und eine für Benutzernamen) für die in den Konstruktor des Eingangsfilters Objekt injiziert Anmeldeformular (ZfcUser\Form\RegisterFilter).

Dann in der ZfcUser\Form\RegisterFilter Klasse werden die Validatoren zu den Elementdefinitionen hinzugefügt:

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

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

Ich glaube, eine andere Alternative ist es, die vollständig qualifizierten Klassennamen als Validierer zu verwenden Name (zB: "User \ Validator \ PasswordStrength" anstelle von "PasswordStrengthValidator"), obwohl ich das selbst nie versucht habe.

+0

Huh, ich wusste nicht, dass es mit dem Namen zu tun haben, konnte ich es wie es Registrierung ... Ich habe versucht, wirklich Ihre letzte Vorschlag aus und konfiguriert sie in der ServiceManager mit dem voll qualifizierten Klassennamen, und das hat es geschafft! Danke für Ihre Hilfe! –

3

Entfernen Sie Ihre aufrufbare Konfiguration.

und ändern Sie Ihre Validator Einstellungen:

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

Arbeit für mich.

+0

Danke für Ihre Antwort. Ich glaube, das wird funktionieren, aber das Entfernen der aufrufbaren Konfiguration bedeutet, dass der Validator nicht beim ServiceManager registriert wird. Das ist in Ordnung, aber mir wurde empfohlen, den ServiceManager für solche Aufgaben zu verwenden. –

5

können Sie diese Abhilfe versuchen ... Registrer Ihre Validator in module.php aber mit Funktion getValidatorConfig oder in module.config.php unter dem Schlüssel 'Validierer'.

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

Dann in Ihrem User.php, versuchen Sie dies:

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

(aber Sie müssen den Zugang zu Service-Locator haben, können Sie es von Userfactory usw. injizieren) für mich Dies funktioniert.

Martin

1

Rufinus Lösung funktioniert wie Charme. Die Schritte, die ich folgte eine benutzerdefinierte Validator verwenden wurde (in meinem Fall eine URL Validator zu überprüfen, ob die Bahn tatsächlich existiert):

1) In module.config.php

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

2) In Pfad Anwendung /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) In der Form

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

Extr a) Wenn Sie es überall in der App verwenden möchten innerhalb einer Controller-Aktion), können Sie aus dem ValidatorManager Plugin abzurufen:

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

Was wäre, wenn Sie möchten, dass die tatsächliche URL-Prüfung (diese Curl-Anrufe) in einer Service-Methode durchgeführt wird? Gibt es eine Möglichkeit, den Service zu diesem Validator zu übertragen? Oder wenn nicht, um es aus dem Validator zu instanziieren? – Stephane

0

Ja, es von Conti oder als Fabrik in Fall wie angegeben aufrufbaren sein können Sie benötigen Service-Manager zum Beispiel, oder Lehre EntityManager in injizieren folgendes Beispiel. Es ist sehr elegante Lösung auf diese Weise:

'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; 
      }, 
     ), 
    ),