ZF2将InputFilter注入Fieldset无法自动工作 [英] ZF2 injecting InputFilter into Fieldset not working automatically
问题描述
我正在使用ZF2和Doctrine2构建一个小型应用程序。以具有大量可重复使用的代码和技术的方式进行设置。但是,被我的 InputFilter
不会自动注入到应该关联的 Fieldset
的事实所困扰。
I'm building a small application with ZF2 and Doctrine2. Setting it up in such a way as to have a lot of reusable code and technique. However, getting stumped by the fact that my InputFilter
is not automatically injected into the Fieldset
that it should get associated to.
我已经确认使用 Fieldset
的表单可以正常工作(无需 InputFilter
)。 InputFilter
在调试过程中也可见。
I've confirmed that the Form that uses the Fieldset
works (without the InputFilter
). The InputFilter
is also visible as present during debugging.
然后的问题是,我在做什么错了,如何解决将单独的 InputFilter
与< ZF2中的code> Fieldset ?
The question then, what am I doing wrong and how to fix having a separate InputFilter
, coupled to a Fieldset
in ZF2?
边注:
1-我知道使用 InputFilterInterface
可以得到 InputFilter
在 Fieldset
类中,并具有 getInputFilterSpecification()
函数。但是,由于我试图使其保持干燥和可重复使用,因此如果我要创建需要使用 Entity
的API,则不必复制它和 InputFilter
,但只能将后者与 Fieldset
结合使用。
1 - I am aware that by using the InputFilterInterface
I could have the InputFilter
inside of the Fieldset
class with the getInputFilterSpecification()
function. However, as I'm trying to keep it DRY and reusable, it wouldn't do to have to copy it if I were to create an API that needs to use the Entity
and InputFilter
, but can only have the latter coupled with a Fieldset
.
2-使用了很多Abstract类,在摘要中将使用哪些摘要类来说明它们具有哪些意义
2 - A lot of Abstract classes are used, where used I'll indicate in the snippets what they have that's relevant
3-问题行位于 CustomerFieldsetFactory.php
3 - The problem line is in 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
Fieldset: 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'),
],
]);
}
}
InputFilter: CustomerInputFilter.php
InputFilter: 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,
],
],
],
]);
}
}
以上课程。在工厂下方
FormFactory: CustomerFormFactory.php
FormFactory: 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;
}
}
FieldsetFactory: CustomerFieldsetFactory.php
FieldsetFactory: 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;
}
}
InputFilterFactory: CustomerInputFilterFactory.php
InputFilterFactory: 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);
}
}
Config: 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,
],
],
我希望你们中的一个能在这里帮助我。
I am hoping one of you can help me out here.
编辑:更新时出现实际错误
CustomerFieldset.php
中的以下行(上面)触发错误。
The following line in the CustomerFieldset.php
(above) triggers the error.
$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
如上面的代码片段所示, InputFilterManager
是InputFilter(及其工厂)。
As seen in the above snippet, the InputFilter (and it's Factory) are known the the InputFilterManager
.
该错误表明它不知道Fieldset上的 getInputFilter()
函数。在某种程度上是正确的,它不存在。然后的问题是,如何使函数存在以便注入InputFilter起作用,或者如何将此InputFilter绑定到Fieldset?
The error states it does not know the getInputFilter()
function on the Fieldset. Which is correct in a way, it doesn't exist. The question then is, how to have the function exist so that injecting the InputFilter will work, or how to bind this InputFilter to the Fieldset?
编辑2:基于Wilt的答案进行更新
添加了使用InputFilterAwareTrait
来抽象类 AbstractInputFilter
创建以下内容(从答案中得出):
EDIT 2: Update based on Wilt's answer
Added use InputFilterAwareTrait
to Abstract class AbstractInputFilter
to create following (from answer):
use Zend\InputFilter\InputFilterAwareTrait;
abstract class AbstractFieldset extends Fieldset
{
use InputFilterAwareTrait;
// ... Other code
}
原来,我有上面(原始)代码中的另一个错误:
在文件 module.config.php
input_filters
应该是 input_filter_specs
。 (使用Trait之后),这是一个无效工厂注册错误(标题为
ServiceNotCreatedException
)。
Turns out that I had another mistake in the (original) code above as well:
In file module.config.php
the input_filters
should've been input_filter_specs
. This was (after using the Trait) a Invalid Factory registered
error (titled ServiceNotCreatedException
).
以下内容可能对某人有用,工厂使用Hydrator,Object和Inputfilter创建字段集具有以下 createService()
函数:
The following might be of use to someone, the Factory to create a Fieldset with Hydrator, Object and Inputfilter has the following createService()
function:
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;
}
推荐答案
添加了很多信息对你的问题。建议您日后尝试缩小问题范围。在此处阅读有关指导原则的更多信息:如何创建最小,完整和可验证的示例。
There is lots of information added to your question. I'd suggest you try to narrow down your question in the future. Read more on the guidelines for a good question here: How to create a Minimal, Complete, and Verifiable example.
Zend框架提供了 InputFilterAwareTrait
和 setInputFilter
和 getInputFilter
方法。您可以在 CustomerFieldset
类中轻松实现/使用此特征:
Zend framework provides a InputFilterAwareTrait
with both the setInputFilter
and getInputFilter
methods. You can easily implement/use this trait inside your CustomerFieldset
class:
use Zend\InputFilter\InputFilterAwareTrait;
class CustomerFieldset extends AbstractFieldset
{
use InputFilterAwareTrait;
//...remaining code
}
如果您希望所有扩展抽象 AbstractFieldset
类的类中的inputfilter,也可以决定在其中添加特征:
In case you want the inputfilter in all classes that extend your abstract AbstractFieldset
class you could also decide to add the trait there:
use Zend\InputFilter\InputFilterAwareTrait;
class AbstractFieldset
{
use InputFilterAwareTrait;
//...remaining code
}
这篇关于ZF2将InputFilter注入Fieldset无法自动工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!