我希望能够动态设置表单字段的
required=true/false
选项或 array(...other stuff..., 'class' => ' hidden')
。
上下文如下:有一个带有一些字段的“项目”实体。当我使用表单创建其他实体时,我想检查项目实体的某些属性,并就我正在创建的实体的某些字段的可见性/必需性做出决策。
例如,如果项目具有属性“timePressure=high”,则不需要给定实体的字段(但可见)。如果有其他条件它就会变得不可见等等...
所以基本上我希望在表单生成器的每个
->add()
中调用一个函数来吐出相关部分(例如,该函数将返回一个带有“required=true”的字符串或与隐藏类相关的其他字符串)。问题是该函数应该作为参数:projectID(好的,这可以作为表单构建器的选项传递)、我们正在讨论的类和字段来决定。我正在设想类似的事情:
->add('background', 'textarea', array('attr' => array('rows' => 4, functionToDecideIfInvisible($projectId)), functionToDecideRequiredness($projectId)))
这两个函数将返回字符串
'class' => ' hidden'
和 required=true
(或 false)
我想避免指定字段名称(在本例中为
background
)以避免代码重复。
这可以吗?
关于如何解决问题的其他建议?
谢谢!
SN
它们允许您根据您的数据修改表单。
您在控制器中创建项目表单:
$form = $this->createForm(new ProjectType(), $project, array(
'action' => $this->generateUrl('project.edit'),
'method' => 'POST',
));
然后添加 FormEvents::PRE_SET_DATA 监听器:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$project = $event->getData();
$form = $event->getForm();
// check timePressure on the Project object
if ('high' === $project->timePressure) {
$form->add('timePressure', 'text', array(
'required' => false
);
}
});
}
我找到了一种方法。
我的添加如下:
->add('background', 'textarea', array_merge($this->vr->fieldReq(get_class($this),
'background', $projectID), array('attr' => array_merge(array('rows' => 4, ),
$this->vr->fieldCssClass(get_class($this), 'background', $projectID) ) )))
为此,我必须将表单定义为服务,另外我创建了另一个类作为服务(包含我需要的两种方法的类)。
这是班级:
class FieldReqAndCssClass
{
public function fieldReq($parentEntity, $field, $projectID)
{
$required = array();
$required['required'] = false; //do stuff on the database instead of setting it to false hardcoded
return $required;
}
public function fieldCssClass($parentEntity, $field, $projectID)
{
$cssClass= array();
//do stuff on the database instead of setting the class as hidden hardcoded
//$cssClass['class'] = ' hidden';
$cssClass['class'] = '';
return $cssClass;
}
}
当然,以我的形式,我必须:
public function __construct(\AppBundle\Util\FieldReqAndCssClass $fieldReqAndCssClass)
{
$this->vr = $fieldReqAndCssClass; // vr stands for visibility and requiredness
}
这是两项服务:
app_bundle.field_req_and_css_class:
class: AppBundle\Util\FieldReqAndCssClass
arguments: []
app_bundle.form.type.projectdetail:
class: AppBundle\Form\Type\ProjectDetailFormType
arguments: [@app_bundle.field_req_and_css_class]
tags:
- { name: form.type, alias: ProjectDetail }
当然,在第一个服务中,我需要注入实体管理器并将其添加到构造中,也可能在表单服务中,但基本框架正在工作:)
我是一个快乐的人:)
编辑 上面的唯一问题是它隐藏了小部件而不是标签。要修复它:
->add('background', 'textarea', array_merge($vr->fieldReq($myClass,
'background', $project), array('label_attr' => $vr->fieldCssClass($myClass,
'background', $project),'attr' => array_merge(array('rows' => 4, ),
$vr->fieldCssClass($myClass, 'background', $project) ) )))
显然在我必须声明之前:
$myClass = get_class($this);
$vr = $this->vr;