2016-11-22 3 views
0

У меня есть большая форма с полями времени, даты, выбора и EntityType. Форма не связана с сущностью, но она содержит поля из других объектов. Другими словами, у меня нет data_class в OptionsResolver формы FormType.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); 
     } 
     // ... 
    } 
} 

Все это выше работает отлично. Но теперь эта сложная часть, я должен вернуть backupdata в форму. Пользователь может выбрать предыдущее состояние формы из списка FormStates. Затем нажмите кнопку загрузки.

Атрибут объекта FormState, который я пытаюсь загрузить в форму, является просто результатом $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?.


Я попробовал два способа добавления данных:

Первая попытка, в контроллере:

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()); 
     } 
    } 

} 

Вторая попытка, с помощью 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?

Что является предпочтительным решением в этом случае? Я могу создать фиктивный Entity и исправить эту проблему, но он чувствует себя немного уродливым, а не тем, как идти.

ответ

0

После нескольких дней занятий я нашел решение.

Моя борьба, где не Как сохранить данные формы, как я показал в вопросе. Тем не менее, я допустил ошибку, сохранив . Просмотрите данные в базу данных и попытайтесь загрузить их позже. Хорошо прочитайте здесь, что я имею в виду: https://symfony.com/doc/current/form/events.html#registering-event-listeners-or-event-subscribers

Итак, я также переписал сохранение состояния формы, чтобы быть в форме подписчика. Примечание: помните, что моя форма не имеет data_class в настройках OptionsResolver формы FormType. Таким образом, автоматическое datamapping и т. Д.

В моем первоначальном вопросе вы можете видеть, что у меня есть несколько кнопок отправки, а в контроллере вы можете проверить, какой из них был легко щелкнут. Потому что в контроллере у вас есть доступ к функции getClickedButton().Но не в форме подписчика. Таким образом, я нашел способ, чтобы получить нажал кнопку в EventSubscriberInterface формы:

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 ""; 
    } 
} 

Ниже вы найдете реальное решение, как я спас и loadedthe образуют правильный путь. Я подключаю их на этапе FormEvent :: PRE_SUBMIT. На этом этапе вы можете сохранить и загрузить Request data в FormEvent. Отлично.

Сохранение и загрузка/prepopulating данные формы с помощью 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 
      } 
     } 
    } 
} 

Я уверен, что это решение сэкономит кому-то дней кодирования!

 Смежные вопросы

  • Нет связанных вопросов^_^