4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

EC-CUBE4 管理画面のCRUD 脱初心者三歩目 其ノ三 FormType編

Posted at

#はじめに
前回のRepository編に続き、FormType編をやっていきます。

FormTypeはその名の通り、フォームを作成する元になるファイルです。
登録・編集フォームや検索フォームなど様々なFormTypeが作成されています。

FormTypeをマスターしようとすると、膨大な記事になりますし、僕もすべて使いこなせてるかと聞かれれば、「No!!」と答えます。

この記事では、基本的な実装方法と、拡張方法を説明します。

#FormTypeの作成

参考にする本体ソース:Eccube/Form/Type/Front/EntryType.php

参考ソースを元に必要最低限な部分を取り出してみます。

namespace Eccube\Form\Type\Front;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class EntryType extends AbstractType
{

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'entry';
    }
}

基本的には、この形に肉付けをしていけば良いかなと思います。
getBlockPrefixでリターンされてる文字列はname属性になり、name="entry[***]"という感じになります。

##フィールド設定

さて、肉付けですが、buildForm内にaddで追加していきます。

基本的なパーツとしてはcompany_nameの設定が分かり易いかと。

$builder
    ->add('company_name', TextType::class, [
        'required' => false,
        'constraints' => [
            new Assert\Length([
                'max' => $this->eccubeConfig['eccube_stext_len'],
            ]),
        ],
    ]);

$builderaddメソッドで、第1引数に名前、第2引数にフィールドタイプ、第3引数にoptionを設定できます。

第1引数の名前は好きにつけて良いのですが、後ほど説明するEntityと紐づけする設定を行うと、Entityに自動で値をセットしてくれるようになります。
そのため、紐づけたEntityのプロパティ名と同じ名前を付けないとエラーになってしまいます。

オプションでmappedを調べてみると幸せになる可能性もあります。

フィールドタイプやオプションは公式リファレンスをお読みください。
https://symfony.com/doc/3.4/reference/forms/types.html
symfony3.4のページですが、必要に応じてバージョン選択してください。

##フィールドのグループ化
では、他にaddされたフィールドを見てみましょう。
その中にNameTypeKanaType AddressTypeといったリファレンスにないフィールドが設定されています。

これは何か?

それは、useされている物を見れば分かりますが、Eccube\Form\Type\に作成されているFormTypeです。
例)Eccube/Form/Type/NameType

パッと見た感じ理解しがたいですが、name01name02が設定されています。
出来上がったテキストフィールド名はname="entry[name][name01]"name="entry[name][name02]"になっています。

オプションの設定をすれば、ある程度柔軟な使い回しが出来るように作られています。

頭がパンクしそうになるかもですが、本体ソースのFormTypeを追ってみてください。
結構利用できそうなものが作られていますよ。

##Entityに紐づけ

Eccube/Form/Type/Front/EntryTypeは新規会員登録とマイページの登録情報編集で使われているFormTypeです。
ここで入力された情報は会員情報なので、Eccube/Entity/Customerにセットしなければなりません。

ですので、下記のメソッドでEntityクラスを紐づけます。

/**
 * {@inheritdoc}
 */
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'data_class' => 'Eccube\Entity\Customer',
    ]);
}

少しだけControllerを見てみましょう。
Eccube/Controller/EntryController

/** @var $Customer \Eccube\Entity\Customer */
$Customer = $this->customerRepository->newCustomer();

/* @var $builder \Symfony\Component\Form\FormBuilderInterface */
$builder = $this->formFactory->createBuilder(EntryType::class, $Customer);

createBuilderの時にEntryType::classCustomerのEntityオブジェクトを設定していますね。

EntityのないContactだと
Eccube/Controller/ContactController

$builder = $this->formFactory->createBuilder(ContactType::class);

createBuilderの時にContactType::classだけ設定されています。
ContactTypeにもEntityを紐づけるような記述はないです。
Eccube/Form/Type/Front/ContactType

##Form Events
Eccube/Form/Type/Front/EntryTypeでは、$builder->addEventListenerが二つ設定されています。
symfony公式ドキュメント(Form Events)

$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
    $Customer = $event->getData();
    if ($Customer instanceof Customer && !$Customer->getId()) {
        $form = $event->getForm();

        $form->add('user_policy_check', CheckboxType::class, [
                'required' => true,
                'label' => null,
                'mapped' => false,
                'constraints' => [
                     new Assert\NotBlank(),
                ],
            ]);
    }
}
);

$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
    $form = $event->getForm();
    /** @var Customer $Customer */
    $Customer = $event->getData();
    if ($Customer->getPassword() != '' && $Customer->getPassword() == $Customer->getEmail()) {
        $form['password']['first']->addError(new FormError(trans('common.password_eq_email')));
    }
});

この部分ですね。
FormEventsの種類は公式ドキュメントを見て頂きたいのですが、ここではPRE_SET_DATAPOST_SUBMITが設定されています。

###FormEvents::PRE_SET_DATA
ドキュメントの翻訳ですが、

  • 事前入力中に指定されたデータを変更します。
  • 事前入力されたデータに応じてフォームを変更します(フィールドを動的に追加または削除します)。

上記目的で使用されます。
EntryTypeは会員新規登録とマイページの情報編集で利用されています。
そしてPRE_SET_DATAの処理は、Entity/Customerのインスタンスであり、IDが否定された場合(nullだったら)user_policy_checkを追加するようになっています。

新規登録フォームの時は「利用規約に同意してお進みください」のチェックボックスを追加して、マイページの情報編集の時は追加しない処理になっています。

###FormEvents::POST_SUBMIT
タイミング的にはControllerの$form->handleRequest($request);の時に呼び出されます。
処理の内容を見てみると、入力されたパスワードが空でなくて、パスワードとメールアドレスが一緒の時、パスワードはメールアドレスと同じ値を設定できません。をいうエラーを設定しています。

複雑なバリデーションを追加したい時に使う印象があります。

##FormType作成の説明は以上
FormType作成の説明は以上なのですが、伝えたい事が沢山ありすぎて、この説明でいいのか不安ではあります。
分からなければ、symfony公式を見る、ググル、勉強会へ参加してみる、質問してみるなどしてみましょう。

#FormType拡張

EC-CUBEのドキュメントに拡張方法が記されています。
FormTypeのカスタマイズ

こちらを読むだけで大丈夫かなと思いますので、ここでの説明は省きます。

#最後に
FromTypeを作成している時に、あーしたいこーしたいで躓くことが多々あります。
そうなった場合は、自分の検索力がものをいうと思いますので、頑張ってください。。。

必要な時、必要な事を検索して身に付けるだけで、気が付けばデキル人になっているものです。

Agentに対してのFormTypeですが、後々すべてを公開しますので、しばらくおまちください。

色々書いてみましたが、FromTypeについての説明はまだまだ足りません。
この記事で逆に迷わすような事になるかもと思いましたが、それでも少しでも参考になればと思います。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?