2016-11-22 4 views
0

時間、日付、選択、およびエンティティタイプのフィールドを持つ大きなフォームがあります。フォームはエンティティにリンクされていませんが、他のエンティティのフィールドを含んでいます。言い換えれば、私はdata_classがFormTypeのOptionsResolverにありません。ここでSymfonyフォームの状態をデータベースにバックアップしてリストアする/または:データベースからフォームを事前入力する方法

私にformTypeです:私は、バックアップの形式のデータをすることができ、コントローラで(簡単にするためにただ一つのフィールドを示す)

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
     $builder 
      ->add('company', EntityType::class, array(
       'placeholder' => 'Companies', 
       'class' => 'AppBundle:Company', 
       'choice_label' => 'name', 
       'multiple' => true, 
       'query_builder' => function (EntityRepository $repository) { 
        return $repository->createQueryBuilder('c')->orderBy('c.name', 'ASC'); 
       }, 
       'required' => false 
      )) 
      //... much more fields 
} 

public function configureOptions(OptionsResolver $resolver) 
{ 
    // This form is not linked to an Entity 
    // Therefore no `data_class` 
} 

。 FormStateが呼び出されました。 FormStateを次のようにデータベースに保存します。

namespace AppBundle\Controller; 

class ReportController extends Controller 
{ 
    /** // ... */ 
    public function listAction(Request $request) 
    { 
     $form = $this->createForm(ReportType::class); 

     $form->handleRequest($request); 

     // Save the form to a FormState 
     if ($form->isSubmitted() && $form->getClickedButton()->getName() == 'saveFormState') { 
      $formStateManager = $this->get('app.manager.form_state'); 

      // Get form data that we want to save 
      $data = $form->getData(); 
      $name = 'Stackoverflow example'; // give it a name 

      $formState = $formStateManager->createNewFormState(); // Create new FormState Entity object 
      $formState->setName($name); 
      $formState->setData($data); 
      $formStateManager->save($formState); 
     } 
     // ... 
    } 
} 

これはすべて上記の作業に最適です。しかし、今は面倒な部分ですが、バックアップデータをフォームに戻す必要があります。ユーザーはFormStatesのリストから以前のフォーム状態を選択できます。そして、ロードボタンを押してください。

フォームにロードしようとするFormStateオブジェクトのdata属性は、$form->getData()の結果に過ぎません。つまり、オブジェクトのない通常の配列です。たぶんそれは問題ですが、私はそれを何とかすることはできません。

そのdata配列は、フォームにロードしようとしているので、値を取ります。私は$form->setData()経由で試してみましたか、$this->createForm(ReportType::class, $data)で新しいフォームを作成してみました。どちらも同じエラーメッセージ:Entities passed to the choice field must be managed. Maybe persist them in the entity manager?で失敗します。コントローラには、

最初の試み:


は、私がデータを追加する2つの方法を試してみました

namespace AppBundle\Controller; 

class ReportController extends Controller 
{ 
    /** // ... */ 
    public function listAction(Request $request) 
    { 

     if ($form->isSubmitted() && $form->getClickedButton()->getName() == 'loadFormState') { 
      // ... 

      $form = $this->createForm(ReportType::class, $formState->getData()); // <-- throws the error 
      $form->submit($formState->getData()); 
     } 
    } 

} 

2回目の試行を、FormEvent加入者経由: 私はそれを行うとFormEventサブスクライバを介して、私は同じエラーが発生します。ここに私のコードは次のとおりです。

namespace AppBundle\Form\EventListener; 

class ReportFieldsSubscriber implements EventSubscriberInterface 
{ 

    // ... 

    public static function getSubscribedEvents() 
    { 
     return array(
      FormEvents::PRE_SUBMIT => array(
       array('loadFormState'), 
      ), 
     ); 
    } 

    /** 
    * Load selected FormState in form 
    * @param FormEvent $event 
    */ 
    public function loadFormState(FormEvent $event) 
    { 
     $form = $event->getForm(); 

     //... 
     // Choosen FormState 
     $formState = $formStateManager->findOneById($formStateId); 

     $formStateData = $formState->getData(); 

     $form->setData($formStateData); // <-- Set data, trows error 
     // ... 
    } 
} 

私は両方のソリューションがエラーを投げて言ったように:Entities passed to the choice field must be managed. Maybe persist them in the entity manager?

この場合、好ましい解決策は何ですか?ダミーのエンティティを作成してこの問題を修正することはできますが、少し醜いと感じられます。

答えて

0

私は解決策を見つけた。

私の闘いではないフォームデータを保存する方法は、私が質問に示したとおりです。しかし、ビューデータをデータベースに保存し、後でロードしようとすると間違いました。 https://symfony.com/doc/current/form/events.html#registering-event-listeners-or-event-subscribers

このように、フォームの状態の保存をフォームのサブスクライバに書き直すこともできます。 注:FormTypeのOptionsResolver設定では、自分のフォームにdata_classがないことを覚えておいてください。したがって、自動データ処理などはありません。

私の最初の質問では、複数のサブミットボタンがあり、コントローラ内でどのボタンがクリックされたのかを簡単に確認できます。コントローラではgetClickedButton()機能にアクセスできるためです。しかし、加入者の形ではありません。だから私は、フォームのEventSubscriberInterfaceでクリックされたボタンを取得する方法を見つけた:あなたは、私が保存されてどのように実際の解決策を見つけ、適切な方法を形成loadedthe下

class ReportFieldsSubscriber implements EventSubscriberInterface 
{ 
    /** 
    * Find which button was clicked 
    * @param $data 
    * @return string 
    */ 
    public function getClickedButton($data) 
    { 
     $requestParams = serialize($data); 

     if (strpos($requestParams, 'saveFormState') !== false) { 
      return 'saveFormState'; 
     } 
     if (strpos($requestParams, 'loadFormState') !== false) { 
      return 'loadFormState'; 
     } 
     if (strpos($requestParams, 'deleteFormState') !== false) { 
      return 'deleteFormState'; 
     } 
     return ""; 
    } 
} 

。私はそれらをFormEvent :: PRE_SUBMITステージに接続します。その段階で、Request dataを保存してFormEventにロードできます。完璧。

FormEventを経由してフォームデータを事前入力の保存と読み込みは、/ :: PRE_SUBMIT:

class ReportFieldsSubscriber implements EventSubscriberInterface 
{ 

    public static function getSubscribedEvents() 
    { 
     return array(
      FormEvents::PRE_SUBMIT => array(
       array('saveFormState'), 
       array('loadFormState'), 
      ), 
     ); 
    } 

    /** 
    * Save form data 
    * @param FormEvent $event 
    */ 
    public function saveFormState(FormEvent $event) 
    { 
     $data = $event->getData(); 
     if ($this->getClickedButton($data) == 'saveFormState') { 
      $formStateManager = $this->formStateManager; 

      // ... 
      $formState = $formStateManager->createNewFormState(); 
      // ... 

      $formState->setData($data); 
      $formStateManager->save($formState); 
     } 
    } 

    /** 
    * Load choosen form data 
    * @param FormEvent $event 
    */ 
    public function loadFormState(FormEvent $event) 
    { 
     $data = $event->getData(); 

     if ($this->getClickedButton($data) == 'loadFormState') { 
      $formStateId = $data['formState']['formStates']; 

      if (is_numeric($formStateId)) { 
       $formStateManager = $this->formStateManager; 
       $formState = $formStateManager->findOneById(intval($formStateId)); 

       // Choosen FormState data 
       $formStateData = $formState->getData(); 

       $event->setData($formStateData); // <-- Call setData() on the FormEvent, not on the form itself 
      } 
     } 
    } 
} 

私は、このソリューションは、コーディングの誰かの日が保存されますかなり確信しています!

関連する問題