ZF2 将 InputFilter 注入 Fieldset 无法自动工作
ZF2 injecting InputFilter into Fieldset not working automatically
我正在使用 ZF2 和 Doctrine2 构建一个小型应用程序。以具有大量可重用代码和技术的方式进行设置。然而,我的 InputFilter
没有自动注入到它应该关联的 Fieldset
中,这让我很困惑。
我已确认使用 Fieldset
的表单有效(没有 InputFilter
)。 InputFilter
在调试期间也可见。
接下来的问题是,我做错了什么以及如何解决在 ZF2 中将单独的 InputFilter
与 Fieldset
耦合的问题?
旁注:
1 - 我知道通过使用 InputFilterInterface
我可以在 Fieldset
class 内部使用 getInputFilterSpecification()
函数获得 InputFilter
。但是,由于我试图保持干燥和可重复使用,如果我要创建一个需要使用 Entity
和 [=22= 的 API,则不必复制它],但只能让后者加上一个Fieldset
。
2 - 使用了很多摘要 classes,在使用的地方我会在片段中指出它们具有相关的内容
3 - 问题行在 CustomerFieldsetFactory.php
============================================= ============================
实体:Customer.php
/**
* Class Customer
* @package Customer\Entity
*
* @ORM\Entity
* @ORM\Table(name="customers")
*/
class Customer extends AbstractEntity //Contains $id
{
/**
* @var string
* @ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
}
形式:CustomerForm.php
class CustomerForm extends AbstractForm
{
public function __construct($name = null, array $options)
{
parent::__construct($name, $options); // Adds CSRF
}
public function init()
{
$this->add([
'name' => 'customer',
'type' => CustomerFieldset::class,
'options' => [
'use_as_base_fieldset' => true,
],
]);
//Call parent initializer. Check in parent what it does.
parent::init(); //Adds submit button if not in form
}
}
字段集:CustomerFieldset.php
class CustomerFieldset extends AbstractFieldset //Contains EntityManager property and constructor requirement (as we're managing Doctrine Entities here)
{
public function init()
{
$this->add([ //For now id field is here, until InputFilter injection works
'name' => 'id',
'type' => Hidden::class,
'attributes' => [
'id' => 'entityId',
],
]);
$this->add([
'name' => 'name',
'type' => Text::class,
'options' => [
'label' => _('Name'),
],
]);
}
}
输入过滤器:CustomerInputFilter.php
class CustomerInputFilter extends AbstractInputFilter
{
public function init()
{
parent::init();
$this->add([
'name' => 'name',
'required' => true,
'filters' => [
['name' => StringTrim::class],
['name' => StripTags::class],
],
'validators' => [
[
'name' => StringLength::class,
'options' => [
'min' => 3,
'max' => 255,
],
],
],
]);
}
}
在 class 之上。工厂下方
表格工厂:CustomerFormFactory.php
class CustomerFormFactory implements FactoryInterface, MutableCreationOptionsInterface
{
/**
* @var array
*/
protected $options;
/**
* @param array $options
*/
public function setCreationOptions(array $options)
{
//Arguments checking removed
$this->options = $options;
}
/**
* @param ServiceLocatorInterface|ControllerManager $serviceLocator
* @return CustomerForm
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$serviceManager = $serviceLocator->getServiceLocator();
$form = new CustomerForm($this->options['name'], $this->options['options']);
$form->setTranslator($serviceManager->get('translator'));
return $form;
}
}
字段集工厂:CustomerFieldsetFactory.php
class CustomerFieldsetFactory implements FactoryInterface, MutableCreationOptionsInterface
{
/**
* @var string
*/
protected $name;
public function setCreationOptions(array $options)
{
//Argument checking removed
$this->name = $options['name'];
}
public function createService(ServiceLocatorInterface $serviceLocator)
{
$serviceManager = $serviceLocator->getServiceLocator();
$fieldset = new CustomerFieldset($serviceManager->get('Doctrine\ORM\EntityManager'), $this->name);
$fieldset->setHydrator(new DoctrineObject($serviceManager->get('doctrine.entitymanager.orm_default'), false));
$fieldset->setObject(new Customer());
$fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class));
//RIGHT HERE! THE LINE ABOVE IS THE ONE THAT DOES NOT WORK!!!
return $fieldset;
}
}
输入过滤器工厂:CustomerInputFilterFactory.php
class CustomerInputFilterFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$repository = $serviceLocator->getServiceLocator()
->get('Doctrine\ORM\EntityManager')
->getRepository(Customer::class);
return new CustomerInputFilter($repository);
}
}
配置:module.config.php
'controllers' => [
'factories' => [
CustomerController::class => CustomerControllerFactory::class,
],
],
'form_elements' => [
'factories' => [
CustomerForm::class => CustomerFormFactory::class,
CustomerFieldset::class => CustomerFieldsetFactory::class,
],
],
'input_filters' => [
'factories' => [
CustomerInputFilter::class => CustomerInputFilterFactory::class,
],
],
'service_manager' => [
'invokables' => [
CustomerControllerService::class => CustomerControllerService::class,
],
],
我希望你们中的一位能帮我解决这个问题。
编辑:更新实际错误
CustomerFieldset.php
(以上)中的以下行触发错误。
$fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class));
错误:
Fatal error: Call to undefined method Customer\Fieldset\CustomerFieldset::setInputFilter() in D:\htdocs\server-manager\module\Customer\src\Customer\Factory\CustomerFieldsetFactory.php on line 57
如上面的代码片段所示,InputFilter(及其工厂)被称为 InputFilterManager
。
错误表明它不知道 Fieldset 上的 getInputFilter()
函数。这在某种程度上是正确的,它不存在。接下来的问题是,如何让函数存在以便注入 InputFilter 将起作用,或者如何将此 InputFilter 绑定到 Fieldset?
编辑 2:根据威尔特的回答更新
将 use InputFilterAwareTrait
添加到摘要 class AbstractInputFilter
以创建以下内容(来自答案):
use Zend\InputFilter\InputFilterAwareTrait;
abstract class AbstractFieldset extends Fieldset
{
use InputFilterAwareTrait;
// ... Other code
}
原来我在上面的(原始)代码中还有另一个错误:
在文件 module.config.php
中,input_filters
应该是 input_filter_specs
。这是(在使用 Trait 之后)一个 Invalid Factory registered
错误(标题为 ServiceNotCreatedException
)。
以下内容可能对某人有用,使用 Hydrator 创建 Fieldset 的工厂,Object 和 Inputfilter 具有以下 createService()
功能:
public function createService(ServiceLocatorInterface $serviceLocator)
{
/** @var ServiceLocator $serviceManager */
$serviceManager = $serviceLocator->getServiceLocator();
/** @var CustomerRepository $customerRepository */
$customerRepository = $serviceManager->get('Doctrine\ORM\EntityManager')->getRepository(Customer::class);
$fieldset = new CustomerFieldset($serviceManager->get('Doctrine\ORM\EntityManager'), $this->name);
$fieldset->setHydrator(new DoctrineObject($serviceManager->get('doctrine.entitymanager.orm_default'), false));
$fieldset->setObject(new Customer());
$fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class, $customerRepository));
return $fieldset;
}
您的问题中添加了很多信息。我建议您以后尝试缩小问题范围。在此处阅读有关好问题指南的更多信息:How to create a Minimal, Complete, and Verifiable example.
Zend 框架提供了一个 InputFilterAwareTrait
与 setInputFilter
和 getInputFilter
方法。你可以很容易地 implement/use 你的 CustomerFieldset
class:
这个特质
use Zend\InputFilter\InputFilterAwareTrait;
class CustomerFieldset extends AbstractFieldset
{
use InputFilterAwareTrait;
//...remaining code
}
如果您希望所有 class 中的输入过滤器扩展您的摘要 AbstractFieldset
class,您还可以决定在那里添加特征:
use Zend\InputFilter\InputFilterAwareTrait;
class AbstractFieldset
{
use InputFilterAwareTrait;
//...remaining code
}
请参阅以下问题:How to validate nested fieldsets。字段集不包含 InputFilters,但您应该扩展表单的基础 InputFilter。
为每个字段集创建一个 InputFilter,并将它们添加到表单的 InputFilter 中,并与您的字段集同名。正如我链接的另一个问题的答案中所见。
如果您不想这样做,您可以考虑使用 InputSpecification。
我正在使用 ZF2 和 Doctrine2 构建一个小型应用程序。以具有大量可重用代码和技术的方式进行设置。然而,我的 InputFilter
没有自动注入到它应该关联的 Fieldset
中,这让我很困惑。
我已确认使用 Fieldset
的表单有效(没有 InputFilter
)。 InputFilter
在调试期间也可见。
接下来的问题是,我做错了什么以及如何解决在 ZF2 中将单独的 InputFilter
与 Fieldset
耦合的问题?
旁注:
1 - 我知道通过使用 InputFilterInterface
我可以在 Fieldset
class 内部使用 getInputFilterSpecification()
函数获得 InputFilter
。但是,由于我试图保持干燥和可重复使用,如果我要创建一个需要使用 Entity
和 [=22= 的 API,则不必复制它],但只能让后者加上一个Fieldset
。
2 - 使用了很多摘要 classes,在使用的地方我会在片段中指出它们具有相关的内容
3 - 问题行在 CustomerFieldsetFactory.php
============================================= ============================
实体:Customer.php
/**
* Class Customer
* @package Customer\Entity
*
* @ORM\Entity
* @ORM\Table(name="customers")
*/
class Customer extends AbstractEntity //Contains $id
{
/**
* @var string
* @ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
}
形式:CustomerForm.php
class CustomerForm extends AbstractForm
{
public function __construct($name = null, array $options)
{
parent::__construct($name, $options); // Adds CSRF
}
public function init()
{
$this->add([
'name' => 'customer',
'type' => CustomerFieldset::class,
'options' => [
'use_as_base_fieldset' => true,
],
]);
//Call parent initializer. Check in parent what it does.
parent::init(); //Adds submit button if not in form
}
}
字段集:CustomerFieldset.php
class CustomerFieldset extends AbstractFieldset //Contains EntityManager property and constructor requirement (as we're managing Doctrine Entities here)
{
public function init()
{
$this->add([ //For now id field is here, until InputFilter injection works
'name' => 'id',
'type' => Hidden::class,
'attributes' => [
'id' => 'entityId',
],
]);
$this->add([
'name' => 'name',
'type' => Text::class,
'options' => [
'label' => _('Name'),
],
]);
}
}
输入过滤器:CustomerInputFilter.php
class CustomerInputFilter extends AbstractInputFilter
{
public function init()
{
parent::init();
$this->add([
'name' => 'name',
'required' => true,
'filters' => [
['name' => StringTrim::class],
['name' => StripTags::class],
],
'validators' => [
[
'name' => StringLength::class,
'options' => [
'min' => 3,
'max' => 255,
],
],
],
]);
}
}
在 class 之上。工厂下方
表格工厂:CustomerFormFactory.php
class CustomerFormFactory implements FactoryInterface, MutableCreationOptionsInterface
{
/**
* @var array
*/
protected $options;
/**
* @param array $options
*/
public function setCreationOptions(array $options)
{
//Arguments checking removed
$this->options = $options;
}
/**
* @param ServiceLocatorInterface|ControllerManager $serviceLocator
* @return CustomerForm
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$serviceManager = $serviceLocator->getServiceLocator();
$form = new CustomerForm($this->options['name'], $this->options['options']);
$form->setTranslator($serviceManager->get('translator'));
return $form;
}
}
字段集工厂:CustomerFieldsetFactory.php
class CustomerFieldsetFactory implements FactoryInterface, MutableCreationOptionsInterface
{
/**
* @var string
*/
protected $name;
public function setCreationOptions(array $options)
{
//Argument checking removed
$this->name = $options['name'];
}
public function createService(ServiceLocatorInterface $serviceLocator)
{
$serviceManager = $serviceLocator->getServiceLocator();
$fieldset = new CustomerFieldset($serviceManager->get('Doctrine\ORM\EntityManager'), $this->name);
$fieldset->setHydrator(new DoctrineObject($serviceManager->get('doctrine.entitymanager.orm_default'), false));
$fieldset->setObject(new Customer());
$fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class));
//RIGHT HERE! THE LINE ABOVE IS THE ONE THAT DOES NOT WORK!!!
return $fieldset;
}
}
输入过滤器工厂:CustomerInputFilterFactory.php
class CustomerInputFilterFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$repository = $serviceLocator->getServiceLocator()
->get('Doctrine\ORM\EntityManager')
->getRepository(Customer::class);
return new CustomerInputFilter($repository);
}
}
配置:module.config.php
'controllers' => [
'factories' => [
CustomerController::class => CustomerControllerFactory::class,
],
],
'form_elements' => [
'factories' => [
CustomerForm::class => CustomerFormFactory::class,
CustomerFieldset::class => CustomerFieldsetFactory::class,
],
],
'input_filters' => [
'factories' => [
CustomerInputFilter::class => CustomerInputFilterFactory::class,
],
],
'service_manager' => [
'invokables' => [
CustomerControllerService::class => CustomerControllerService::class,
],
],
我希望你们中的一位能帮我解决这个问题。
编辑:更新实际错误
CustomerFieldset.php
(以上)中的以下行触发错误。
$fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class));
错误:
Fatal error: Call to undefined method Customer\Fieldset\CustomerFieldset::setInputFilter() in D:\htdocs\server-manager\module\Customer\src\Customer\Factory\CustomerFieldsetFactory.php on line 57
如上面的代码片段所示,InputFilter(及其工厂)被称为 InputFilterManager
。
错误表明它不知道 Fieldset 上的 getInputFilter()
函数。这在某种程度上是正确的,它不存在。接下来的问题是,如何让函数存在以便注入 InputFilter 将起作用,或者如何将此 InputFilter 绑定到 Fieldset?
编辑 2:根据威尔特的回答更新
将 use InputFilterAwareTrait
添加到摘要 class AbstractInputFilter
以创建以下内容(来自答案):
use Zend\InputFilter\InputFilterAwareTrait;
abstract class AbstractFieldset extends Fieldset
{
use InputFilterAwareTrait;
// ... Other code
}
原来我在上面的(原始)代码中还有另一个错误:
在文件 module.config.php
中,input_filters
应该是 input_filter_specs
。这是(在使用 Trait 之后)一个 Invalid Factory registered
错误(标题为 ServiceNotCreatedException
)。
以下内容可能对某人有用,使用 Hydrator 创建 Fieldset 的工厂,Object 和 Inputfilter 具有以下 createService()
功能:
public function createService(ServiceLocatorInterface $serviceLocator)
{
/** @var ServiceLocator $serviceManager */
$serviceManager = $serviceLocator->getServiceLocator();
/** @var CustomerRepository $customerRepository */
$customerRepository = $serviceManager->get('Doctrine\ORM\EntityManager')->getRepository(Customer::class);
$fieldset = new CustomerFieldset($serviceManager->get('Doctrine\ORM\EntityManager'), $this->name);
$fieldset->setHydrator(new DoctrineObject($serviceManager->get('doctrine.entitymanager.orm_default'), false));
$fieldset->setObject(new Customer());
$fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class, $customerRepository));
return $fieldset;
}
您的问题中添加了很多信息。我建议您以后尝试缩小问题范围。在此处阅读有关好问题指南的更多信息:How to create a Minimal, Complete, and Verifiable example.
Zend 框架提供了一个 InputFilterAwareTrait
与 setInputFilter
和 getInputFilter
方法。你可以很容易地 implement/use 你的 CustomerFieldset
class:
use Zend\InputFilter\InputFilterAwareTrait;
class CustomerFieldset extends AbstractFieldset
{
use InputFilterAwareTrait;
//...remaining code
}
如果您希望所有 class 中的输入过滤器扩展您的摘要 AbstractFieldset
class,您还可以决定在那里添加特征:
use Zend\InputFilter\InputFilterAwareTrait;
class AbstractFieldset
{
use InputFilterAwareTrait;
//...remaining code
}
请参阅以下问题:How to validate nested fieldsets。字段集不包含 InputFilters,但您应该扩展表单的基础 InputFilter。
为每个字段集创建一个 InputFilter,并将它们添加到表单的 InputFilter 中,并与您的字段集同名。正如我链接的另一个问题的答案中所见。
如果您不想这样做,您可以考虑使用 InputSpecification。