2016-11-19 288 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工作。