Php 是否可以创建工厂来实例化自定义表单验证程序?

Php 是否可以创建工厂来实例化自定义表单验证程序?,php,zend-framework2,Php,Zend Framework2,(使用Zend Framework 2.2.4) 我的验证器工厂在验证时似乎不存在。如果我尝试从表单所在的控制器实例化验证器,它反过来工作正常: 这很有效… $mycustomvalidator = $this->getServiceLocator() ->get('ValidatorManager') ->get('LDP_PinAvailable'); 下面是如何在代码中设置的,否则,我似乎找不到问题所在,希望避免打开ZF2源代码来理解。从文件上看,这似乎

(使用Zend Framework 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)

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

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

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


请参阅:

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

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

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


请看:

再挖一些,我发现了问题所在。它在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 );

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

进一步挖掘,我发现了问题所在。它在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 );

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

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

'form_elements' => [
    'factories' => [
        SomeForm::class => SomeFormFactory::class,
    ]
]
和您的验证器:

'validators' => [
    'factories' => [
        SomeValidator::class => SomeValidatorFactory::class,
    ]    
]
您不会通过工厂实例化验证器。原因是表单工厂(类似于
$form->getFormFactory()
)有一个输入过滤器工厂,其中包含默认的验证器链。并且此验证程序链没有附加
ValidatorManager
。如果没有
验证器管理器
,默认链无法将验证器名称映射到验证器工厂

要解决所有这些难题,请在控制器工厂执行以下操作:

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

你的麻烦就结束了

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

'form_elements' => [
    'factories' => [
        SomeForm::class => SomeFormFactory::class,
    ]
]
和您的验证器:

'validators' => [
    'factories' => [
        SomeValidator::class => SomeValidatorFactory::class,
    ]    
]
您不会通过工厂实例化验证器。原因是表单工厂(类似于
$form->getFormFactory()
)有一个输入过滤器工厂,其中包含默认的验证器链。并且此验证程序链没有附加
ValidatorManager
。如果没有
验证器管理器
,默认链无法将验证器名称映射到验证器工厂

要解决所有这些难题,请在控制器工厂执行以下操作:

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

你的麻烦就结束了

谢谢你的回答。这有点像皮塔。从语义上讲,我认为验证器配置中抽象工厂的可用性应该表示开发人员的意图。没有类名解析。对于ZF3来说,这可能是一个值得讨论/建议。请随意在ZF2回购协议上创建一个问题,提出您认为它应该如何表现以及原因。:)完成。现在,我已将验证器的服务名称更改为使用简单的小写字符串。我可以使用控制器中的字符串,例如:
$this->getServiceLocator()->get('ldp-validator-pinavailable')并找到“ok”。当表单尝试验证时,Zend\Validator\ValidatorPluginManager::get失败,无法获取或创建ldp Validator PinAvailableAnks的实例以供您今天的帮助;我没有标记答案,因为我发现解决方案不包括这里提到的关于名字的内容,而是留下了向上投票的好业力和感谢。谢谢你的回答。这有点像皮塔。从语义上讲,我认为在v语言中存在一个抽象工厂