ZF2:Validator中的ServiceLocator无法获取实例

时间:2015-12-06 15:11:01

标签: zend-framework2

我已经实现了一个自定义验证器类,如下所示

class UsernameUnique extends AbstractValidator implements ServiceLocatorAwareInterface
{
    use ServiceLocatorAwareTrait;

    protected $userManager;

    public function getUserManager()
    {
        if(!$this->userManager)
        {
            $this->userManager = $this->getServiceLocator()->get('RTUserManager');
        }
        return $this->userManager;
    }

    public isValid()
    {
        $um = $this->getUserManager();
        //rest of code
    }
}

我在表格中使用了这个验证器。

'validators' => array(
    array(
        'name'  => 'RTUser\Form\Validator\EmailUnique'
         )
    )

一切似乎都很好但是当表单验证发生时,我得到一个例外

Zend\Validator\ValidatorPluginManager::get was unable to fetch or create an instance for RTUserManager

堆栈跟踪指向Validator类。

可以从控制器创建“RTUserManager”。因此service_manager配置没有问题。但验证器无法创建其实例。

我该如何解决这个问题?

编辑: 这是控制器插件中的代码。

public function register()
{
    $newuser = $this->getInputValues();

    if($newuser->isValid())
    {
        $userdata = $newuser->getData(FormInterface::VALUES_AS_ARRAY);
        if($this->saveUserToDB($userdata))
        {
            return $message('Registration has been successful. Verify your email address to login.');
        }
    }
    return $this->registrationForm($newuser);
}

protected function getInputValues()
{
    $userdata = $this->getController()->getRequest()->getPost();
    $newuser = new RegistrationForm();
    $newuser->bind($userdata);
    return $newuser;
}

表格代码。

class RegistrationForm extends Form
{
    protected $inputfilter;

    public function __construct() 
    {
        //code to add form elements
        $this->setInputFilter($this->getInputFilter());
    }

    public function getInputFilter() 
    {

       if(!$this->inputfilter)
       {
           $inputFilter = new InputFilter();
           //code to add other validators and filters

           $inputFilter->add(
               'name' => 'email',
               'validators' => array(
                    'name'  => 'RTUser\Form\Validator\EmailUnique',
               )
           );
           $this->inputfilter = $inputFilter;
       }
       return $this->inputfilter;
    }
}

1 个答案:

答案 0 :(得分:0)

Zend Framework有多个经理,他们都是服务定位器。如果您只了解ServiceManager

,这可能会造成混淆

在您的验证器中,getServiceLocator不会返回ServiceManager,而是返回ValidatorPluginManagerservice_manager当然不知道您的AbstractPluginManager配置。 幸运的是,它扩展了ServiceManager - 这意味着它包含实际的服务管理器。

因此,在获得服务之前,您需要先访问$this->userManager = $this->getServiceLocator()->get('RTUserManager'); 。代替:

/** @var ValidatorPluginManager $validatorManager */
$validatorManager = $this->getServiceLocator();
/** @var ServiceManager $serviceManager */
$serviceManager = $validatorManager->getServiceLocator();
$this->userManager = $serviceManager->get('RTUserManager');

尝试:

$this->userManager = $this->getServiceLocator()->getServiceLocator()->get('RTUserManager');

这只是一个更清晰的符号:

RTUserManager

最后,我建议你为你的验证器编写一些工厂来注入你的依赖关系InputFilter,以便不依赖于依赖关系。在您的类和Zend 3中使用任何服务定位器并不是一个好习惯,服务定位器甚至可能只在工厂中可用。但那是现在可选的。

修改

你是对的,直接创建ServiceManager是你的第二个问题。因为您这样做了,所以它无法了解InputFilterPluginManager。要解决此问题,您需要:

  1. Zend\InputFilter\Factory注入InputFilter
  2. 使用此工厂
  3. 创建RegistrationForm

    所以你的class RegistrationForm extends Form { protected $inputfilter; /** * @var InputFilterPluginManager */ protected $inputFilterManager; /** * RegistrationForm constructor. * @param InputFilterPluginManager $inputFilterManager */ public function __construct(InputFilterPluginManager $inputFilterManager) { $this->setInputFilterManager($inputFilterManager); parent::__construct("registration"); //code to add form elements $this->setInputFilter($this->getInputFilter()); } public function getInputFilter() { if(!$this->inputfilter) { $factory = new Factory($this->getInputFilterManager()); $inputFilter = $factory->createInputFilter(array( // other input specifications "email" => array( 'name' => 'email', 'validators' => array( array( 'name' => 'Application\Form\Validator\EmailUnique', ), ), ), )); $this->inputfilter = $inputFilter; } return $this->inputfilter; } /** * @return InputFilterPluginManager */ public function getInputFilterManager() { return $this->inputFilterManager; } /** * @param InputFilterPluginManager $inputFilterManager */ public function setInputFilterManager($inputFilterManager) { $this->inputFilterManager = $inputFilterManager; } } 应该是这样的:

    InputFilterPluginManager

    您需要在实例化RegistrationForm时直接传递protected function getInputValues() { /** @var InputFilterPluginManager $inputManager */ $inputManager = $this->getController()->getServiceLocator()->get("InputFilterManager"); $userdata = $this->getController()->getRequest()->getPost(); $newuser = new RegistrationForm($inputManager); $newuser->bind($userdata); return $newuser; } ,或者为其构建工厂。为简单起见,我只是扩展您当前的插件代码,尽管我更喜欢工厂:

    InputFilterPluginManager

    就是这样。工厂可以通过$dirname = "D:\${env:computername}"访问所有经理,因此可以创建具有适当依赖注入的验证器。