1

(使用 Zend 框架 2.2.4)

我的验证器工厂在验证时似乎并不“存在”。如果我尝试从表单所在的控制器实例化验证器,则相反,它可以正常工作:

这有效...

$mycustomvalidator = $this->getServiceLocator()
    ->get('ValidatorManager')
    ->get('LDP_PinAvailable');

以下是代码中的其他设置方式,我似乎找不到问题,并希望避免打开 ZF2 源代码来理解。通过文档,这似乎是正确的。

模块配置

public function getValidatorConfig()
{
    return array(
       'abstract_factories' => array(
           '\LDP\Form\Validator\ValidatorAbstractFactory',
       ),
    );
}

工厂类

namespace LDP\Form\Validator;

use Zend\ServiceManager\AbstractFactoryInterface,
    Zend\ServiceManager\ServiceLocatorInterface;

class ValidatorAbstractFactory implements AbstractFactoryInterface
{
    public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
    {
        return stristr($requestedName, 'LDP_PinAvailable') !== false;
    }


    public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
    {
        // baked in for sake of conversation
        $validator = new \LDP\Form\Validator\PinAvailable();

        if( $validator instanceof DatabaseFormValidatorInterface )
            $validator->setDatabase( $locator->get('mysql_slave') );

        return $validator;
    }
}

自定义验证器

namespace LDP\Form\Validator;

class PinAvailable extends \Zend\Validator\AbstractValidator implements DatabaseFormValidatorInterface
{

    /**
     * @var \Zend\Db\Sql\Sql
     */
    private $database;

    public function setDatabase( \Zend\Db\Sql\Sql $db )
    {
        $this->database = $db;
    }


    public function isValid( $value )
    {
        $DBA = $this->database->getAdapter();
        // do the mixed database stuff here
        return true;
    }
}

最后,数组的表单字段验证器配置部分:

'pin' => array(
    'required' => true,
        'filters'  => array(
            array('name' => 'alnum'),
            array('name' => 'stringtrim'),
        ),
        'validators' => array(
            array( 'name' => 'LDP_PinAvailable' )
        ),
    ),
),

将它们拼凑在一起,加载表单,提交后,它会使用下面的堆栈跟踪:

2013-10-28T17:09:35-04:00 ERR (3): Exception:
1: Zend\Validator\ValidatorPluginManager::get was unable to fetch or create an instance for LDP_PinAvailable
Trace:
#0 /Users/Saeven/Documents/workspace/Application/vendor/zendframework/zendframework/library/Zend/ServiceManager/AbstractPluginManager.php(103): Zend\ServiceManager\ServiceManager->get('LDP_PinAvailabl...', true)
#1 /Users/Saeven/Documents/workspace/Application/vendor/zendframework/zendframework/library/Zend/Validator/ValidatorChain.php(82): Zend\ServiceManager\AbstractPluginManager->get('LDP_PinAvailabl...', Array)
4

3 回答 3

4

ValidatorPluginManager 扩展了 Zend\ServiceManager\AbstractPluginManager。AbstractPluginManager 有一个名为“autoAddInvokableClass”的功能,默认启用。

基本上,这意味着,如果 ValidatorPluginManager 无法解析请求的服务名称,它将检查该名称是否是有效的类名称。如果是这样,它只会按需将其作为可调用类添加到那里,这当然意味着它永远不会退回到您的抽象工厂。

为了避免这种行为,最简单的方法是简单地让您的抽象工厂响应实际上并未解析为实际类名的服务名称。

请参阅:AbstractPluginManager.php#L98-L100

于 2013-10-28T18:27:40.210 回答
2

再挖一些,我发现了问题。它在 Zend\Validator\ValidatorChain 大约第 80 行中提炼为这些行:

public function plugin($name, array $options = null)
{
    $plugins = $this->getPluginManager();
    return $plugins->get($name, $options);
} 

上下文中没有可用的插件管理器。

当我在控制器中准备表单时,我用谷歌搜索了大约三秒钟才发现我必须这样做:

 $validators = $this->getServiceLocator()->get('ValidatorManager');
 $chain      = new ValidatorChain();
 $chain->setPluginManager( $validators );
 $form->getFormFactory()->getInputFilterFactory()->setDefaultValidatorChain( $chain );

希望这对其他人有帮助。以这种方式设置时,您可以使用常规的旧类名,无需扭曲类名。

于 2013-10-29T02:29:20.290 回答
0

在 ZF3/Laminas 中,如果验证器注册为invokable,您可以在表单中调用验证器getInputFilterSpecification(),没有问题。如果使用工厂实例化验证器,则会遇到麻烦。如果我理解正确,即使您的表格是这样注册的

'form_elements' => [
    'factories' => [
        SomeForm::class => SomeFormFactory::class,
    ]
]

和你的验证者:

'validators' => [
    'factories' => [
        SomeValidator::class => SomeValidatorFactory::class,
    ]    
]

您不会通过工厂实例化验证器。原因是表单工厂(你得到的那个$form->getFormFactory())有一个输入过滤器工厂,里面有默认的验证器链。并且这个验证者链没有ValidatorManager附加。如果没有ValidatorManager,默认链无法将验证器名称映射到验证器工厂。

为了解决所有这些令人头疼的问题,在您的控制器工厂中执行以下操作:

$form->('FormElementManager')->get(SomeForm::class);
$form->getFormFactory()->getInputFilterFactory()
        ->getDefaultValidatorChain()->setPluginManager($container->get('ValidatorManager'));

你的麻烦就过去了。

于 2020-04-18T09:59:07.077 回答