我正在使用ZF2和Doctrine2构建一个小应用程序。以这样的方式进行设置,以便拥有大量可重用的代码和技术。但是,由于我的InputFilter
没有被自动注入它应该关联到的Fieldset
这一事实而感到困惑。
我已确认使用Fieldset
的表单有效(没有InputFilter
)。在调试期间,InputFilter
也可见。
那么问题是,我做错了什么以及如何修复单独的InputFilter
,并与ZF2中的Fieldset
相关联?
旁注:
1 - 我知道使用InputFilterInterface
我可以在InputFilter
类中使用Fieldset
getInputFilterSpecification()
函数。但是,当我试图保持DRY和可重用时,如果我要创建一个需要使用Entity
和InputFilter
的API,则无需复制它,但是只有后者加上Fieldset
。
2 - 使用了很多抽象类,在使用的时候我会在片段中指出他们有什么相关的
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
}
}
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
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
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
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
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:根据Wilt的回答进行更新
已将use InputFilterAwareTrait
添加到抽象类AbstractInputFilter
以创建以下内容(来自答案):
use Zend\InputFilter\InputFilterAwareTrait;
abstract class AbstractFieldset extends Fieldset
{
use InputFilterAwareTrait;
// ... Other code
}
原来我上面的(原始)代码中还有另一个错误:
在文件module.config.php
中,input_filters
应该是input_filter_specs
。这是(使用特征后)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;
}
答案 0 :(得分:1)
您的问题中添加了大量信息。我建议你将来尝试缩小你的问题范围。请在此处详细了解有关一个好问题的指南:How to create a Minimal, Complete, and Verifiable example。
Zend框架提供TypeError: Cannot read property 'FormsModule' of undefined(…)
TypeError: Cannot read property 'annotations' of undefined(…)
和InputFilterAwareTrait
和setInputFilter
方法。您可以在getInputFilter
类中轻松实现/使用此特征:
CustomerFieldset
如果您希望扩展抽象use Zend\InputFilter\InputFilterAwareTrait;
class CustomerFieldset extends AbstractFieldset
{
use InputFilterAwareTrait;
//...remaining code
}
类的所有类中的inputfilter,您还可以决定在那里添加特征:
AbstractFieldset
答案 1 :(得分:0)
请参阅以下问题:How to validate nested fieldsets。字段集不包含InputFilters,但您应该扩展表单的基本InputFilter。
为每个Fieldset创建一个InputFilter,并将它们与您的fieldset同名,添加到表单的InputFilter中。正如我所链接的另一个问题的回答所示。
如果您不想这样做,可以考虑使用InputSpecification。