形状
Web 開発者にとって、HTML フォームの処理は最も一般的かつ困難なタスクの 1 つです。 Symfony はフォームコンポーネントを統合して、フォームの処理を簡単にします。この章では、複雑なフォームを最初から作成し、フォーム ライブラリの重要な機能を学習します。
Symfony の Form コンポーネントは、Symfony プロジェクトの外部で使用できる独立したクラス ライブラリです。詳細については、フォーム コンポーネントのドキュメントを参照してください。
単純なフォームを作成する ¶
いくつかの「タスク」を表示するための単純な To Do リストを作成しているとします。ユーザーがタスクを編集および作成できるようにするフォームを作成する必要があります。その前に、単一タスクのデータを表示および保存できる Task
クラスを見てみましょう。
// src/AppBundle/Entity/Task.phpnamespace AppBundle\Entity; class Task{ protected $task; protected $dueDate; public function getTask() { return $this->task; } public function setTask($task) { $this->task = $task; } public function getDueDate() { return $this->dueDate; } public function setDueDate(\DateTime $dueDate = null) { $this->dueDate = $dueDate; }}
これは、Symfony と対話したり、他のライブラリを参照したりしないため、ネイティブ PHP オブジェクト クラスです。これは、your プログラムの task
(タスク) のデータ問題を直接解決する、非常に単純な PHP オブジェクト クラスです。もちろん、この章が終わるまでに、HTML フォーム経由で Task
インスタンスにデータを送信し、その値を検証し、データベースに保存できるようになります。
フォームの構築 ¶
Task
クラスを作成したので、次のステップは実際のタスクを作成してレンダリングすることです。 html形式。 Symfony では、これはフォーム オブジェクトを構築し、それをテンプレートにレンダリングすることによって行われます。これで、これらすべてをコントローラーで実行できるようになります。
// src/AppBundle/Controller/DefaultController.phpnamespace AppBundle\Controller; use AppBundle\Entity\Task;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\Form\Extension\Core\Type\TextType;use Symfony\Component\Form\Extension\Core\Type\DateType;use Symfony\Component\Form\Extension\Core\Type\SubmitType; class DefaultController extends Controller{ public function newAction(Request $request) { // create a task and give it some dummy data for this example // 创建一个task对象,赋一些例程中的假数据给它 $task = new Task(); $task->setTask('Write a blog post'); $task->setDueDate(new \DateTime('tomorrow')); $form = $this->createFormBuilder($task) ->add('task', TextType::class) ->add('dueDate', DateType::class) ->add('save', SubmitType::class, array('label' => 'Create Task')) ->getForm(); return $this->render('default/new.html.twig', array( 'form' => $form->createView(), )); }}
この例では、コントローラーでフォームを直接構築する方法を示します。次の Create form class では、独立したクラスを使用してフォームを構築します。フォームを再利用できるため、この方法をお勧めします。
Symfony のフォームオブジェクトは「フォームビルダー」を通じて作成されるため、フォームの作成には多くのコードは必要ありません。フォーム ビルダーの目的は、単純なフォーム作成の「命令」を記述できるようにすることであり、実際にフォームを作成するときのすべての「オーバーロード」タスクはビルダーによって完了されます。
この例では、フォームに task
と dueDate
という 2 つのフィールドを追加しました。 Task
クラスの task
属性と dueDate
属性に対応します。それぞれに FQCN (完全修飾クラス名/完全パス クラス名) の「タイプ」(TextType
、DateType
など) を指定しました。タイプによって、どちらが生成されるかが決まります。フィールドの HTML フォーム タグ (タグ グループ)。
最後に、フォームをサーバーに送信するためのカスタム ラベルを持つ送信ボタンを追加します。
Symfony には多数の組み込み型が付属していますが、これらについて簡単に紹介します (以下の 組み込みフォーム型 を参照)。
フォームのレンダリング ¶
フォームが作成されたら、次のステップはフォームをレンダリングすることです。これは、特定のフォーム「ビュー」オブジェクト (上記のサンプル コントローラーの $form->createView()
メソッドに注意してください) をテンプレートに渡し、一連のフォーム ヘルパー関数 ( helper関数)。
TWIG:{# app/Resources/views/default/new.html.twig #} {{ form_start(form) }} {{ form_widget(form) }} {{ form_end(form) }}
PHP:<!-- app/Resources/views/default/new.html.php --> <?php echo $view['form']->start($form) ?> <?php echo $view['form']->widget($form) ?> <?php echo $view['form']->end($form) ?>
この例では、「POST」リクエストでフォームを送信し、それを「フォーム表示 (ページ)」と同じ URL に送信すると想定しています。 )」。後で、フォーム送信後にリクエスト メソッドとターゲット URL を変更する方法を学びます。 ############それでおしまい!完全なフォームをレンダリングするには 3 行だけが必要です:
form_start(form)
- ファイルのアップロードを使用する場合を含め、フォームの開始タグをレンダリングします。正しい enctype 属性。
- フィールド要素自体、フィールドラベル、フィールド検証のためのエラー情報を含むすべてのフィールドをレンダリングします。
- 各フィールドを手動で生成すると、フォーム終了タグだけでなく、フォーム内のまだレンダリングされていないすべてのフィールドもレンダリングできます。レンダリングされました。これは、非表示フィールドをレンダリングし、自動化されたフィールドを利用する場合に便利です。
CSRF 保護
- 保護メカニズムを使用する場合に非常に便利です。 とてもシンプルですが、(今のところ)あまり柔軟性がありません。通常、フォームのスタイルを制御するには、フォーム内の各フィールドを個別にレンダリングする必要があります。この方法は、後の
続行する前に、レンダリングされた フォーム システムは、 メソッドは #後もう一度電話してください。そうしないと、 コントローラーはフォームを処理するときに一般的なパターンに従います。これには 3 つの方法があります: ブラウザが最初にページを読み込むとき、フォームが作成され、レンダリングされます。 ユーザーがフォームを送信すると、 ユーザーが法的データを含むフォームを送信すると、送信されたデータは再度フォームに書き込まれますが、今回は フォームが正常に送信された後にユーザーをリダイレクトするのは、ユーザーがブラウザーの「更新」ボタンを使用してデータを繰り返し送信するのを防ぐためです。 フォームがいつ送信されるか、またはどのデータがフォームに渡されるかを正確に制御する必要がある場合は、submit() を使用できます。詳細については、「Form::submit() を手動で呼び出す」を参照してください。 前のセクションでは、有効または無効なデータを含むフォームがどのように送信されるかを学びました。 Symfony では、検証プロセスは基礎となるオブジェクト ( 検証は、一連のルール (「制約/制約」と呼ばれる) をクラスに追加することによって実行されます。ルールと制約を 以上です!ここで無効なデータを使用してフォームを再送信すると、適切なエラーがフォームに出力されるのが表示されます。 検証は Symfony の非常に強力な機能であり、独自の 専用の章があります。 Symfony の標準バージョンには、遭遇する可能性のあるすべての従来のフォームフィールドとデータタイプをカバーする膨大な数のフィールドタイプが含まれています。 #各フィールド タイプには、タイプを渡すための異なるオプション セットがあります。フィールド タイプの詳細については、各タイプのドキュメントを参照してください。 タスク メソッドの 2 番目のパラメータを省略した場合 (または 検証制約 (この制約に属さない制約も含む) が考慮されます。 「使用中」検証グループ)。 フィールドタイプを推測することに加えて、Symfony はフィールドオプションの正しい値を推測することもできます。 これらのオプションを設定すると、HTML5 クライアント側検証で使用するための特別な HTML 属性を使用してフィールドがレンダリングされます。ただし、サーバー側では対応する検証ルール ( null# を渡す場合) にのみ使用されます。 ## as add() メソッドの 2 番目のパラメーター) が推測されます。 ご覧のとおり、フォームはコントローラーで直接作成して使用できます。ただし、より良いアプローチは、別の PHP クラスでフォームを作成することです。プログラム内のどこでも再利用できます。 「タスク フォームの作成」に必要なロジックを保持する新しいクラスを作成します。 この新しいクラスには、タスク フォームの作成に必要なすべての要素が含まれています。これを使用すると、コントローラーでフォームをすばやく作成できます。 フォーム ロジックを独自のクラスに配置すると、プロジェクト内のどこでもフォームを簡単に再利用できるようになります。これはフォームを作成する最良の方法ですが、決定はあなた次第です。 を設定する必要があります。マップされたtask
入力ボックスに $task
オブジェクトのプロパティ値 (つまり、「ブログ投稿を書く」) が含まれている理由に注意してください。これはフォームの最初のタスクです。オブジェクトからデータを取得し、それを HTML フォームで表示できるように適切な形式に変換します。 getTask()
および setTask()## を通じて
Task クラスにアクセスできるほど賢いです。 # メソッド 保護された
task 属性。パブリック プロパティでない限り、フォーム コンポーネントがこれらのプロパティからデータを取得および書き込みできるように、
must には "getter" メソッドと "setter" メソッドが定義されている必要があります。ブール型プロパティの場合、ゲッター メソッド (getPublished( ) および
getReminder())。
フォーム送信の処理
¶ここで、フォームの 2 番目のタスクは、ユーザーが送信したデータをオブジェクトのプロパティに転送することです。これを行うには、ユーザーが送信したデータをフォーム オブジェクトに書き込む必要があります。次の機能をコントローラーに追加します。
createView()// ...use Symfony\Component\HttpFoundation\Request; public function newAction(Request $request){
// just setup a fresh $task object (remove the dummy data)
// 直接设置一个全新$task对象(删除了假数据)
$task = new Task(); $form = $this->createFormBuilder($task)
->add('task', TextType::class)
->add('dueDate', DateType::class)
->add('save', SubmitType::class, array('label' => 'Create Task'))
->getForm(); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { // $form->getData() holds the submitted values
// but, the original `$task` variable has also been updated
// $form->getData() 持有提交过来的值
// 但是,原始的 `$task` 变量也已被更新了
$task = $form->getData(); // ... perform some action, such as saving the task to the database
// for example, if Task is a Doctrine entity, save it!
// 一些操作,比如把任务存到数据库中
// 例如,如果Tast对象是一个Doctrine entity,存下它!
// $em = $this->getDoctrine()->getManager();
// $em->persist($task);
// $em->flush(); return $this->redirectToRoute('task_success');
} return $this->render('default/new.html.twig', array(
'form' => $form->createView(),
));}
*_SUBMIT
フォーム イベントへの変更はビュー レイヤーに適用されません (検証中のエラー メッセージなど)。 handleRequest()
フォームが送信されていないことを認識し、何も行いません。フォームが送信されない場合、isSubmitted()
は false を返します。 handleRequest( )
はこのアクションを認識し、送信されたデータを $task
オブジェクトの task
プロパティと dueDate
プロパティに直ちに書き込みます。その後、オブジェクトが検証されます。無効な場合 (検証については次の章で説明します)、isValid()
は false
を返し、フォームは再度レンダリングされますが、今回のみ検証エラー; isValid()
true
を返します。ユーザーを他のページ (「ありがとう」ページや「成功」ページなど) にリダイレクトする前に、$task
オブジェクトを使用していくつかの操作 (データベースへの永続化など) を実行する機会があります。 )。 フォームの検証 ¶
Task
など) で実行されます。言い換えれば、問題は「フォーム」が有効かどうかではなく、「送信されたデータがフォームに適用された」後に $task
オブジェクトが有効かどうかです。 $form->isvalid()
の呼び出しは、基礎となる $task
オブジェクトに有効なデータを取得したかどうかを問い合わせるショートカットです。 Task
クラスに追加して、タスク属性を空にすることはできず、duDate
フィールドも空ではなく、有効な DateTime オブジェクトでなければならないようにします。 Annotations:// src/AppBundle/Entity/Task.phpnamespace AppBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Task{
/**
* @Assert\NotBlank()
*/
public $task; /**
* @Assert\NotBlank()
* @Assert\Type("\DateTime")
*/
protected $dueDate;}
YAML:# src/AppBundle/Resources/config/validation.ymlAppBundle\Entity\Task:
properties:
task:
- NotBlank: ~
dueDate:
- NotBlank: ~
- Type: \DateTime
rreerree組み込みフィールドタイプ ¶
テキスト タイプ フィールド ¶
ChoiceType
DateTimeType
ファイルタイプ
繰り返しタイプ
隠しフィールド ¶
¶ ##ボタンタイプ
##FormType
フィールド タイプのオプション 各フィールド タイプには、構成のための特定の数のオプションがあります。たとえば、dueDate フィールドは現在 3 つの選択ボックスとして表示されます。 DateType
日付フィールドは、単一のテキスト ボックスとして表示されるように構成できます (ユーザーは文字列を日付として入力できます)。 PHP:<!-- app/Resources/views/default/new.html.php --><?php echo $view['form']->form($form, array(
'attr' => array('novalidate' => 'novalidate'),)) ?>
#
Twig:{# app/Resources/views/default/new.html.twig #}
{{ form(form, {'attr': {'novalidate': 'novalidate'}}) }}
# ¶
これで、検証メタデータ (アノテーション: アノテーション) が に追加されました。皆さん、Symfony はすでにあなたのフィールドについて何かを知っています。これを許可すると、Symfony はフィールドのタイプを「推測」して設定できます。次の例では、Symfony は検証ルールに基づいて、
task フィールドが標準の
TextType フィールドであり、
dueDate が
DateType## であると推測できます。 # 分野 。
「Guess」は、->add('dueDate', DateType::class, array(
'widget' => 'single_text',
'required' => false))
null
を入力した場合) に有効になります。 3 番目の引数としてオプションの配列 (上記の dueDate
など) を入力すると、それらのオプションは推測されるフィールドに適用されます。 フィールドタイプのオプションを推測する ¶
Assert\Length
など) は生成されません。これらのサーバー側ルールを手動で追加する必要がありますが、これらのフィールド タイプのオプションはこれらのルールに基づいて推測できます。 必須
必須
オプションは検証ルールに基づいて指定できます (例: フィールド ## です) # NotBlank または
NotNull) または Doctrine メタデータのメタデータ (たとえば、フィールドが
nullable かどうか) が推測されます。クライアント側の検証が自動的に検証ルールと一致するため、これは非常に便利です。
オプションは検証制約 (フィールドに # があるかどうか) に基づいて指定できます。 ## 適用される Length
または Range
) または Doctrine メタデータ (フィールドの長さによる)。 推測された (オプション) 値を変更する場合は、この項目をフィールド タイプのオプション配列に渡してオーバーライドできます。
->add('dueDate', DateType::class, array(
'widget' => 'single_text',
'label' => 'Due Date',))
# public function newAction(){
$task = new Task(); $form = $this->createFormBuilder($task)
->add('task')
->add('dueDate', null, array('widget' => 'single_text'))
->add('save', SubmitType::class)
->getForm();}
# フォーム クラスの作成 ¶
1
->add('task', null, array('attr' => array('maxlength' => 4)))
オプションは
false:
// src/AppBundle/Controller/DefaultController.phpuse AppBundle\Form\Type\TaskType; public function newAction(){
$task = ...;
$form = $this->createForm(TaskType::class, $task); // ...}
さらに、フォームのフィールドが送信されたデータに含まれていない場合、これらのフィールドは明示的に # に設定されます。 ##ヌル ###。 コントローラーでは、フィールド データ (フィールド値) にアクセスできます:
use Symfony\Component\OptionsResolver\OptionsResolver; public function configureOptions(OptionsResolver $resolver){
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Task',
));}
##さらに、マップされていないフィールドのデータを直接変更することもできます: use Symfony\Component\Form\FormBuilderInterface; public function buildForm(FormBuilderInterface $builder, array $options){
$builder
->add('task')
->add('dueDate', null, array('mapped' => false))
->add('save', SubmitType::class)
;}