#はじめに
前回の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'],
]),
],
]);
$builder
にadd
メソッドで、第1引数に名前、第2引数にフィールドタイプ、第3引数にoptionを設定できます。
第1引数の名前は好きにつけて良いのですが、後ほど説明するEntityと紐づけする設定を行うと、Entityに自動で値をセットしてくれるようになります。
そのため、紐づけたEntityのプロパティ名と同じ名前を付けないとエラーになってしまいます。
オプションでmapped
を調べてみると幸せになる可能性もあります。
フィールドタイプやオプションは公式リファレンスをお読みください。
https://symfony.com/doc/3.4/reference/forms/types.html
symfony3.4のページですが、必要に応じてバージョン選択してください。
##フィールドのグループ化
では、他にadd
されたフィールドを見てみましょう。
その中にNameType
やKanaType
AddressType
といったリファレンスにないフィールドが設定されています。
これは何か?
それは、useされている物を見れば分かりますが、Eccube\Form\Type\
に作成されているFormTypeです。
例)Eccube/Form/Type/NameType
パッと見た感じ理解しがたいですが、name01
とname02
が設定されています。
出来上がったテキストフィールド名は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::class
とCustomer
の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_DATA
とPOST_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についての説明はまだまだ足りません。
この記事で逆に迷わすような事になるかもと思いましたが、それでも少しでも参考になればと思います。