可以创建工厂来实例化自定义表单验证器吗?

时间:2013-10-28 18:14:36

标签: php zend-framework2

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

3 个答案:

答案 0 :(得分:4)

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

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

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

请参阅:AbstractPluginManager.php#L98-L100

答案 1 :(得分: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 );

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

答案 2 :(得分:0)

在ZF3 / Laminas中,如果将验证者注册为#!/usr/bin/env python """ minimum code to run a model view """ import sys from PyQt5 import QtWidgets as qtw from PyQt5 import QtCore as qtc from PyQt5 import QtGui as qtg class ViewModel(qtc.QAbstractListModel): def __init__(self, input_data=None): super().__init__() self.input_data = input_data or [] # naming of rows ,columns static !! def headerData(self, section, orientation, role): if role == qtc.Qt.DisplayRole: if orientation == qtc.Qt.Horizontal: return "dude" # todo dynamic labeling else: return "leboswki" # todo dynamic labeling def data(self, index, role): if role == qtc.Qt.DisplayRole: row = index.row() # == wie liste[row] der index item = self.input_data[row] return item def rowCount(self, index): # parameter inside is needed ! return len(self.input_data) def flags(self, index): return qtc.Qt.ItemIsEditable | qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled def setData(self, index, value, role): if role == qtc.Qt.EditRole: row = index.row() if index.isValid(): self.input_data[row] = value self.dataChanged.emit(index, index) return True else: return False def removeRows(self, position, rows, parent=qtc.QModelIndex()): self.beginRemoveRows(parent, position, position + rows-1) for i in range(rows): value = self.input_data[position] self.input_data.remove(value) self.endRemoveRows() return True class MainWindow(qtw.QWidget): def __init__(self): super().__init__() # View list_view = qtw.QListView() self.model = ViewModel(input_data=["text1", "text2", "text3", "text4"]) list_view.setModel(self.model) table_view = qtw.QTableView() table_view.setModel(self.model) # widgets self.deleate_row_button = qtw.QPushButton("deleate rows") # layout qvboxlayout = qtw.QVBoxLayout() qvboxlayout.addWidget(list_view) qvboxlayout.addWidget(table_view) qvboxlayout.addWidget(self.deleate_row_button) self.setLayout(qvboxlayout) self.show() # function self.deleate_row_button.clicked.connect(lambda: self.model.removeRows(-1, 1)) if __name__ == '__main__': app = qtw.QApplication(sys.argv) w = MainWindow() sys.exit(app.exec_()) ,则可以在表单的invokable中调用验证者,这没有问题。如果使用工厂实例化验证器,则会遇到麻烦。如果我理解正确,即使您的表格是这样注册的

getInputFilterSpecification()

和您的验证者:

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

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

要解决所有这些头痛问题,请在您的控制器工厂中执行以下操作:

ValidatorManager

,您的烦恼已经结束。