本文作者为表单组件的team leader:@webmozart
个人主页 https://webmozart.io

Choice表单类型是Symfony表单类型中最为先进的。同时它还是最为重要的类型之一,因为有大量其他类型在继承它,例如EntityTypeCountryTypeLocaleType

在Symfony 2.7中,这个表单类型已经被彻底重制,为的是动态生成labels,values,indexes和attributes。之所以成为可能,还要感谢全新选项choice_labelchoice_namechoice_valuechoice_attrgroup_bychoices_as_values

动态生成choice标签 

默认情况是,把choices数组的键,作为labels,但你也可以传一个回调到choice_label选项中,用于动态地生成它们:

1
2
3
4
5
6
7
8
9
10
11
$builder->add('attending', 'choice', array(
    'choices' => array(
        'yes' => true,
        'no' => false,
        'maybe' => null,
    ),
    'choices_as_values' => true,
    'choice_label' => function ($allChoices, $currentChoiceKey) {
        return 'form.choice.'.$currentChoiceKey;
    },
));

若不用callable,你可以把属性名传入,作为label:

1
2
3
4
5
6
7
8
9
$builder->add('attending', 'choice', array(
    'choices' => array(
        Status::getInstance(Status::YES),
        Status::getInstance(Status::NO),
        Status::getInstance(Status::MAYBE),
    ),
    'choices_as_values' => true,
    'choice_label' => 'displayName',
));

动态生成choice names和values 

使用choice_name选项,可以为每个choice生成name,使用choice_value选项,则可以生成它们的字符串值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$builder->add('attending', 'choice', array(
    'choices' => array(
        'Yes' => true,
        'No' => false,
        'Maybe' => null,
    ),
    'choices_as_values' => true,
    'choice_name' => function ($allChoices, $currentChoiceKey) {
        // use the labels as names
        return strtolower($currentChoiceKey);
    },
    'choice_value' => function ($allChoices, $currentChoiceKey) {
        if (null === $currentChoiceKey) {
            return 'null';
        }
 
        if (true === $currentChoiceKey) {
            return 'true';
        }
 
        return 'false';
    },
));

若不用回调,这些选项你也可以直接使用属性的name。

动态生成choice属性 

choice_attr定义的是所有附加的HTML属性,应用于每个choice中。这个选项,允许定义其值为一个简单数组,很适合设置简单的choices:

1
2
3
4
5
6
7
8
9
10
11
$builder->add('attending', 'choice', array(
    'choices' => array(
        'Yes' => true,
        'No' => false,
        'Maybe' => null,
    ),
    'choices_as_values' => true,
    'choice_attr' => array(
        'Maybe' => array('class' => 'text-muted'),
    ),
));

当使用更复杂的choices时,还是用回callable比较理想:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$builder->add('attending', 'choice', array(
    'choices' => array(
        'Yes' => true,
        'No' => false,
        'Maybe' => null,
    ),
    'choices_as_values' => true,
    'choice_attr' => function ($allChoices, $currentChoiceKey) {
        if (null === $currentChoiceKey) {
            return array('class' => 'text-muted');
        }
 
        return array();
    },
));

再一次提醒,你可以直接向这选项传入属性的path,来代替数组或回调。

动态生成群组 

默认条件下,choices群组化时,用的是choices选项所提供的同一结构:

1
2
3
4
5
6
7
8
9
10
11
12
$builder->add('attending', 'choice', array(
    'choices' => array(
        'Decided' => array(
            'Yes' => true,
            'No' => false,
        ),
        'Undecided' => array(
            'Maybe' => null,
        ),
    ),
    'choices_as_values' => true,
));

choices的群组能够被动态生成,在group_by选项中使用回调或属性path即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$builder->add('attending', 'choice', array(
    'choices' => array(
        'Yes' => true,
        'No' => false,
        'Maybe' => null,
    ),
    'choices_as_values' => true,
 
    // grouping defined using a callback
    'group_by' => function ($allChoices, $currentChoiceKey) {
        if (null === $currentChoiceKey) {
            return 'Undecided';
        }
 
        return 'Decided';
    },
));

动态生成默认的choices 

最后,生成默认choices,可以在全新的perferred_choices选项中进行定义,可以使用数组、回调或属性path:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$builder->add('attending', 'choice', array(
    'choices' => array(
        'Yes' => true,
        'No' => false,
        'Maybe' => null,
    ),
    'choices_as_values' => true,
 
    // using an array to show the 'true' choice as preferred
    'preferred_choices' => array(true),
 
    // using a callable to show the 'true' choice as preferred
    'preferred_choices' => function ($choice, $key) {
        return true === $choice;
    },
));