1

フォーム、フィールドセット、および入力フィルターの抽象クラスを使用して構造体を設定しました。 InputFiltersが作成され、FieldsetFactoryによってフィールドセットに設定されている間、フォームとフィールドセットの工場を持っているZF2/Doctrine2 - フィールドセットが検証されず、データは常に有効です

私が持っている問題はInputFilters フォームのためにロードされあるが、これらに使用されていないということです(オプションに沿って通過するMutableCreationOptionsInterfaceを使用しています)データを検証します。すべての入力は有効として受け入れられます。

などです。nameプロパティを持つCountryエンティティを持っています。国名は少なくとも3文字、最大255文字でなければなりません。名前が「ab」のときは有効です。

誰かがを尋ねる前に:エラーがスローされていない、データは単に有効なものとして受け入れられています。

私は過ぎ去った数日間、私が間違いを犯した場所を見つけようとしていたが、見つけられなかった。

また、かなりのコードがあります。私はそれが私が関係していると思うものに限定しましたが、もっと必要なものがあればもっと多くあります。

module.config.php

'form_elements' => [ 
    'factories' => [ 
     CountryForm::class => CountryFormFactory::class, 
     CountryFieldset::class => CountryFieldsetFactory::class, 
    ], 
], 

class Country extends AbstractEntity // Creates $id + getter/setter 
{ 
    /** 
    * @var string 
    * @ORM\Column(name="name", type="string", length=255, nullable=false) 
    */ 
    protected $name; 

    // Other properties 
    // Getters/setters 
} 
Country.php
を、私は型チェック、にdocblockの多くを削除したとタイプは、コード行/読み出し時間を制限するヒント

CountryController.php - AbstractActionControllerを拡張します。

public function editAction() // Here to show the params used to call function 
{ 
    return parent::editAction(
     Country::class, 
     CountryForm::class, 
     [ 
      'name' => 'country', 
      'options' => [] 
     ], 
     'id', 
     'admin/countries/view', 
     'admin/countries', 
     ['id'] 
    ); 
} 

AbstractActionController.php - (ここで間違って行く) - CountryController#editAction(使用)

public function editAction (
    $emEntity, 
    $formName, 
    $formOptions, 
    $idProperty, 
    $route, 
    $errorRoute, array 
    $routeParams = [] 
) { 
    //Check if form is set 

    $id = $this->params()->fromRoute($idProperty, null); 

    /** @var AbstractEntity $entity */ 
    $entity = $this->getEntityManager()->getRepository($emEntity)->find($id); 

    /** @var AbstractForm $form */ 
    $form = $this->getFormElementManager()->get($formName, (is_null($formOptions) ? [] : $formOptions)); 
    $form->bind($entity); 

    /** @var Request $request */ 
    $request = $this->getRequest(); 
    if ($request->isPost()) { 
     $form->setData($request->getPost()); 

     if ($form->isValid()) { // HERE IS WHERE IT GOES WRONG -> ALL IS TRUE 
      try { 
       $this->getEntityManager()->flush(); 
      } catch (\Exception $e) { 
       //Print errors & return (removed, unnecessary) 
      } 

      return $this->redirectToRoute($route, $this->getRouteParams($entity, $routeParams)); 
     } 
    } 

    return [ 
     'form' => $form, 
     'validationMessages' => $form->getMessages() ?: '', 
    ]; 
} 

CountryForm.php

class CountryForm extends AbstractForm 
{ 
    // This one added for SO, does nothing but call parent#__construct, which would happen anyway 
    public function __construct($name = null, array $options) 
    { 
     parent::__construct($name, $options); 
    } 

    public function init() 
    { 
     //Call parent initializer. 
     parent::init(); 

     $this->add([ 
      'name' => 'country', 
      'type' => CountryFieldset::class, 
      'options' => [ 
       'use_as_base_fieldset' => true, 
      ], 
     ]); 
    } 
} 

CountryFormFactory.php

- ベースのフィールドセット

として CountryForm.phpにより上記で使用 $form = $this->getFormElementManager()->get($formName, (is_null($formOptions) ? [] : $formOptions))

abstract class AbstractFormFactory implements FactoryInterface, MutableCreationOptionsInterface 
{ 
    protected $name; 
    protected $options; 

    /** 
    * @param array $options 
    */ 
    public function setCreationOptions(array $options) 
    { 
     // Check presence of required "name" (string) parameter in $options 
     $this->name = $options['name']; 

     // Check presence of required "options" (array) parameter in $options 
     $this->options = $options['options']; 
    } 
} 

CountryFieldset.php: - 10

class CountryFormFactory extends AbstractFormFactory 
{ 
    public function createService(ServiceLocatorInterface $serviceLocator) 
    { 
     $serviceManager = $serviceLocator->getServiceLocator(); 

     /** @var EntityManager $entityManager */ 
     $entityManager = $serviceManager->get('Doctrine\ORM\EntityManager'); 

     $form = new CountryForm($this->name, $this->options); 
     $form->setObjectManager($entityManager); 
     $form->setTranslator($serviceManager->get('translator')); 

     return $form; 
    } 
} 

AbstractFormFactory.phpは、コントローラ関数呼び出しからオプションを受信するようにMutableCreationOptionsInterfaceを使用します

class CountryFieldset extends AbstractFieldset 
{ 
    public function init() 
    { 
     parent::init(); 

     $this->add([ 
      'name' => 'name', 
      'required' => true, 
      'type' => Text::class, 
      'options' => [ 
       'label' => _('Name'), 
      ], 
     ]); 
     // Other properties 
    } 
} 

AbstractFieldset。INPUTFILTERがFIELDSET

class CountryFieldsetFactory extends AbstractFieldsetFactory 
{ 
    public function createService(ServiceLocatorInterface $serviceLocator) 
    { 
     parent::createService($serviceLocator); 

     /** @var CountryRepository $entityRepository */ 
     $entityRepository = $this->getEntityManager()->getRepository(Country::class); 

     $fieldset = new CountryFieldset($this->getEntityManager(), $this->name); 
     $fieldset->setHydrator(new DoctrineObject($this->getServiceManager()->get('doctrine.entitymanager.orm_default'), false)); 
     $fieldset->setObject(new Country()); 
     $fieldset->setTranslator($this->getTranslator()); 

     // HERE THE INPUTFILTER IS SET ONTO THE FIELDSET THAT WAS JUST CREATED 
     $fieldset->setInputFilter(
      $this->getServiceManager()->get('InputFilterManager')->get(
       CountryInputFilter::class, 
       [ // These are the options read by the MutableCreationOptionsInterface 
        'object_manager' => $this->getEntityManager(), 
        'object_repository' => $entityRepository, 
        'translator' => $this->getTranslator(), 
       ] 
      ) 
     ); 

     return $fieldset; 
    } 
} 

ONTO設定されているHERE IN AbstractFieldsetFactory.php

abstract class AbstractFieldsetFactory implements FactoryInterface, MutableCreationOptionsInterface 
{ 

    protected $serviceManager; 
    protected $entityManager; 
    protected $translator; 
    protected $name; 


    public function setCreationOptions(array $options) 
    { 
     $this->name = $options['name']; 
    } 

    public function createService(ServiceLocatorInterface $serviceLocator) 
    { 
     /** @var ServiceLocator $serviceManager */ 
     $this->serviceManager = $serviceLocator->getServiceLocator(); 

     /** @var EntityManager $entityManager */ 
     $this->entityManager = $this->getServiceManager()->get('Doctrine\ORM\EntityManager'); 

     /** @var Translator $translator */ 
     $this->translator = $this->getServiceManager()->get('translator'); 
    } 

    // Getters/setters for properties 
} 

C - PHP

abstract class AbstractFieldset extends Fieldset 
{ 
    use InputFilterAwareTrait; 
    use TranslatorAwareTrait; 

    protected $entityManager; 

    public function __construct(EntityManager $entityManager, $name) 
    { 
     parent::__construct($name); 

     $this->setEntityManager($entityManager); 
    } 

    public function init() 
    { 
     $this->add([ 
      'name' => 'id', 
      'type' => Hidden::class, 
     ]); 
    } 

    // Getters/setters for $entityManager 
} 

CountryFieldsetFactory.php ountryFieldsetInputFilter.php

class CountryInputFilter 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, // This is just completely ignored 
         'max' => 255, 
        ], 
       ], 
      ], 
     ]); 

     // More adding 
    } 
} 

AbstractFieldsetInputFilter.php - ラスト1! :)

abstract class AbstractInputFilter extends InputFilter 
{ 
    use TranslatorAwareTrait; 

    protected $repository; 
    protected $objectManager; 

    public function __construct(array $options) 
    { 
     // Check if ObjectManager|EntityManager for InputFilter is set 
     $this->setObjectManager($options['object_manager']); 

     // Check if EntityRepository instance for InputFilter is set 
     $this->setRepository($options['object_repository']); 

     // Check for presence of translator so as to translate return messages 
     $this->setTranslator($options['translator']); 
    } 

    public function init() 
    { 
     $this->add([ 
      'name' => 'id', 
      'required' => false, 
      'filters' => [ 
       ['name' => ToInt::class], 
      ], 
      'validators' => [ 
       ['name' => IsInt::class], 
      ], 
     ]); 
    } 

    //Getters/setters for properties 
} 

すべてのヘルプは非常に高く評価されるだろう。うまくいけば、あなたはあまりにも上記のコードで過負荷ではありません。しかし、私はこの問題を約3〜4日間戻ってきており、何がうまくいかないのかつまらなかったのです。

要約すると:で

CountryForm上に作成されます。これは、CountryInputFilterで事前にロードされるCountryFieldsetCountryFieldsetFactory)を使用します。

データの検証に関しては、すべてが有効であると認められます。例えば。 - 国名「ab」は有効ですが、StringLengthバリデータは'min' => 3,がオプションとして定義されています。

答えて

1

持っているのでInputFilter。 InputFilterSpecificationsを使用する代わりに。

だからあなたinput_filters設定キーに入力フィルタを追加します。

'form_elements' => [ 
    'factories' => [ 
     CountryForm::class => CountryFormFactory::class, 
     CountryFieldset::class => CountryFieldsetFactory::class, 
    ], 
], 
'input_filters' => [ 
    'factories' => [ 
     CountryInputFilter::class => CountryInputFilterFactory::class, 
     CountryFieldsetInputFilter::class => CountryFieldsetInputFilterFactory::class, 
    ], 
], 

ファクトリクラス:

class CountryInputFilterFactory implements FactoryInterface 
{ 
    public function createService(ServiceLocatorInterface $serviceLocator) 
    { 
     $serviceManager = $serviceLocator->getServiceLocator(); 

     $inputFilter = new CountryInputFilter(
      $serviceLocator->get(CountryFieldsetInputFilter::class), 
      $serviceManager()->get('Doctrine\ORM\EntityManager'), 
      $serviceManager()->get('translator') 
     ); 

     return $inputFilter; 
    } 
} 

class CountryFieldsetInputFilterFactory implements FactoryInterface 
{ 
    public function createService(ServiceLocatorInterface $serviceLocator) 
    { 
     $serviceManager = $serviceLocator->getServiceLocator(); 

     return new CountryFieldsetInputFilter(
      $serviceManager()->get('Doctrine\ORM\EntityManager'), 
      $serviceManager()->get('translator') 
     ); 
    } 
} 

class CountryFormFactory implements AbstractFormFactory 
{ 
    public function createService(ServiceLocatorInterface $serviceLocator) 
    { 
     $serviceManager = $serviceLocator->getServiceLocator(); 

     $form = new CountryForm($this->name, $this->options); 
     $form->setObjectManager($serviceManager->get('Doctrine\ORM\EntityManager')); 
     $form->setTranslator($serviceManager->get('translator')); 

     $form->setInputFilter($serviceManager->get('InputFilterManager')->get(CountryInputFilterFactory::class)); 
     return $form; 
    } 
} 

フォーム:

class CountryForm extends AbstractForm 
{ 
    const COUNTRY_FIELDSET_NAME = 'country'; 

    // This one added for SO, does nothing but call parent#__construct, which would happen anyway 
    public function __construct($name = null, array $options) 
    { 
     parent::__construct($name, $options); 
    } 

    public function init() 
    { 
     //Call parent initializer. 
     parent::init(); 

     $this->add([ 
      'name' => self::COUNTRY_FIELDSET_NAME, 
      'type' => CountryFieldset::class, 
      'options' => [ 
       'use_as_base_fieldset' => true, 
      ], 
     ]); 
    } 
} 

InputFilters:

class CountryInputFilter extends AbstractInputFilter 
{ 
    /** @var CountryFieldsetInputFilter */ 
    protected $countryFieldsetInputFilter; 

    public function __construct(CountryFieldsetInputFilter $filter, $objectManager, $translator) 
    { 
     $this->countryFieldsetInputFilter = $filter; 
     // other dependencies 
    } 

    public function init() 
    { 
     $this->add($this->countryFieldsetInputFilter, CountryForm::COUNTRY_FIELDSET_NAME); 
    } 
} 

class CountryFieldsetInputFilter extends AbstractInputFilter 
{ 
    public function __construct($objectManager, $translator) 
    { 
     // dependencies 
    } 

    public function init() 
    { 
     $this->add([ 
      // configuration 
     ]); 
    } 
} 

インスタンスを保持する配列ではなく、インスタンスごとに引数ごとに依存関係をInputFiltersに挿入しました。

+0

あなたが提供した設定でそれを変更することも問題ではないと仮定しています: ''input_filters' => ['factories' => [[ – Nukeface

+0

@Nukefaceはい他の設定| serviceManagerインスタンスと同じように動作します。 – Kwido

+0

私は、モジュール構成ではなく独自のクラスを持っています。 Factoryクラスを使って自分のアプリケーションを正しく修正したと思いますが、Formに登録されているInputFilterを見ていますが、名前はありません。例えば、 '$ form'オブジェクト(CountryForm)では、 : 'fil '(ここではキーはありません)' =>(CountryFieldsetInputFilter)=> [フィルタはここ]、]、]、 '。 'CountryFormFactory'はあなたの例とまったく同じです(Fieldset名を追加する可能性をチェックしましたが、' setInputFilter() 'ではできません)。 FieldsetFactoryも独自のクラスでは同じですが、 – Nukeface

0
$fieldset->setInputFilter($inputFilter); 

$fieldsetZend\Form\Fieldsetのインスタンスであると仮定すると、この方法は存在しません。あなたはフォームZend\Form\Form)に入力フィルタを設定する必要があるためです。

私はあなたのコードを修正した場合、私は次のようにそうするでしょう。フォームを使って、入力フィルタを提供するために、CountryFormを変更します。これは、Zend\InputFilter\InputFilterProviderInterfaceを使用し、typeキーでカスタム入力フィルタを参照することによって、フォームごとにカスタム入力フィルタを定義する必要なく行うことができます。

フォーム要素マネージャがフォームを作成すると、カスタムを見つけることができるフィルタマネージャCountryInputFilter

たとえば

:あなたは(@AlexPから)別のアプローチは、フォームにフィールドセットのInputFiltersを構築し、追加することによって、そこにある、すでに設定したすべてのクラスを

use Zend\InputFilter\InputFilterProviderInterface; 

class CountryForm extends AbstractForm implements InputFilterProviderInterface 
{ 

    public function init() 
    { 
     //.. add the country fieldset here 
    } 

    /** 
    * getInputFilterSpecification 
    * 
    * Return the form's input filter specification array. 
    * 
    * @return array 
    */ 
    public function getInputFilterSpecification() 
    { 
     return [ 
      // Refers to the country element (happens to be a fieldset) 
      'country' => [ 

       // Tell the input filter factory what type of input filter. 
       'type' => 'Country\\InputFilter\\CountryInputFilter', 

       // You could even overload/change the default defined in the input filter 
       // here. This is useful as sometimes the requirements of the FORM are 
       // different from what the FIELDSET expects. 
       // [ 
       //  'name'  => 'name', 
       //  'required' => false, 
       //  'allow_empty' => true, 
       // ], 
      ], 
     ]; 
    } 

} 
+0

ありがとうございます、私は明日最初に打ち合わせをしています。しかし、一つのこと。 InputFiltersは 'object_repository'、' object_manager'、 'translator'の存在を必要とします。この方法を使ってどうやって渡すのですか? – Nukeface

+0

@Nukefaceフィルタは入力フィルタマネージャからロードされます。依存関係が必要な場合は、それらを挿入するための 'CountryInputFilterFactory'を作成することができます。もしそうなら、 'AbstractInputFilter :: __ construct($ options)'を介して現在行われている '$ options'が工場に渡されます(例えば' CountryInputFilterFactory :: __ construct($ options) ')。 – AlexP

関連する問題