【发布时间】:2016-11-19 23:34:37
【问题描述】:
我正在使用 ZF2 和 Doctrine2 构建一个小型应用程序。以具有大量可重用代码和技术的方式进行设置。然而,我的InputFilter 并没有自动注入到它应该关联的Fieldset 中,这让我感到困惑。
我已经确认使用Fieldset 的表单可以正常工作(没有InputFilter)。 InputFilter 在调试期间也可见。
然后的问题是,我做错了什么以及如何解决在 ZF2 中将 InputFilter 与 Fieldset 耦合的问题?
旁注:
1 - 我知道通过使用InputFilterInterface,我可以在Fieldset 类中使用InputFilter 和getInputFilterSpecification() 函数。但是,由于我试图使其保持干燥和可重复使用,因此如果我要创建一个需要使用 Entity 和 InputFilter 但只能使用后者的 API,则不必复制它加上Fieldset。
2 - 使用了很多抽象类,我将在 sn-ps 中指出它们的相关内容
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,
],
],
],
]);
}
}
高于类。工厂下面
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;
}
}
输入过滤器工厂: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
从上面的 sn-p 中可以看出,InputFilter(和它的工厂)被称为 InputFilterManager。
错误表明它不知道 Fieldset 上的 getInputFilter() 函数。这在某种程度上是正确的,它不存在。那么问题是,如何让函数存在以便注入 InputFilter 起作用,或者如何将此 InputFilter 绑定到 Fieldset?
编辑 2:根据威尔特的回答更新
将use InputFilterAwareTrait 添加到抽象类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、Object 和 Inputfilter 创建 Fieldset 的工厂具有以下 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;
}
【问题讨论】:
-
你搞定了吗?
-
您提供了很多信息,但没有真正解释实际的错误。输入过滤器管理器是否找到
CustomerInputFilter?你执行CustomerInputFilterFactory中的任何代码吗? -
@PurpleHexagon 还没有。当前在字段集上使用
InputFilterProviderInterface解决它,并在getInputFilterSpecification函数中具有规范。 -
@AlexP 我已经更新了问题(在底部;))以清楚地说明问题发生在哪里,我已经调试了变量并理解了错误。只是不知道如何修复错误;) InputFilter 和 InputFilterFactory 都在管理器中注册。但是在 InputFilterFactory 中没有执行任何代码。
->get('CustomerInputFilter')实际返回:An exception was raised while creating "Customer\Fieldset\CustomerFieldset"; no instance returned。
标签: php dependency-injection doctrine-orm zend-framework2