首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Symfony 表單組件完整指南:建構、驗證、渲染與進階主題化

     編輯:PHP 相關知識

Symfony Form 組件核心概念

Form 組件是獨立函式庫,可脫離 Symfony 專案使用。核心流程:

  1. 建立表單類:定義欄位、類型、選項、驗證規則
  2. 綁定資料:將物件/陣列資料映射到表單
  3. 處理請求:提交資料綁定、驗證
  4. 渲染輸出:Twig/PHP 模板輸出 HTML

快速入門:建立簡單表單

資料類別 (純 PHP 物件)

// src/Entity/Task.php
namespace App\Entity;

class Task {
    private $task;
    private $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; }
}

控制器中建立表單 (FormBuilder)

use App\Entity\Task;
use Symfony\Component\HttpFoundation\Request;

public function newAction(Request $request) {
    $task = new Task();
    $task->setTask('Write a blog post');
    $task->setDueDate(new \DateTime('tomorrow'));

    $form = $this->createFormBuilder($task)
        ->add('task', 'text')
        ->add('dueDate', 'date')
        ->getForm();

    return $this->render('task/new.html.twig', ['form' => $form->createView()]);
}

Twig 渲染

{# templates/task/new.html.twig #}
{{ form_widget(form) }}

表單提交處理與驗證

標準控制器流程

public function newAction(Request $request) {
    $task = new Task();
    $form = $this->createFormBuilder($task)
        ->add('task', 'text')
        ->add('dueDate', 'date')
        ->getForm();

    $form->handleRequest($request); // 3.4+ 推薦用法,替代 bindRequest()

    if ($form->isSubmitted() && $form->isValid()) {
        // 持久化、重導向
        $em = $this->getDoctrine()->getManager();
        $em->persist($task);
        $em->flush();
        return $this->redirectToRoute('task_success');
    }

    return $this->render('task/new.html.twig', ['form' => $form->createView()]);
}

三種請求路徑:

  1. GET 初始載入 → 建構渲染
  2. POST 驗證失敗 → 綁定資料、渲染錯誤
  3. POST 驗證通過 → 執行業務邏輯、重導向 (PRG 模式)

驗證規則定義 (Validator 組件)

驗證作用於底層物件,而非表單本身。$form->isValid() 實際檢查物件是否符合約束。

// src/Entity/Task.php (Annotations)
use Symfony\Component\Validator\Constraints as Assert;

class Task {
    /**
     * @Assert\NotBlank()
     */
    private $task;

    /**
     * @Assert\NotBlank()
     * @Assert\Type("\DateTime")
     */
    private $dueDate;
    // ... getter/setter
}

或 YAML/XML/PHP 格式配置。

HTML5 客戶端驗證

自動為必填欄位加 required、型別對應 type="email/number/url" 等。可用 novalidate 關閉。

內建欄位類型總覽

分類類型
文字text, textarea, email, integer, money, number, password, percent, search, url
選擇choice, entity, country, language, locale, timezone
日期時間date, datetime, time, birthday
其他checkbox, file, radio
群組collection, repeated
隱藏hidden, csrf

欄位選項常用配置

$builder->add('dueDate', 'date', [
    'widget' => 'single_text',  // 單一文字框而非三個 select
    'label' => '截止日期',       // 自定義標籤
    'required' => false,        // 關閉 required 屬性 (不影響伺服端驗證)
    'attr' => ['class' => 'form-control'], // HTML 屬性
]);

注意:required: true (預設) 僅影響 HTML5 客戶端驗證,伺服端仍需 NotBlank 等約束。

欄位類型猜測

若物件已有驗證元資料,省略類型讓 Symfony 猜測:

$form = $this->createFormBuilder($task)
    ->add('task')                    // 猜測為 text
    ->add('dueDate', null, [        // 猜測為 date
        'widget' => 'single_text'
    ])
    ->getForm();

猜測依據:驗證約束、Doctrine 元資料。可覆蓋猜測選項:'max_length' => 4。

進階渲染控制

逐欄位渲染

{# 完整控制 #}
{{ form_errors(form) }}
{{ form_label(form.task) }} {{ form_errors(form.task) }} {{ form_widget(form.task, {'attr': {'class': 'task_field'}}) }}
{{ form_label(form.dueDate, '截止日期') }} {{ form_errors(form.dueDate) }} {{ form_widget(form.dueDate) }}
{{ form_rest(form) }} {# 渲染隱藏欄位、CSRF token 等 #}

存取欄位屬性

{{ form.task.vars.id }}          {# id 屬性 #}
{{ form.task.vars.full_name }}    {# name 屬性 #}
{{ form.task.vars.value }}        {# 當前值 #}
{{ form.task.vars.label }}        {# 標籤文字 #}

建立獨立表單類別 (最佳實踐)

// src/Form/Type/TaskType.php
namespace App\Form\Type;

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

class TaskType extends AbstractType {
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->add('task')
            ->add('dueDate', null, ['widget' => 'single_text']);
    }

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults([
            'data_class' => Task::class, // 明確指定資料類別
            'validation_groups' => ['registration'], // 指定驗證群組
        ]);
    }

    public function getBlockPrefix() { return 'task'; } // 3.4+ 替代 getName()
}

控制器使用:$form = $this->createForm(TaskType::class, $task);

嵌入表單 (關聯物件)

單一關聯物件

// Task 關聯 Category
$builder->add('category', CategoryType::class);
{# 模板 #}

分類

{{ form_row(form.category.name) }}

提交時自動建立 Category 物件並設定到 Task->category。

集合嵌入 (一對多)

$builder->add('tags', CollectionType::class, [
    'entry_type' => TagType::class,
    'allow_add' => true,
    'allow_delete' => true,
    'by_reference' => false, // 重要:確保 setter 被呼叫
]);

前端需配合 JavaScript 動態增減欄位 (參考 Symfony 文檔 prototype 模式)。

表單主題化

Twig 區塊覆寫

{# templates/form/fields.html.twig #}
{% block field_row %}
{% spaceless %}
    
{{ form_label(form) }} {{ form_errors(form) }} {{ form_widget(form) }}
{% endspaceless %} {% endblock %}
{# 在模板套用 #}
{% form_theme form 'form/fields.html.twig' %}

片段命名規則

類型_部分:textarea_widget、field_errors、form_row。父類型回退機制:textarea_errors 不存在 → 用 field_errors。

全域主題配置

# config.yml
twig:
    form:
        resources: ['form/fields.html.twig']

單一模板內嵌主題

{% extends 'base.html.twig' %}
{% form_theme form _self %}
{% block field_row %} {# 自定義 #} {% endblock %}
{% block content %}{{ form_row(form.task) }}{% endblock %}

CSRF 保護

預設啟用,隱藏欄位 _token。form_rest(form) 會自動渲染。自定義:

public function configureOptions(OptionsResolver $resolver) {
    $resolver->setDefaults([
        'csrf_protection' => true,
        'csrf_field_name' => '_token',
        'csrf_token_id'   => 'task_item', // 不同表單用不同 token
    ]);
}

關閉:'csrf_protection' => false。

無資料類別表單 (純陣列)

public function contactAction(Request $request) {
    $defaultData = ['message' => 'Type your message here'];
    $form = $this->createFormBuilder($defaultData)
        ->add('name', 'text')
        ->add('email', 'email')
        ->add('message', 'textarea')
        ->getForm();

    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $data = $form->getData(); // 回傳陣列 ['name'=>..., 'email'=>..., 'message'=>...]
        // 發送郵件等
    }
    // ...
}

未指定 data_class 且資料非物件時,自動陣列模式。驗證需手動傳入 validation_constraint 選項 (Collection 約束)。

總結

Symfony Form 組件提供從簡單到複雜的完整表單解決方案。關鍵要點:

  • 表單類別化、服務化,促進重用與測試
  • 驗證屬於領域物件,表單只是 UI 綁定層
  • 善用猜測減少樣板代碼,但關鍵處明確配置
  • 渲染靈活:form_row 快速、手動控制精細
  • 主題化機制強大,支援區塊繼承與全域/局部覆寫
  • 嵌入表單處理關聯資料,CollectionType 處理動態集合
  • CSRF 預設開啟,form_rest() 不可省略
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved