跳到內容

ChoiceType 欄位 (選擇下拉式選單、單選按鈕和複選框)

編輯此頁面

一個多用途欄位,用於允許使用者「選擇」一個或多個選項。它可以呈現為 select 標籤、單選按鈕或複選框。

要使用此欄位,您必須指定或者 choiceschoice_loader 選項。

呈現為 可以是各種標籤 (請參閱下方)
預設無效訊息 選取的選項無效。
父類型 FormType
類別 ChoiceType

提示

此表單類型定義和繼承的完整選項列表,可透過在您的應用程式中執行此命令取得

1
2
# replace 'FooType' by the class name of your form type
$ php bin/console debug:form FooType

範例用法

使用此欄位最簡單的方式是定義 choices 選項,以指定選項為關聯陣列,其中鍵是顯示給終端使用者的標籤,而陣列值是表單欄位中使用的內部值

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('isAttending', ChoiceType::class, [
    'choices'  => [
        'Maybe' => null,
        'Yes' => true,
        'No' => false,
    ],
]);

這將建立一個像這樣的 select 下拉式選單

A choice list form input with the options "Maybe", "Yes" and "No".

如果使用者選擇 No,表單將針對此欄位傳回 false。同樣地,如果此欄位的起始資料為 true,則 Yes 將會自動選取。換句話說,每個項目的選項是您想要在 PHP 程式碼中取得/設定的值,而是將顯示給使用者的標籤

進階範例 (使用物件!)

此欄位有許多選項,並且大多數選項控制欄位的顯示方式。在此範例中,底層資料是一些具有 getName() 方法的 Category 物件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
use App\Entity\Category;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('category', ChoiceType::class, [
    'choices' => [
        new Category('Cat1'),
        new Category('Cat2'),
        new Category('Cat3'),
        new Category('Cat4'),
    ],
    // "name" is a property path, meaning Symfony will look for a public
    // property or a public method like "getName()" to define the input
    // string value that will be submitted by the form
    'choice_value' => 'name',
    // a callback to return the label for a given choice
    // if a placeholder is used, its empty value (null) may be passed but
    // its label is defined by its own "placeholder" option
    'choice_label' => function (?Category $category): string {
        return $category ? strtoupper($category->getName()) : '';
    },
    // returns the html attributes for each option input (may be radio/checkbox)
    'choice_attr' => function (?Category $category): array {
        return $category ? ['class' => 'category_'.strtolower($category->getName())] : [];
    },
    // every option can use a string property path or any callable that get
    // passed each choice as argument, but it may not be needed
    'group_by' => function (): string {
        // randomly assign things into 2 groups
        return rand(0, 1) === 1 ? 'Group A' : 'Group B';
    },
    // a callback to return whether a category is preferred
    'preferred_choices' => function (?Category $category): bool {
        return $category && 100 < $category->getArticleCounts();
    },
]);

您也可以自訂每個選項的 choice_name。您可以在以下章節中瞭解有關所有這些選項的更多資訊。

警告

placeholder 是一個特定欄位,當選項是可選的時候,列表中的第一個項目必須是空的,以便使用者可以取消選取。使用回呼時,請務必始終處理空選項 null

選擇標籤、複選框或單選按鈕

此欄位可以呈現為多個 HTML 欄位之一,具體取決於 expandedmultiple 選項

元素類型 展開 多選
select 標籤 false false
select 標籤 (帶有 multiple 屬性) false true
單選按鈕 true false
複選框 true true

自訂每個選項的文字 (標籤)

通常,choices 選項中每個項目的陣列鍵會用作顯示給使用者的文字。但是,可以透過 choice_label 選項完全自訂。查看它以取得更多詳細資訊。

群組選項

您可以透過傳遞多維 choices 陣列,將 <select><option> 元素分組到 <optgroup>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('stockStatus', ChoiceType::class, [
    'choices' => [
        'Main Statuses' => [
            'Yes' => 'stock_yes',
            'No' => 'stock_no',
        ],
        'Out of Stock Statuses' => [
            'Backordered' => 'stock_backordered',
            'Discontinued' => 'stock_discontinued',
        ],
    ],
]);
A choice list with the options "Yes" and "No" grouped under "Main Statuses" and the options "Backordered" and "Discontinued" under "Out of Stock Statuses".

若要更精緻,請改用 group_by 選項。

欄位選項

choices

類型array 預設值[]

這是指定此欄位應使用之選項的最基本方法。choices 選項是一個陣列,其中陣列鍵是項目的標籤,而陣列值是項目的值

1
2
3
4
5
6
7
8
9
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('inStock', ChoiceType::class, [
    'choices' => [
        'In Stock' => true,
        'Out of Stock' => false,
    ],
]);

如果存在非純量或字串化表示形式不唯一的選項值,Symfony 將使用遞增整數作為值。當表單提交時,具有正確類型的正確值將會被指派給模型。

choice_attr

類型arraycallablestringPropertyPath 預設值[]

使用此選項可為每個選項新增額外的 HTML 屬性。這可以是關聯陣列,其中鍵與選項鍵匹配,值是每個選項的屬性,也可以是可呼叫或屬性路徑 (就像 choice_label 一樣)。

如果是陣列,則必須將 choices 陣列的鍵用作鍵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('fruits', ChoiceType::class, [
    'choices' => [
        'Apple' => 1,
        'Banana' => 2,
        'Durian' => 3,
    ],
    'choice_attr' => [
        'Apple' => ['data-color' => 'Red'],
        'Banana' => ['data-color' => 'Yellow'],
        'Durian' => ['data-color' => 'Green'],
    ],
]);

// or use a callable
$builder->add('attending', ChoiceType::class, [
    'choices' => [
        'Yes' => true,
        'No' => false,
        'Maybe' => null,
    ],
    'choice_attr' => function ($choice, string $key, mixed $value) {
        // adds a class like attending_yes, attending_no, etc
        return ['class' => 'attending_'.strtolower($key)];
    },
]);

提示

當定義自訂類型時,您應該使用 ChoiceList 類別協助程式

1
2
3
4
5
6
7
8
9
use App\Entity\Category;
use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
    'choice_attr' => ChoiceList::attr($this, function (?Category $category): array {
        return $category ? ['data-uuid' => $category->getUuid()] : [];
    }),
]);

請參閱 「choice_loader」選項文件

choice_filter

類型callablestringPropertyPath 預設值null

當使用來自 Symfony 核心或供應商程式庫的預定義選項類型 (即 CountryType) 時,此選項可讓您定義一個可呼叫物件,該物件將每個選項作為唯一引數,並且必須傳回 true 以保留選項或 false 以捨棄選項

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// src/Form/Type/AddressType.php
namespace App\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CountryType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class AddressType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver
            ->setDefaults([
                // enable this type to accept a limited set of countries
                'allowed_countries' => null,
            ])
        ;
    }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $allowedCountries = $options['allowed_countries'];

        $builder
            // ...
            ->add('country', CountryType::class, [
                // if the AddressType "allowed_countries" option is passed,
                // use it to create a filter
                'choice_filter' => $allowedCountries ? function ($countryCode) use ($allowedCountries): bool {
                    return in_array($countryCode, $allowedCountries, true);
                } : null,

            ])
        ;
    }

當選項是物件時,此選項可以是可呼叫物件或屬性路徑

1
2
3
4
5
6
7
// ...
$builder
    ->add('category', ChoiceType::class, [
        // ...
        'choice_filter' => 'isSelectable',
    ])
;

提示

考慮到這個 AddressType 可能是 CollectionType 的一個條目,您應該使用 ChoiceList 類別協助程式來啟用快取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/Form/Type/AddressType.php
// ...
use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
'choice_filter' => $allowedCountries ? ChoiceList::filter(
    // pass the type as first argument
    $this,
    function (string $countryCode) use ($allowedCountries): bool {
        return in_array($countryCode, $allowedCountries, true);
    },
    // pass the option that makes the filter "vary" to compute a unique hash
    $allowedCountries
) : null,
// ...

choice_label

類型stringcallablefalsePropertyPath 預設值null

預設情況下,choices 選項中每個項目的陣列鍵會用作顯示給使用者的文字。choice_label 選項可讓您取得更多控制權

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('attending', ChoiceType::class, [
    'choices' => [
        'yes' => true,
        'no' => false,
        'maybe' => null,
    ],
    'choice_label' => function ($choice, string $key, mixed $value): TranslatableMessage|string {
        if (true === $choice) {
            return 'Definitely!';
        }

        return strtoupper($key);

        // or if you want to translate some key
        //return 'form.choice.'.$key;
        //return new TranslatableMessage($key, false === $choice ? [] : ['%status%' => $value], 'store');
    },
]);

此方法針對每個選項呼叫,從選項陣列中傳遞 $choice$key 給您 (額外的 $valuechoice_value 相關)。這將給您

A choice list with the options "Definitely!", "NO" and "MAYBE".

如果您的選項值是物件,則 choice_label 也可以是 屬性路徑。想像一下您有一些具有 getDisplayName() 方法的 Status 類別

1
2
3
4
5
6
7
8
9
10
11
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('attending', ChoiceType::class, [
    'choices' => [
        new Status(Status::YES),
        new Status(Status::NO),
        new Status(Status::MAYBE),
    ],
    'choice_label' => 'displayName',
]);

如果設定為 false,則將為單選或複選框輸入捨棄所有標籤。您也可以從可呼叫物件傳回 false 以捨棄某些標籤。

提示

當定義自訂類型時,您應該使用 ChoiceList 類別協助程式

1
2
3
4
5
6
use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
    'choice_label' => ChoiceList::label($this, 'displayName'),
]);

請參閱 「choice_loader」選項文件

choice_loader

類型ChoiceLoaderInterface

choice_loader 選項可以用來代替 choices 選項。它允許在僅擷取一組提交值的選項時,延遲或部分建立列表 (即查詢像 ElasticSearch 這樣的搜尋引擎可能是一個繁重的過程)。

如果您想利用延遲載入,可以使用 CallbackChoiceLoader 的實例

1
2
3
4
5
6
7
8
9
10
use App\StaticClass;
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('loaded_choices', ChoiceType::class, [
    'choice_loader' => new CallbackChoiceLoader(static function (): array {
        return StaticClass::getConstants();
    }),
]);

如果請求被重新導向並且沒有預設或提交的資料,這將導致不發生 StaticClass::getConstants() 的呼叫。否則,選項選項將需要被解析,從而觸發回呼。

如果內建的 CallbackChoiceLoader 不符合您的需求,您可以透過實作 ChoiceLoaderInterface 或擴充 AbstractChoiceLoader 來建立您自己的載入器。這個抽象類別透過實作介面的一些方法來為您節省一些樣板程式碼,因此您只需要實作 loadChoices() 方法即可擁有功能齊全的選項載入器。

當您定義一個可能在許多欄位 (例如集合的條目) 中重複使用或在多個表單中同時重複使用的自訂選項類型時,您應該使用 ChoiceList 靜態方法來包裝載入器,並使選項列表可快取以獲得更好的效能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
use App\Form\ChoiceList\CustomChoiceLoader;
use App\StaticClass;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\ChoiceList\ChoiceList;
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ConstantsType extends AbstractType
{
    public function getParent(): string
    {
        return ChoiceType::class;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            // the example below will create a CallbackChoiceLoader from the callable
            'choice_loader' => ChoiceList::lazy($this, function () {
                return StaticClass::getConstants();
            }),

            // you can pass your own loader as well, depending on other options
            'some_key' => null,
            'choice_loader' => function (Options $options): ChoiceLoaderInterface {
                return ChoiceList::loader(
                    // pass the instance of the type or type extension which is
                    // currently configuring the choice list as first argument
                    $this,
                    // pass the other option to the loader
                    new CustomChoiceLoader($options['some_key']),
                    // ensure the type stores a loader per key
                    // by using the special third argument "$vary"
                    // an array containing anything that "changes" the loader
                    [$options['some_key']]
                );
            },
        ]);
    }
}

choice_lazy

類型boolean 預設值false

7.2

choice_lazy 選項在 Symfony 7.2 中引入。

choice_lazy 選項在處理大量選項時特別有用,因為一次載入所有選項可能會導致效能問題或延遲

1
2
3
4
5
6
7
use App\Entity\User;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;

$builder->add('user', EntityType::class, [
    'class' => User::class,
    'choice_lazy' => true,
]);

當設定為 true 並與 choice_loader 選項一起使用時,表單將僅載入和呈現預設值或提交值中預設的選項。這會延遲載入完整選項列表,有助於提高表單的效能。

警告

請記住,當使用 choice_lazy 時,您有責任為選擇選項提供使用者介面,通常透過能夠動態載入選項的 JavaScript 外掛程式。

choice_name

類型callablestringPropertyPath 預設值null

控制選項的內部欄位名稱。您通常不關心這個,但在某些進階情況下,您可能會關心。例如,此「名稱」會變成範本中選項檢視的索引,並用作欄位名稱屬性的一部分。

這可以是可呼叫物件或屬性路徑。有關類似用法,請參閱 choice_label。預設情況下,可以使用選項鍵或遞增整數 (從 0 開始)。

提示

當定義自訂類型時,您應該使用 ChoiceList 類別協助程式

1
2
3
4
5
6
use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
    'choice_name' => ChoiceList::fieldName($this, 'name'),
]);

請參閱 「choice_loader」選項文件

警告

設定的值必須是有效的表單名稱。使用可呼叫物件時,請確保僅傳回有效的名稱。有效的表單名稱必須由字母、數字、底線、破折號和冒號組成,並且不得以破折號或冒號開頭。

choice_translation_domain

類型stringbooleannull 預設值true

此選項決定是否應翻譯選項值以及在哪個翻譯網域中翻譯。

choice_translation_domain 選項的值可以是 true (重複使用目前的翻譯網域)、false (停用翻譯)、null (使用父翻譯網域或預設網域) 或表示要使用的確切翻譯網域的字串。

choice_translation_parameters

類型arraycallablestringPropertyPath 預設值[]

選項值會在顯示之前翻譯,因此它可以包含 翻譯佔位符。此選項定義用於取代這些佔位符的值。這可以是關聯陣列,其中鍵與選項鍵匹配,值是每個選項的屬性,也可以是可呼叫或屬性路徑 (就像 choice_label 一樣)。

給定此翻譯訊息

1
2
3
# translations/messages.en.yaml
form.order.yes: 'I confirm my order to the company %company%'
form.order.no: 'I cancel my order'

您可以如下指定佔位符值

1
2
3
4
5
6
7
8
9
10
11
12
13
$builder->add('id', null, [
    'choices' => [
        'form.order.yes' => true,
        'form.order.no' => false,
    ],
    'choice_translation_parameters' => function ($choice, string $key, mixed $value): array {
        if (false === $choice) {
            return [];
        }

        return ['%company%' => 'ACME Inc.'];
    },
]);

如果是陣列,則必須將 choices 陣列的鍵用作鍵

1
2
3
4
5
6
7
8
9
10
$builder->add('id', null, [
    'choices' => [
        'form.order.yes' => true,
        'form.order.no' => false,
    ],
    'choice_translation_parameters' => [
        'form.order.yes' => ['%company%' => 'ACME Inc.'],
        'form.order.no' => [],
    ],
]);

子欄位的翻譯參數會與其父欄位的相同選項合併,因此子欄位可以重複使用和/或覆寫任何父佔位符。

choice_value

類型callablestringPropertyPath 預設值null

針對每個選項傳回字串「value」,這在所有選項中必須是唯一的。這在 HTML 中的 value 屬性中使用,並在 POST/PUT 請求中提交。您通常不需要擔心這個,但在處理 API 請求時可能會很方便 (因為您可以設定將在 API 請求中傳送的值)。

這可以是可呼叫物件或屬性路徑。預設情況下,如果選項可以轉換為字串,則會使用選項。否則,將使用遞增整數 (從 0 開始)。

如果您傳遞可呼叫物件,它將接收一個引數:選項本身。當使用 EntityType 欄位時,引數將是每個選項的實體物件,如果使用佔位符,則為 null,您需要處理它

1
2
3
'choice_value' => function (?MyOptionEntity $entity): string {
    return $entity ? $entity->getId() : '';
},

提示

當定義自訂類型時,您應該使用 ChoiceList 類別協助程式

1
2
3
4
5
6
use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
    'choice_value' => ChoiceList::value($this, 'uuid'),
]);

請參閱 「choice_loader」選項文件

duplicate_preferred_choices

類型boolean 預設值true

當使用 preferred_choices 選項時,這些偏好選項預設會顯示兩次:在列表的頂部和下面的完整列表中。將此選項設定為 false,僅在列表頂部顯示偏好選項

1
2
3
4
5
6
7
8
9
10
11
12
13
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('language', ChoiceType::class, [
    'choices' => [
        'English' => 'en',
        'Spanish' => 'es',
        'Bork' => 'muppets',
        'Pirate' => 'arr',
    ],
    'preferred_choices' => ['muppets', 'arr'],
    'duplicate_preferred_choices' => false,
]);

expanded

類型boolean 預設值false

如果設定為 true,將會呈現單選按鈕或複選框 (取決於 multiple 值)。如果為 false,將會呈現 select 元素。

group_by

類型stringcallablePropertyPath 預設值null

您可以透過將多維陣列傳遞給 choices,將 <select><option> 元素分組到 <optgroup> 中。請參閱有關此內容的 群組選項 章節。

group_by 選項是群組選項的替代方法,它為您提供更大的彈性。

以下列範例為例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('publishAt', ChoiceType::class, [
    'choices' => [
        'now' => new \DateTime('now'),
        'tomorrow' => new \DateTime('+1 day'),
        '1 week' => new \DateTime('+1 week'),
        '1 month' => new \DateTime('+1 month'),
    ],
    'group_by' => function($choice, $key, $value) {
        if ($choice <= new \DateTime('+3 days')) {
            return 'Soon';
        }

        return 'Later';
    },
]);

這會將 3 天內的日期分組到「Soon」中,並將所有其他日期分組到「Later」<optgroup>

A choice list with "now" and "tomorrow" grouped under "Soon", and "1 week" and "1 month" grouped under "Later".

如果您傳回 null,則選項將不會分組。您也可以傳遞將被呼叫以取得群組的字串「屬性路徑」。有關使用屬性路徑的詳細資訊,請參閱 choice_label

提示

當定義自訂類型時,您應該使用 ChoiceList 類別協助程式

1
2
3
4
5
6
use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
    'group_by' => ChoiceList::groupBy($this, 'category'),
]);

請參閱 「choice_loader」選項文件

multiple

類型boolean 預設值false

如果為 true,使用者將能夠選擇多個選項 (而不是僅選擇一個選項)。根據 expanded 選項的值,如果為 true,這將呈現 select 標籤或複選框,如果為 false,則呈現 select 標籤或單選按鈕。傳回的值將會是一個陣列。

placeholder

類型stringTranslatableMessageboolean

此選項決定是否在 select 小工具的頂部顯示特殊的「空」選項 (例如「選擇一個選項」)。此選項僅在 multiple 選項設定為 false 時適用。

  • 新增一個空值,文字為「選擇一個選項」

    1
    2
    3
    4
    5
    6
    7
    8
    9
    use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
    // ...
    
    $builder->add('states', ChoiceType::class, [
        'placeholder' => 'Choose an option',
    
        // or if you want to translate the text
        'placeholder' => new TranslatableMessage('form.placeholder.select_option', [], 'form'),
    ]);
  • 保證不會顯示「空」值選項

    1
    2
    3
    4
    5
    6
    use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
    // ...
    
    $builder->add('states', ChoiceType::class, [
        'placeholder' => false,
    ]);

如果您將 placeholder 選項設定為未設定,則僅當 required 選項為 false 時,才會自動新增空白 (沒有文字) 選項

1
2
3
4
5
6
7
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

// a blank (with no text) option will be added
$builder->add('states', ChoiceType::class, [
    'required' => false,
]);

placeholder_attr

類型array 預設值[]

使用此選項可為佔位符選項新增額外的 HTML 屬性

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('fruits', ChoiceType::class, [
    // ...
    'placeholder' => '...',
    'placeholder_attr' => [
        ['title' => 'Choose an option'],
    ],
]);

preferred_choices

類型arraycallablestringPropertyPath 預設值[]

此選項可讓您在列表頂端顯示特定選項,並在這些選項與完整選項列表之間加上視覺分隔線。如果您有一個語言表單,您可以將最常用的語言列在頂端,例如 Bork 和 Pirate。

1
2
3
4
5
6
7
8
9
10
11
12
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('language', ChoiceType::class, [
    'choices' => [
        'English' => 'en',
        'Spanish' => 'es',
        'Bork' => 'muppets',
        'Pirate' => 'arr',
    ],
    'preferred_choices' => ['muppets', 'arr'],
]);

此選項也可以是一個回呼函數,讓您有更大的彈性。如果您的值是物件,這可能會特別有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('publishAt', ChoiceType::class, [
    'choices' => [
        'now' => new \DateTime('now'),
        'tomorrow' => new \DateTime('+1 day'),
        '1 week' => new \DateTime('+1 week'),
        '1 month' => new \DateTime('+1 month'),
    ],
    'preferred_choices' => function ($choice, $key, $value): bool {
        // prefer options within 3 days
        return $choice <= new \DateTime('+3 days');
    },
]);

這將「偏好」僅顯示「now」和「tomorrow」選項。

A choice list with "now" and "tomorrow" on top, separated by a line from "1 week" and "1 month".

最後,如果您的值是物件,您也可以在物件上指定一個屬性路徑字串,該字串將傳回 true 或 false。

偏好選項僅在呈現 select 元素時才有意義(即 expanded 為 false)。偏好選項和一般選項在視覺上以一組虛線分隔(即 -------------------)。這可以在呈現欄位時進行自訂。

1
{{ form_widget(form.publishAt, { 'separator': '=====' }) }}

提示

當定義自訂類型時,您應該使用 ChoiceList 類別協助程式

1
2
3
4
5
6
use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
    'preferred_choices' => ChoiceList::preferred($this, 'taggedAsFavorite'),
]);

請參閱 「choice_loader」選項文件

separator

type: string default: -------------------

此選項可讓您自訂在偏好選項之後顯示的視覺分隔線。您可以使用 HTML 元素,例如 <hr> 來顯示更現代的分隔線,但您也需要將 separator_html 選項設定為 true

7.1

separator 選項在 Symfony 7.1 中引入。

separator_html

類型boolean 預設值false

如果此選項為 true,則 separator 選項將顯示為 HTML 而不是文字。當使用 HTML 元素(例如 <hr>)作為更現代的視覺分隔線時,這非常有用。

7.1

separator_html 選項在 Symfony 7.1 中引入。

覆寫的選項

compound

type: boolean default: 與 expanded 選項的值相同

此選項指定表單是否為複合式。預設情況下,該值會被 expanded 選項的值覆寫。

empty_data

type: mixed

此選項的實際預設值取決於其他欄位選項。

  • 如果 multiplefalseexpandedfalse,則為 '' (空字串);
  • 否則為 [] (空陣列)。

此選項決定當提交的值為空(或遺失)時,欄位將傳回的值。如果視圖中呈現表單時未提供初始值,則此選項不會設定初始值。

這表示它可以幫助您處理具有空白欄位的表單提交。例如,如果您希望在未選取任何值時,將 name 欄位明確設定為 John Doe,您可以這樣做:

1
2
3
4
$builder->add('name', null, [
    'required'   => false,
    'empty_data' => 'John Doe',
]);

這仍然會呈現一個空白文字方塊,但在提交時,將會設定 John Doe 值。使用 dataplaceholder 選項在呈現的表單中顯示此初始值。

注意

如果表單是複合式,您可以將 empty_data 設定為陣列、物件或閉包。可以為整個表單類別設定此選項,請參閱如何為表單類別設定空資料文章,以取得有關這些選項的更多詳細資訊。

警告

表單資料轉換器仍將應用於 empty_data 值。這表示空字串將被轉換為 null。如果您明確想要傳回空字串,請使用自訂資料轉換器。

error_bubbling

類型boolean 預設值false

設定此欄位的錯誤必須附加到該欄位,而不是父欄位(在大多數情況下為表單)。

trim

類型boolean 預設值false

預設情況下停用修剪,因為選取的值或多個值必須與給定的選項值完全匹配(並且它們可能包含空格)。

invalid_message

type: string default: This value is not valid

這是驗證錯誤訊息,當輸入到此欄位的資料沒有意義(即驗證失敗)時使用。

例如,如果使用者在 TimeType 欄位中輸入無法轉換為真實時間的無意義字串,或者如果使用者在數字欄位中輸入字串(例如 apple),則可能會發生這種情況。

正常的(業務邏輯)驗證(例如,設定欄位的最小長度)應使用驗證規則的驗證訊息來設定(參考)。

繼承的選項

這些選項繼承自 FormType

attr

類型array 預設值[]

如果您想將額外的屬性新增至 HTML 欄位表示,您可以使用 attr 選項。它是一個關聯陣列,HTML 屬性作為鍵。當您需要為某些小工具設定自訂類別時,這可能很有用。

1
2
3
$builder->add('body', TextareaType::class, [
    'attr' => ['class' => 'tinymce'],
]);

另請參閱

如果您想將這些屬性新增至表單類型列元素,請使用 row_attr 選項。

by_reference

類型boolean 預設值true

在大多數情況下,如果您有一個 author 欄位,那麼您期望在底層物件上呼叫 setAuthor()。但是,在某些情況下,可能不會呼叫 setAuthor()。將 by_reference 設定為 false 可確保在所有情況下都呼叫 setter。

為了進一步解釋這一點,這是一個簡單的範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
// ...

$builder = $this->createFormBuilder($article);
$builder
    ->add('title', TextType::class)
    ->add(
        $builder->create('author', FormType::class, ['by_reference' => ?])
            ->add('name', TextType::class)
            ->add('email', EmailType::class)
    )

如果 by_reference 為 true,當您在表單上呼叫 submit()(或 handleRequest())時,幕後會發生以下情況:

1
2
3
$article->setTitle('...');
$article->getAuthor()->setName('...');
$article->getAuthor()->setEmail('...');

請注意,未呼叫 setAuthor()。作者是透過引用修改的。

如果您將 by_reference 設定為 false,則提交看起來像這樣:

1
2
3
4
5
$article->setTitle('...');
$author = clone $article->getAuthor();
$author->setName('...');
$author->setEmail('...');
$article->setAuthor($author);

因此,by_reference=false 真正做的就是複製物件,這會強制框架在父物件上呼叫 setter。

同樣地,如果您正在使用 CollectionType 欄位,其中您的底層集合資料是一個物件(例如 Doctrine 的 ArrayCollection),那麼如果您需要呼叫 adder 和 remover(例如 addAuthor()removeAuthor()),則必須將 by_reference 設定為 false

data

type: mixed default: 預設為底層結構的欄位。

當您建立表單時,每個欄位最初都會顯示表單網域資料的對應屬性值(例如,如果您將物件繫結到表單)。如果您想覆寫表單或個別欄位的此初始值,您可以在 data 選項中設定它。

1
2
3
4
5
6
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
// ...

$builder->add('token', HiddenType::class, [
    'data' => 'abcdef',
]);

警告

呈現時,data 選項總是會覆寫從網域資料(物件)取得的值。這表示當表單編輯已持久化的物件時,物件值也會被覆寫,導致它在提交表單時遺失其持久化的值。

disabled

類型boolean 預設值false

如果您不希望使用者修改欄位的值,您可以將 disabled 選項設定為 true。任何提交的值都將被忽略。

error_mapping

類型array 預設值[]

此選項可讓您修改驗證錯誤的目標。

假設您有一個名為 matchingCityAndZipCode() 的自訂方法,用於驗證城市和郵遞區號是否匹配。不幸的是,您的表單中沒有 matchingCityAndZipCode 欄位,因此 Symfony 所能做的就是在表單頂端顯示錯誤。

透過自訂錯誤映射,您可以做得更好:將錯誤映射到城市欄位,使其顯示在其上方。

1
2
3
4
5
6
7
8
public function configureOptions(OptionsResolver $resolver): void
{
    $resolver->setDefaults([
        'error_mapping' => [
            'matchingCityAndZipCode' => 'city',
        ],
    ]);
}

以下是映射左右兩側的規則:

  • 左側包含屬性路徑;
  • 如果違規是在類別的屬性或方法上產生的,則其路徑為 propertyName
  • 如果違規是在 arrayArrayAccess 物件的項目上產生的,則屬性路徑為 [indexName]
  • 您可以透過串連屬性路徑來建構巢狀屬性路徑,並以點分隔屬性。例如:addresses[work].matchingCityAndZipCode
  • 右側包含表單中欄位的名稱。

預設情況下,任何未映射屬性的錯誤都會冒泡到父表單。您可以使用點 (.) 在左側將所有未映射屬性的錯誤映射到特定欄位。例如,若要將所有這些錯誤映射到 city 欄位,請使用:

1
2
3
4
5
$resolver->setDefaults([
    'error_mapping' => [
        '.' => 'city',
    ],
]);

help

type: stringTranslatableInterface default: null

允許您為表單欄位定義說明訊息,預設情況下,說明訊息會呈現在欄位下方。

1
2
3
4
5
6
7
8
9
10
11
12
13
use Symfony\Component\Translation\TranslatableMessage;

$builder
    ->add('zipCode', null, [
        'help' => 'The ZIP/Postal code for your credit card\'s billing address.',
    ])

    // ...

    ->add('status', null, [
        'help' => new TranslatableMessage('order.status', ['%order_id%' => $order->getId()], 'store'),
    ])
;

help_attr

類型array 預設值[]

設定用於顯示表單欄位說明訊息的元素的 HTML 屬性。其值是一個關聯陣列,HTML 屬性名稱作為鍵。這些屬性也可以在範本中設定。

1
2
3
{{ form_help(form.name, 'Your name', {
    'help_attr': {'class': 'CUSTOM_LABEL_CLASS'}
}) }}

help_html

類型boolean 預設值false

預設情況下,在範本中呈現 help 選項的內容之前,會先對其進行跳脫。將此選項設定為 true 以不跳脫它們,當說明包含 HTML 元素時,這非常有用。

inherit_data

類型boolean 預設值false

此選項決定表單是否將從其父表單繼承資料。如果您有一組跨多個表單重複的欄位,這可能會很有用。請參閱 如何使用 "inherit_data" 減少程式碼重複

警告

當欄位設定了 inherit_data 選項時,它會按原樣使用父表單的資料。這表示 資料轉換器將不會應用於該欄位。

label

type: stringTranslatableMessage default: 標籤是從欄位名稱「猜測」出來的。

設定呈現欄位時將使用的標籤。設定為 false 將會抑制標籤。

1
2
3
4
5
6
7
8
use Symfony\Component\Translation\TranslatableMessage;

$builder
    ->add('zipCode', null, [
        'label' => 'The ZIP/Postal code',
        // optionally, you can use TranslatableMessage objects as the label content
        'label' => new TranslatableMessage('address.zipCode', ['%country%' => $country], 'address'),
    ])

標籤也可以在範本中設定。

1
{{ form_label(form.name, 'Your name') }}

label_attr

類型array 預設值[]

設定 <label> 元素的 HTML 屬性,當呈現欄位的標籤時將會使用它。它是一個關聯陣列,HTML 屬性作為鍵。這些屬性也可以直接在範本內設定。

1
2
3
{{ form_label(form.name, 'Your name', {
    'label_attr': {'class': 'CUSTOM_LABEL_CLASS'}
}) }}

label_html

類型boolean 預設值false

預設情況下,在範本中呈現 label 選項的內容之前,會先對其進行跳脫。將此選項設定為 true 以不跳脫它們,當標籤包含 HTML 元素時,這非常有用。

label_format

type: string default: null

配置用作欄位標籤的字串,以防未設定 label 選項。當使用關鍵字翻譯訊息時,這非常有用。

如果您正在使用關鍵字翻譯訊息作為標籤,您通常會為同一個標籤擁有多個關鍵字訊息(例如,profile_address_streetinvoice_address_street)。這是因為標籤是為欄位的每個「路徑」建構的。為了避免重複的關鍵字訊息,您可以將標籤格式配置為靜態值,例如:

1
2
3
4
5
6
7
8
// ...
$profileFormBuilder->add('address', AddressType::class, [
    'label_format' => 'form.address.%name%',
]);

$invoiceFormBuilder->add('invoice', AddressType::class, [
    'label_format' => 'form.address.%name%',
]);

此選項由子類型繼承。使用上面的程式碼,兩個表單的 street 欄位的標籤都將使用 form.address.street 關鍵字訊息。

標籤格式中有兩個變數可用:

%id%
欄位的唯一識別碼,包含欄位的完整路徑和欄位名稱(例如,profile_address_street);
%name%
欄位名稱(例如,street)。

預設值 (null) 會產生欄位名稱的 「人性化」版本

注意

label_format 選項在表單主題中評估。如果您自訂表單主題,請確保更新您的範本。

mapped

類型boolean 預設值true

如果您希望在讀取或寫入物件時忽略該欄位,您可以將 mapped 選項設定為 false

required

類型boolean 預設值true

如果為 true,將會呈現 HTML5 required 屬性。對應的 label 也將以 required 類別呈現。

這是表面上的,並且獨立於驗證。在最好的情況下,如果您讓 Symfony 猜測您的欄位類型,那麼此選項的值將會從您的驗證資訊中猜測出來。

注意

required 選項也會影響每個欄位的空資料處理方式。如需更多詳細資訊,請參閱 empty_data 選項。

row_attr

類型array 預設值[]

新增至用於呈現表單類型列的元素的 HTML 屬性關聯陣列。

1
2
3
$builder->add('body', TextareaType::class, [
    'row_attr' => ['class' => 'text-editor', 'id' => '...'],
]);

另請參閱

如果您想將這些屬性新增至表單類型小工具元素,請使用 attr 選項。

translation_domain

type: string default: messages

如果 choice_translation_domain 設定為 truenull,則這會配置將用於此欄位呈現的任何標籤或選項的確切翻譯網域。

label_translation_parameters

類型array 預設值[]

label 選項的內容在顯示之前會先翻譯,因此它可以包含翻譯預留位置。此選項定義用於取代這些預留位置的值。

給定此翻譯訊息

1
2
# translations/messages.en.yaml
form.order.id: 'Identifier of the order to %company%'

您可以如下指定佔位符值

1
2
3
4
5
6
$builder->add('id', null, [
    'label' => 'form.order.id',
    'label_translation_parameters' => [
        '%company%' => 'ACME Inc.',
    ],
]);

子欄位的 label_translation_parameters 選項與其父欄位的相同選項合併,因此子欄位可以重複使用和/或覆寫任何父預留位置。

attr_translation_parameters

類型array 預設值[]

attr 選項中定義的 titleplaceholder 值的內容在顯示之前會先翻譯,因此它可以包含翻譯預留位置。此選項定義用於取代這些預留位置的值。

給定此翻譯訊息

1
2
3
# translations/messages.en.yaml
form.order.id.placeholder: 'Enter unique identifier of the order to %company%'
form.order.id.title: 'This will be the reference in communications with %company%'

您可以如下指定佔位符值

1
2
3
4
5
6
7
8
9
$builder->add('id', null, [
    'attr' => [
        'placeholder' => 'form.order.id.placeholder',
        'title' => 'form.order.id.title',
    ],
    'attr_translation_parameters' => [
        '%company%' => 'ACME Inc.',
    ],
]);

子欄位的 attr_translation_parameters 選項與其父欄位的相同選項合併,因此子欄位可以重複使用和/或覆寫任何父預留位置。

help_translation_parameters

類型array 預設值[]

help 選項的內容在顯示之前會先翻譯,因此它可以包含翻譯預留位置。此選項定義用於取代這些預留位置的值。

給定此翻譯訊息

1
2
# translations/messages.en.yaml
form.order.id.help: 'This will be the reference in communications with %company%'

您可以如下指定佔位符值

1
2
3
4
5
6
$builder->add('id', null, [
    'help' => 'form.order.id.help',
    'help_translation_parameters' => [
        '%company%' => 'ACME Inc.',
    ],
]);

子欄位的 help_translation_parameters 選項與其父欄位的相同選項合併,因此子欄位可以重複使用和/或覆寫任何父預留位置。

欄位變數

變數 類型 用法
multiple boolean multiple 選項的值。
expanded boolean expanded 選項的值。
preferred_choices array 一個巢狀陣列,包含應優先呈現給使用者的選項的 ChoiceView 物件。
choices array 一個巢狀陣列,包含剩餘選項的 ChoiceView 物件。
separator string 在選項群組之間使用的分隔符號。
placeholder mixed 如果空值尚未在列表中,則為空值,否則為 null
placeholder_attr array placeholder_attr 選項的值。
choice_translation_domain mixed booleannullstring,以判斷是否應翻譯該值。
is_selected callable 一個可呼叫的物件,它接受一個 ChoiceView 和選取的值,並傳回選項是否在選取的值中。
placeholder_in_choices boolean 空值是否在選項列表中。

提示

在 Twig 範本中,與其使用 is_selected(),不如使用 selectedchoice 測試,速度明顯更快。

存取表單選項資料

每個選項項目的 form.vars 變數都包含諸如選項是否被選取之類的資料。如果您需要取得選項資料和值的完整列表,請使用選項項目的父表單(即 ChoiceType 本身)中的 choices 變數,並搭配 form.parent.vars.choices

1
2
3
4
5
6
7
8
{# `true` or `false`, whether the current choice is selected as radio or checkbox #}
{{ form.vars.data }}

{# the current choice value (i.e a category name when `'choice_value' => 'name'` #}
{{ form.vars.value }}

{# a map of `ChoiceView` or `ChoiceGroupView` instances indexed by choice values or group names #}
{{ form.parent.vars.choices }}

依照與上面相同的高階範例(其中選項值是實體),Category 物件位於 form.parent.vars.choices[key].data 內部。

1
2
3
4
5
6
7
8
9
10
11
{% block _form_categories_entry_widget %}
    {% set entity = form.parent.vars.choices[form.vars.value].data %}

    <tr>
        <td>{{ form_widget(form) }}</td>
        <td>{{ form.vars.label }}</td>
        <td>
            {{ entity.name }} | {{ entity.group }}
        </td>
    </tr>
{% endblock %}
本作品,包括程式碼範例,根據 Creative Commons BY-SA 3.0 授權條款授權。
TOC
    版本