![](/img/trans.png)
[英]How to translate messages of a custom validator in Zend Framework?
[英]How to inject a dependency into a Validator in Zend Framework 3?
我創建了一個自定義的驗證器,稱為CredentialsValidator,如果傳遞的憑證有效,則返回true。 憑據的實際驗證是依賴項AccountService的責任,可以通過getAccountService()方法在Validator中使用該依賴項。 CredentialsValidator :: isValid($ value,$ context = null)的有趣部分是:
$accountService = $this->getAccountService();
$accountService->setEmail($this->getEmail());
$accountService->setPassword($this->getPassword());
try {
$accountService->auth();
} catch (RuntimeException $exception) {
$this->setMessage($exception->getMessage());
$this->error(self::INVALID_CREDENTIALS);
return false;
}
屬性$ email和$ password的填充如下:
if (isset($context['email'])) {
$this->setEmail($context['email']);
}
if (isset($context['password'])) {
$this->setPassword($context['password']);
}
當我在單元測試中實例化CredentialsValidator並手動分配依賴項AccountService時,它可以100%正確地工作。
在實際的Web應用程序中,使用module.config.php中的標准配置通過ServiceManager實例化AccountService:
return [
'service_manager' => [
'factories' => [
AccountServiceFactory::class => AccountServiceFactory::class,
],
]
];
但是,我的目標是創建一個典型的“登錄”表單,該表單使用CredentialsValidator來驗證用戶憑據。
為此,我創建了一個擴展Zend \\ Form \\ Form的表單:
$this->add([
'type' => 'text',
'name' => 'email',
'attributes' => [
'id' => 'email'
],
'options' => [
'label' => 'Email',
],
]);
$this->add([
'type' => 'password',
'name' => 'password',
'attributes' => [
'id' => 'password'
],
'options' => [
'label' => 'Password',
],
]);
以及相關的模型,定義了getInputFilter()方法:
public function getInputFilter()
{
if ($this->inputFilter) {
return $this->inputFilter;
}
$this->inputFilter = new InputFilter();
$this->inputFilter->add([
'name' => 'email',
'required' => true,
'filters' => [
['name' => StringTrimFilter::class],
['name' => StripTagsFilter::class],
['name' => StripNewlinesFilter::class],
],
'validators' => [
[
'name' => EmailAddressValidator::class,
'break_chain_on_failure' => true,
'options' => [
'allow' => HostnameValidator::ALLOW_DNS,
'useMxCheck' => false,
],
],
],
]);
$this->inputFilter->add([
'name' => 'password',
'required' => true,
'filters' => [
['name' => StringTrimFilter::class],
['name' => StripTagsFilter::class],
['name' => StripNewlinesFilter::class],
],
'validators' => [
[
'name' => StringLengthValidator::class,
'break_chain_on_failure' => true,
'options' => [
'min' => 1,
'max' => 128
],
]
],
]);
這是問題開始的地方。 當我添加:
[
'name' => CredentialsValidator::class,
'break_chain_on_failure' => true,
],
在“密碼”字段的“驗證器”鍵上,我無法注入所需的依賴關系,該依賴關系存儲在ServiceManager中,因此CredentialsValidator無法工作,因為它無法訪問AccountService實例。
我為這個問題提出了兩種解決方案,其中一種我立即丟棄,因為它使用單例,而另一種在工作時需要手動傳遞依賴關系。
在onBootstrap(MvcEvent $ event)方法中,可以創建一個單例:
AccountService::getInstance()
然后可以在CredentialsValidator中訪問它,並調用Controller。
我放棄了此解決方案,因為它使用了現在不建議使用的Singleton模式。
在Controller中,可以將AccountService實例傳遞到Model的構造函數中:
$model = new Model([AccountService::class => $accountService]);
然后在Model :: getInputFilter()中,將該實例傳遞到'password'字段的'validators'鍵,如下所示:
$this->inputFilter->add([
'name' => 'password,
'required' => true,
'filters' => [
['name' => StringTrimFilter::class],
['name' => StripTagsFilter::class],
['name' => StripNewlinesFilter::class],
],
'validators' => [
[
'name' => StringLengthValidator::class,
'break_chain_on_failure' => true,
'options' => [
'min' => 1,
'max' => 128
],
],
[
'name' => CredentialsValidator::class,
'break_chain_on_failure' => true,
'options' => [
AccountService::class => $this->getAccountService(),
],
],
],
]);
然后,CredentialsValidator只需通過其構造函數接受依賴關系:
if (array_key_exists(AccountService::class, $options)) {
$this->setAccountService($options[AccountService::class]);
}
該解決方案確實有效,並且確實尊重類之間的接口,但是,手動傳遞AccountService實例是一項相當大的額外工作,實際上,ServiceManager和注入的全部目的就是避免這種情況。 解決方案2在Zend Framework 3應用程序中感覺像是異物。
我的問題:如何在不從Controller手動傳遞的情況下訪問CredentialsValidator中的AccountService實例?
預先感謝您。
我認為您可以為CredentialsValidator
創建一個Factory。 然后寄存器內的工廠validators
配置在module.config.php
或內部getValidatorConfig()
內Module.php
。
示例: module.config.php
'service_manager' => [
'factories' => [
]
],
'validators' => [
'factories' => [
CredentialsValidator::class => CredentialsValidatorFactory::class
]
]
或Module.php
public function getValidatorConfig()
{
return [
'factories' => [
CredentialsValidator::class => new CredentialsValidatorFactory::class($param, $param2)
]
]
}
由於驗證器已經注冊,因此您只需在InputFilter
配置中注冊名稱
$this->inputFilter->add([
'name' => 'Credential',
'required' => true,
'validators' => [
[
'name' => CredentialsValidator::class,
]
],
]);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.