FormType 規約(EC-CUBE 4.4)
対象: src/Eccube/Form/Type/**/*.php, app/Customize/Form/**/*.php
前提: Symfony 7.4 Form / PHP 8.2+
基本ルール
- 名前空間
Eccube\Form\Type。Symfony\Component\Form\AbstractTypeを継承する。 - PHP ファイル先頭に EC-CUBE ライセンスヘッダ。型宣言を付ける(PHPStan level 6)。
- 依存はコンストラクタインジェクション(
EccubeConfig等)。
namespace Eccube\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
class ExampleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('name', TextType::class, [
'required' => true,
'constraints' => [
new Assert\NotBlank(),
new Assert\Length(max: 255),
],
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Example::class,
]);
}
public function getBlockPrefix(): string // 戻り値型宣言は必須(Symfony 6+)
{
return 'example';
}
}
ポイント
getBlockPrefix(): stringの戻り値型宣言は必須(省略すると動かない)。- フォームの動的制御は
$builder->addEventListener(FormEvents::PRE_SET_DATA, ...)/FormEvents::POST_SUBMITで行う。 - バリデーションは制約クラス(
Assert\NotBlank等)で付ける。Rangeで min/max 両方指定時はnotInRangeMessageを使う。 - エンティティに紐づくフォームは
configureOptions()でdata_classを設定する。 - 既存の EC-CUBE 提供 Type(
AddCartType・AddressType・PriceType等)があれば再利用する。 - パスワード入力を扱う場合、対象エンティティに
plain_passwordプロパティが必要。
CSRF
- 管理画面の検索フォーム等で CSRF を無効化しない。
configureOptions()で'csrf_protection' => true(既定)を保ち、テンプレートでトークンを出力する。
カスタマイズ(app/Customize)
- 既存フォームへのフィールド追加は コアを書き換えず
FormTypeExtensionで行い、app/Customize/Form/Extension/に置く(getExtendedTypes()で対象 Type を指定)。
よくある間違い
- ❌
getBlockPrefix()の戻り値型を省略 → ✅: stringを付ける - ❌ 既存フォームをコアで直接改変 → ✅
FormTypeExtension(app/Customize)で拡張 - ❌ 管理画面検索フォームで CSRF 無効化 → ✅ CSRF 保護を保つ
- ❌ 具象クラス依存 → ✅ コンストラクタ DI + 必要なサービスの注入
- ❌ 既存フォームに二重送信防止/楽観ロック用の unmapped hidden を足し、サーバー側で値未送信を即エラー扱い → ✅ 値が空/未送信なら判定をスキップ(プログラム的 POST・既存テスト・外部連携を壊さない後方互換を保つ)
- ❌ 共通 FormType(RepeatedPasswordType 等)を子で使い
options.constraintsを渡す(親が定義した制約が全置換され消える) → ✅ 親の制約一式も再掲して付与する