似乎有很多可能的方法可以做到这一点,但似乎没有理想。
数组解决方案
使用相同的字符串作为选择值和标签(数组键和值)
// ContactType.php
$builder->add('gender', 'choice', array(
'choices' => array(
'Male' => 'Male',
'Female' => 'Female',
),
));
现在在树枝模板上,例如,确认页可以输出如下:
// show.html.twig
{{ gender }}
PROS:
- 易于实现
- 模板很容易创建,设计师可以理解
cons:
- 如果已提交的表单的数据存储在数据库中,则性别选项将存储为完整字符串
Male
或Female
,而不是机器友好值,例如'm'
或'f'
或0
或1
,似乎不好的编程实践
选择解决方案
为选择选项使用机器友好的值,并创建一个树枝过滤器以在模板中读取这些滤镜。
// GenderChoiceList.php
class GenderChoiceList extends LazyChoiceList
{
protected function loadChoiceList()
{
$choices = array(
0 => 'm',
1 => 'f',
);
$labels = array(
0 => 'Male',
1 => 'Female',
);
return new ChoiceList($choices, $labels);
}
}
// ContactType.php
$builder->add('gender', 'choice', array(
'choice_list' => new GenderChoiceList(),
));
// TwigExtension.php
$filter = new Twig_SimpleFilter('getChoice', function ($value) {
$genderChoiceList = new GenderChoiceList();
$choices = $genderChoiceList->getChoicesForValues(array($value))
return $choices[0];
});
// show.html.twig
{{ gender|getChoice }}
PROS:
- 现在,性别以更明智的格式存储在数据库中
cons:
- 更多的代码,因为它应该是微不足道的
- 模板中使用树枝过滤器的使用对于设计师而言尚不清楚且显而易见
学说解决方案
为选择选项创建相关实体。
// src/AppBundle/Entity/Gender.php
// ...
class Gender
{
/**
* @ORMColumn(type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORMColumn(type="string", length=100)
*/
protected $name;
public function __toString()
{
return $this->name;
}
public function getName()
{
return $this->name;
}
// ...
}
// src/AppBundle/Entity/Contact.php
// ...
class Contact
{
// ...
/**
* @ORMManyToOne(targetEntity="Gender", inversedBy="contacts")
* @ORMJoinColumn(name="gender_id", referencedColumnName="id")
*/
protected $gender;
}
// ContactType.php
$builder->add('gender', 'entity', array(
'class' => 'AppBundle:Gender',
));
// show.html.twig
{{ gender }} or {{ gender.name }}
PROS:
- 性别以更明智的格式存储在数据库中
- 选择也存储在数据库中,这似乎是这种数据的明智场所
- 模板代码简单明了
cons:
- 有很多觉得应该很琐碎的代码
- 呈现模板时,除非编写自定义查询,否则还会有其他数据库调用,这再次是代码
结论问题
有更好的选择吗?简单的东西没有缺点?
更新:
也许这可以在Contact
实体的getGender()
方法中最好地处理。
// Contact.php
class Contact
{
// ...
public function getGender()
{
if (null === $this->gender) {
return $this->gender;
}
$choices = array(
'm' => 'Male',
'f' => 'Female',
);
return $choices[$this->gender];
}
// ...
}
输出完整的字符串Male
或Female
如下:
// show.html.twig
{{ gender }}
我使用chocelist/twigextension方法的原因有两个原因:
- 一般来说,实体不必知道显示逻辑
- 在Twigextension中集中检索逻辑意味着将来很容易将转换应用于您的所有列表
可以轻松地获得选择值,然后定义它们,以便在类型中访问它们:
class GenderChoiceList extends ChoiceList
{
public $keyValues = ['m' => 'Male', 'f' => 'Female'];
public function __construct()
{
parent::__construct(array_keys($this->keyValues), array_values($this->keyValues));
}
}
使您的过滤器或功能了解应检索值的选择形式(我通常使用函数):
class ChoiceTwigExtension extends Twig_Extension
{
public function getFunctions()
{
return [
new Twig_SimpleFunction('choice', array($this, 'choiceFunction'))
];
}
public function choiceFunction($class, $choice)
{
$choiceList = new $class;
return $choiceList->keyValues[$choice];
}
...
在模板中,通过类和标签的键:
{{ choice('Bundle\ChoiceList\GenderChoiceList', gender) }}
所以,类似于Twig的constant
的方式。
说到常数,既然PHP 5.6支持数组consts。
旁边:我喜欢将所有列表作为不同的选择性类别。在项目开始时,这似乎有些过分杀伤,但是随着系统的发展并形成繁殖,生活变得更加轻松。