1

Symfony 5 でビルドした動的フォームにデフォルトの条件付きロジックが必要なユースケースがあります。

私のユースケースとは何か、そして私の問題を簡単なフォームで説明してみましょう。たとえば、次の 2 つのフィールドを持つフォーム Product があります。

  1. パーツ (choiceType => 左、右)
  2. 長さ (numberType)

変更すると、すべてのフィールド (:input) が Ajax リクエストを通じて送信されます。ページにアクセスするための2つのコントローラーメソッド(フォームがビルドされている)と、ajaxリクエストを介してフォームをレンダリングするために呼び出されるコントローラーメソッド(条件付きロジックを処理する)があります。

条件付きロジック部分については、次のことを行う必要があります

  • パーツを残す場合、デフォルトの長さは 50 にする必要があります
  • パーツが正しい場合、デフォルトの長さは 100 にする必要があります
  • ユーザーはデフォルトのデータを変更できます

左または右に基づいて長さのデフォルト データを設定することは問題ではありません。左を選択すると、デフォルトの長さは 50 になります。値を 55 に変更すると (変更のたびにフォームが送信されます)、再び 50 になります。この動作は論理的ですが、既定のデータはどのように上書きされたのでしょうか?

上記の状況は、ユーザーにデフォルトのデータを変更するオプションを与えると説明することもできます

フォームタイプ

<?php
// ... namespace, use statments

class ProductType extends AbstractType
{
    /**
     * {@inheritDoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add('part', ChoiceType::class, array(
            'choices' => array(
                'Left' => 'left',
                'Right' => 'right',
            )
        ));

        $builder->add('length', NumberType::class);

        $builder->addEventListener(FormEvents::POST_SET_DATA, function(FormEvent $event) use ($options)
        {
            $form = $event->getForm();
            if(null === $product = $event->getData()) {
                return;
            }

            switch($product->getPart()) {
                case 'left': $defaultLength = 50; break;
                case 'right': $defaultLength = 100; break;
                default: $defaultLength = 0;
            }

            $form->get('length')->setData($defaultLength);
        });
    }

    /**
     * {@inheritDoc}
     */
    public function getName(): string
    {
        return 'product';
    }

    /**
     * {@inheritDoc}
     */
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults(array(
            'data_class' => Product::class,
            'translation_domain' => 'forms',
        ));
    }
}

コントローラ

// src/Controller/ProductController.php

// ... namespace, use statments
namespace App\Controller;

class ProductController extends AbstractController
{
    public function productAction(Request $request): Response
    {
        $product = new Product();

        $form = $this->createForm(ProductType::class, $product);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $product = $form->getData();

            dd($product);
        }

        return $this->render('product_view.html.twig', array(
            'form' => $form->createView()
        ));
    }

    public function productConfigureAjaxAction(Request $request): Response
    {
        $product = new Product();
        $part = $request->request->get('product')['part'] ?? null;

        $product->setPart($part);

        $form = $this->createForm(ProductType::class, $product);
        $form->handleRequest($request);

        // product_form.html.twig is an separated file and included in product_view.html.twig
        // by making the form separated is could been used for an ajax response
        return $this->render('product_form.html.twig', array(
            'form' => $form->createView()
        ));
    }
}
4

0 に答える 0