1
  1. 環境 :

Symfony4 アプリケーションでcraue/CraueFormFlowBundleバンドルを使用して基本的な SYmfony4 フォームからステッパーを生成していますが、フォームイベントを導入してフォームの変更に応じてフォームを変更するまでは正常に動作します。

フォーム イベントを使用してフォームを動的に変更する方法

  1. コード :

コントローラー:

**
 * @Route("/user/add", name="add_user")
 * @param Request $request
 */
public function add(Request $request){

    $employe = new Employe();
    $flow = $this->addUserFlow;
    $flow->bind($employe);

    // form of the current step
    $form = $flow->createForm();
    if ($flow->isValid($form)) {
        $flow->saveCurrentStepData($form);

        if ($flow->nextStep()) {
            // form for the next step
            $form = $flow->createForm();
        } else {

            //Persist user
            $this->manager->persist($employe);
            $this->manager->flush();

            //Reset flow to create new user
            $flow->reset();

            //Redirect to new user detail page
            return $this->redirect($this->generateUrl('user_edit', array('id' => $employe->getId())));
        }
    }

    return $this->render('app/users/users/add.html.twig', [
        'form' => $form->createView(),
        'flow' => $flow,
        'employe' => $employe
    ]);
}

AddUserFlow.php

class AddUserFlow extends FormFlow
{
    protected $allowDynamicStepNavigation = true;

    protected function loadStepsConfig()
    {
        return [
            [
                'label' => 'Informations générales',
                'form_type' => UserGeneralType::class,
            ],
            [
                'label' => 'Contact',
                'form_type' => EmployeContactType::class,
            ],
            [
                'label' => 'Contrat',
                'form_type' => EmployeContractType::class,
            ],
            [
                'label' => "Accès a l'application",
                'form_type' => EmployeAccessType::class,
            ]
        ];
    }

}

FormEvent を含む私のステップ 3 フォームは次のとおりです。

/**
 * Class ContractType
 * @package App\Form\User\Stepper
 */
class ContractType extends AbstractType
{

    /**
     * @var EntityManagerInterface
     */
    private $manager;

    /**
     * ContractType constructor.
     */
    public function __construct(EntityManagerInterface  $manager)
    {
        $this->manager = $manager;
    }

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('type', EntityType::class, [
                "class" => TypeContract::class,
                'label'     => 'Type de contrat',
                "required" => true
            ])
            ->add('startDate', DateType::class, [
                'label'     => 'Date de début',
                'widget'    => 'single_text',
                "required"  => false,
            ])
            ->add('endDate', DateType::class, [
                'label'     => 'Date de fin',
                'widget'    => 'single_text',
                "required"  => false,
            ])
            ->add('isInsertion', CheckboxType::class, [
                'label'     => 'Insertion professionnelle',
                "required"  => false,
            ])
            ->add('hourlyRate', MoneyType::class, [
                'label'     => 'Taux horaire',
                "required"  => false,
            ])
        ;

        $formContractTypeModifier = function (FormInterface $form, $contractType = null) {
            if($contractType != null && !$contractType instanceof TypeContract){
                $contractType = $this->manager->getRepository(TypeContract::class)->find($contractType);
            }

            if($contractType != null && $contractType instanceof TypeContract && $contractType->getSlug() === ContractTypeEnum::INTERIM){
                $form->add('company', EntityType::class, [
                    "class" => Company::class,
                    "label"     => "Entreprise",
                    "required"  => true,
                ]);
            }
        };

        // Events listener to modify the form regarding PRE_SET_DATA datas
        $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formContractTypeModifier){
            /** @var array $data */
            $data = $event->getData();
            /** TypeContract $contractType */
            $contractType = isset($data['type']) ? $data['type'] : null;
            //Add elements to form
            $formContractTypeModifier($event->getForm(), $contractType);
        });

        // Events listener to modify the form regarding PRE_SUBMIT
        $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($formContractTypeModifier){
            /** @var array $data */
            $data = $event->getData();
            /** TypeContract $contractType */
            $contractType = isset($data['type']) ? $data['type'] : null;
            //Add elements to form
            $formContractTypeModifier($event->getForm(), $contractType);
        });

    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => null,
        ]);
    }
}

これが私のadd_user.html.twig見解です:

{% if flow.getCurrentStepNumber() == 3 %}
    {% include 'app/users/users/stepper/_step_3.html.twig' %}
{% else %}
    {{ form_errors(form) }}
    {{ form_rest(form) }}
{% endif %}

step_3.html.twig ビューは次のようになります。

{{ form_row(form.contracts.type) }}

{% if form.contracts.company is defined %}
    {{ form_row(form.contracts.company) }}
{% endif %}

{{ form_row(form.contracts.startDate) }}
{{ form_row(form.contracts.endDate) }}
{{ form_row(form.contracts.hourlyRate) }}
{{ form_row(form.contracts.isInsertion) }}


<script>
    $( document ).ready(function() {
        $('#employe_contract_contracts_type').on('change', function() {
            $.ajax({
                url : $form.attr('action'),
                type: $form.attr('method'),
                data : data,
                success: function(html) {
                    console.log(html);
                    console.log($(html));
                    $('#add_employe_step_3_container').replaceWith($(html).find('#add_employe_step_3_container'));
                }
            });

        });
    });
</script>

  1. 質問/問題:

私の問題は、CraueFlow が FormEvent で使用している方法で機能することを意図しているかどうかわからないことであり、ドキュメントが見つかりませんでした。

この質問で提示した方法を試していると、フローの最初のステップを含む Ajax 呼び出しから結果が得られます。その結果$('#add_employe_step_3_container').replaceWith($(html).find('#add_employe_step_3_container'));、コンテナが見つからないため、コンテナに何もロードされません。

次のステップに進んでから 3 番目のステップに戻るとcompany、ステップ 3 に新しいフィールドが表示されます。これは、グローバル フォームが更新されたように見え、formEvent が正しく機能しているためです。

アイデアや例はありますか?

4

1 に答える 1