2016-11-19 301 views
0

我正在用ZF2和Doctrine2构建一个小应用程序。设置它的方式有很多可重用的代码和技术。然而,难以置信的是,我的InputFilter没有自动注入到它应该关联的Fieldset中。ZF2注入InputFilter到Fieldset不能自动工作

我已确认使用Fieldset工作的表单(没有InputFilter)。在调试期间,InputFilter也可见。

问题是,我做错了什么,以及如何解决有独立的InputFilter,加上在ZF2 Fieldset


图片的标题说明:

1 - 我知道,通过使用InputFilterInterface我能有Fieldset类内的InputFiltergetInputFilterSpecification()功能。但是,由于我试图保持干燥和可重用,如果要创建需要使用EntityInputFilter的API,但只能将后者与Fieldset结合使用,则无需复制它。

2 - 很多抽象类的使用,在那里使用我的片段表明他们有什么与自己相关

3 - 这个问题行是CustomerFieldsetFactory.php

==== ================================================== ===================

实体:​​3210

/** 
* 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; 
    } 
} 

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 

Debug snippet

如在上面的片段可见,输入过滤(和它的工厂)是已知的的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.phpinput_filters应该是input_filter_specs。这是(使用特质后)Invalid Factory registered错误(标题为ServiceNotCreatedException)。

下可能是使用的人,工厂创建具有保湿,对象一个字段,并输入过滤器具有以下功能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

您是否得到了这个工作? –

+0

您提供了大量的信息,但并未真正解释实际的*错误*。输入过滤器管理器是否找到'CustomerInputFilter'?你是否在'CustomerInputFilterFactory'中执行任何代码? – AlexP

+0

@PurpleHexagon还没有。当前使用fieldset上的'InputFilterProviderInterface'解决这个问题,并且在'getInputFilterSpecification'函数中定义规范。 – Nukeface

回答

1

有很多添加到您问题的信息。我建议你在未来尝试缩小你的问题。在这里阅读关于良好问题的指南的更多信息:How to create a Minimal, Complete, and Verifiable example

Zend框架提供了一个InputFilterAwareTraitsetInputFiltergetInputFilter方法。您可以轻松地实现/使用CustomerFieldset类中这个特质:

use Zend\InputFilter\InputFilterAwareTrait; 

class CustomerFieldset extends AbstractFieldset 
{ 
    use InputFilterAwareTrait; 

    //...remaining code 

} 

如果你想在更高级的抽象AbstractFieldset类所有类的输入过滤器,你也可以决定增加在那里的特质:

use Zend\InputFilter\InputFilterAwareTrait; 

class AbstractFieldset 
{ 
    use InputFilterAwareTrait; 

    //...remaining code 

} 
+0

谢谢!解决了!由于配置不正确,有一些后续错误。编辑的问题,以显示这些(因为他们来自我提供的所有代码)。还提供了完整的'createService()'函数。没有意识到'InputFilterAwareTrait',谢谢! – Nukeface

0

看到下面的问题:How to validate nested fieldsets。字段集不包含InputFilters,但您应该扩展您的表单的基本InputFilter。

每个字段集创建输入过滤器,并将它们添加,使用相同的名称作为您的字段集,你的表单的输入过滤器。正如我在其他问题的答案中所看到的那样。

如果你不想这样做,你可能会考虑与InputSpecification工作。