Несколько форм одной и той же сущности

#php #forms #symfony #symfony4 #symfony-forms

#php #формы #symfony #symfony4 #symfony-forms

Вопрос:

Я изо всех сил пытаюсь проверить форму страницы, которая содержит три разные формы одной и той же сущности.

У меня есть это в моем FormType поле «usuario» — это выбор в моем html, где возвращается только то, что я фильтрую с помощью параметров «dpto»:

 <?php

namespace AppForm;

use AppEntityResponsavel;
use AppEntityUsuario;
use DoctrineORMEntityRepository;
use SymfonyBridgeDoctrineFormTypeEntityType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormExtensionCoreTypeHiddenType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;

class ResponsavelType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('competenciaInicial')
            ->add('cliente')
            ->add('usuario', EntityType::class, [
                'required'=> false,
                'placeholder'=> '',
                'class'=> Usuario::class,
                'query_builder' => function(EntityRepository $er) use ($options){
                return $er->createQueryBuilder('u')
                ->where('u.ativo = 1 AND u.acesso < 9 AND u.departamento = :dpto')
                ->setParameter('dpto',$options['dpto'])
                ->orderBy('u.nome', 'ASC');}
            ])
            ->add('ativo')
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Responsavel::class,
            'dpto' => '',
        ]);
    }
    
}

 

Вот мой контроллер (такой же, как при загрузке страницы), где я создал form1, form2, form3 и передал разные «dpto» в качестве опции для создания представления, а затем я выполнил простой тест, чтобы при отправке формы она сбрасывала, из какой формы она была получена.

 /**
 * @Route("/responsavel", name="responsavel_index")
 */
public function index(Request $request)
{

    $responsavel = new Responsavel();
    $contabil = $request->request->get('contabil');
    
    $form1 =  $this->createForm(ResponsavelType::class, $responsavel, ['dpto'=>'C']);
    $form1->remove('ativo');
    $form1->remove('cliente');
    $form1->remove('competenciaInicial');
    $form1->handleRequest($request);
    
    $form2 =  $this->createForm(ResponsavelType::class, $responsavel, ['dpto'=>'D']);
    $form2->remove('ativo');
    $form2->remove('cliente');
    $form2->remove('competenciaInicial');
    $form2->handleRequest($request);

    $form3 =  $this->createForm(ResponsavelType::class, $responsavel, ['dpto'=>'F']);
    $form3->remove('ativo');
    $form3->remove('cliente');
    $form3->remove('competenciaInicial');
    $form3->handleRequest($request);
    
    if ($form1->isSubmitted()) {
        dump('form1');
    }

    if($form2->isSubmitted()){
        dump('form2');
    }
    
    if($form3->isSubmitted()){
        dump('form3');
    }

    return $this->render('responsavel/index.html.twig', [
        'entity' => [],
        'form1' => $form1->createView(),
        'form2' => $form2->createView(),
        'form3' => $form3->createView()
    ]);
}
 

И вот рендеринг форм и js отправки формы:

 
<div class="modal-body px-4">
  <div id="clienteId" data-cliente="" class="d-none">
  </div>
  {% if app.user.acesso in [1,2,3,4,7]%}
    {% if app.user.acesso <= 3 or app.user.departamento == 'C' %}
      {{ form_start(form1, {'name' : 'responsavelContabil'})}}
        <label class="text-monospace"> Contabilidade </label>
        <div class="row">
          <div class="mb-3 col-10">
              {{form_widget(form1.usuario, {'id' : 'usuarioContabil'})}}
          </div>
          <div class="col-2 mb-3">
              <button id="okContabil" type="submit" class="btn btn-success"><i class="mdi mdi-check"></i></button>
          </div>
        </div>
      {{ form_end(form1)}}
    {% endif %}
    {% if app.user.acesso <= 3 or app.user.departamento == 'D' %}
      {{ form_start(form2, {'name' : 'responsavelDp'})}}
        <label class="text-monospace"> Dpto. Pessoal </label>
        <div class="row">
          <div class="mb-3 col-10">
              {{form_widget(form2.usuario, {'id' : 'usuarioDp'})}}
          </div>
          <div class="col-2 mb-3">
              <button id="okDp" class="btn btn-success"><i class="mdi mdi-check"></i></button>
          </div>
        </div>
      {{ form_end(form2)}}
    {% endif %}
    {% if app.user.acesso <= 3 or app.user.departamento == 'F' %}
      {{ form_start(form3, {'name' : 'responsavelFiscal'})}}
        <label class="text-monospace"> Fiscal </label>
        <div class="row">
          <div class="mb-3 col-10">
              {{form_widget(form3.usuario, {'id' : 'usuarioFiscal'})}}
          </div>
          <div class="col-2 mb-3">
              <button id="okFiscal" class="btn btn-success"><i class="mdi mdi-check"></i></button>
          </div>
        </div>
      {{ form_end(form3)}}
    {% endif %}
  {% endif %}
</div>
...

$('form').submit(function(e){
  e.preventDefault();
  console.log($(this));
  var dpto = $(this[0]).attr('id').replace('usuario', '').charAt(0);

  var responsavel = {dpto:dpto, cliente: $('#clienteId').data('cliente'), responsavel: {usuario: $(this[0]).val()}}
  $.ajax({
    url: "{{ path('responsavel_index')}}",
    type: 'post',
    dataType: 'json',
    data: responsavel,
    success: function(){
      console.log('foi');
    }
  });

 

По-видимому, проблема в том, что когда я отправляю форму, она не отличает одну от другой, а затем повторяет все условия, также проверяет только идентификатор «usuario», переданный в запросе, на соответствие списку вариантов формы, созданной в form1, а затем возвращает ошибку «поле недопустимо» переданногоидентификатор «usuario» в средстве проверки формы.

Есть идеи о том, что я делаю неправильно и как это исправить или как отладить?

Заранее спасибо!

Ответ №1:

Я думаю, вы можете попытаться различить формы по их именам, ключам, которые проходят через запрос.

 public function __construct() {
    $this->prefix = self::$count  ;
}

private $prefix;
private static $count = 0;

public function getBlockPrefix() {
    return $this->prefix . '_form';
}
 

Это был код для вашего типа формы. При этом отображаемые входные данные будут иметь разные имена для каждой формы, например:

     <input type="text" id="form_name" name="0_form[name]" class="form-control">
 

Каждая форма будет иметь разный суффикс, и их представленные значения не будут мешать другим. Просто убедитесь, что вы создаете формы в том же порядке при рендеринге и последующей обработке отправленной формы, поскольку суффикс зависит от порядка (часть «count «). Попробуйте и дайте мне знать, если это сработает.

Обновить:

Это не будет работать в symfony 3 . Экземпляр создается только один раз, но метод buildForm в yout Type вызывается каждый раз, когда вы запускаете форму в Controller guaranteedy. Итак:

 private $formPrefix;

public function __construct()
{
    $this->formPrefix = 0;
}
public function getBlockPrefix()
{
    return $this->formPrefix . '-' . parent::getBlockPrefix();
}

public function buildForm(FormBuilderInterface $builder, array $options) {
      $this->formPrefix;
    ...
}
 

Цитата из блока

Результат создания 2 форм

Комментарии:

1. Кроме того, часть getBlockPrefix ‘_form’ похожа на ‘foo’, замените ее на то, что вы хотите. Переменная $count также может использоваться как sufix ofc.

2. Спасибо за помощь! И как будет выглядеть мой контроллер? Я вставил _construct и getBlocPrefix в свой FormType, он изменил имена отображаемых элементов формы, но для всех трех префикс равен «0_form»

3. О, я понимаю, почему это не работает в Symfony 3 , экземпляр создается только один раз. Я обновлю свой ответ. Попробовал этот метод, и он работает

4. Это не сработало, по-прежнему повторяет 0 в качестве префикса

5. Sry я не упомянул в buildForm @LucasMarques . В ответ добавляется функция buildForm