Symfony 自定义表单约束将错误写入父表单
Symfony custom form constraint writes error to parent form
我在 Symfony 中创建了自定义表单类型和约束。
约束附加到这样的表单类型:
->add('customField', 'customField', array(
'required' =>
'mapped' => false,
'constraints' => array(new CustomField()),
))
其中 CustomField 是约束 class。
约束验证器的 validate() 方法如下所示:
public function validate($value, Constraint $constraint)
{
//I know this will always fail, but it's just for illustration purposes
$this->context->addViolation($constraint->message);
}
我已经像这样更改了表单的默认模板:
{% block form_row -%}
<div class="form-group">
{{- form_widget(form) -}}
{{- form_errors(form) -}}
</div>
{%- endblock form_row %}
{% block customField_widget %}
{% spaceless %}
<!-- actually different but you get the idea -->
<input type="text" name="customField" id="customField" />
{% endspaceless %}
{% endblock %}
{% block form_errors -%}
{% if errors|length > 0 -%}
{%- for error in errors -%}
<small class="help-block">
{{ error.message }}
</small>
{%- endfor -%}
{%- endif %}
{%- endblock form_errors %}
并且在显示表单的模板中,我添加了一些代码来显示附加到整个表单的错误而不是单个字段错误:
{{ form_start(formAdd) }}
{% if formAdd.vars.valid is same as(false) -%}
<div class="alert alert-danger">
<strong>Errors!</strong> Please correct the errors indicated below.
{% if formAdd.vars.errors %}
<ul>
{% for error in formAdd.vars.errors %}
<li>
{{ error.getMessage() }}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{%- endif %}
...
所有这一切的问题,这个特定字段的验证器,是将约束违规附加到表单对象而不是 customField 表单类型。这会导致错误最终与表单的一般错误一起显示,而不是显示为字段错误。
现在,这不是我添加的唯一自定义表单类型和验证器,但它是唯一显示此行为的,而我无法识别这一个和其他之间的区别。你能看出这里有什么问题吗?
你必须specify path in your validator:
$this->context
->buildViolation($constraint->message)
->atPath('customField')
->addViolation();
我自己解决了这个问题。它与约束或验证器无关。问题出在自定义表单类型(我没有在我的问题中描述)。问题是这个表单类型有 "form" 作为复合类型的父级。这意味着默认情况下(根据 docs),错误冒泡也是真的,这反过来意味着 "any errors for that field will be attached to the main form, not to the specific field".
您必须在自定义表单类型中将 'error_bubbling' 设置为 false
class CustomFieldType extends AbstractType
{
public function getName()
{
return 'customField';
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('error_bubbling', false);
}
}
我在 Symfony 中创建了自定义表单类型和约束。
约束附加到这样的表单类型:
->add('customField', 'customField', array(
'required' =>
'mapped' => false,
'constraints' => array(new CustomField()),
))
其中 CustomField 是约束 class。
约束验证器的 validate() 方法如下所示:
public function validate($value, Constraint $constraint)
{
//I know this will always fail, but it's just for illustration purposes
$this->context->addViolation($constraint->message);
}
我已经像这样更改了表单的默认模板:
{% block form_row -%}
<div class="form-group">
{{- form_widget(form) -}}
{{- form_errors(form) -}}
</div>
{%- endblock form_row %}
{% block customField_widget %}
{% spaceless %}
<!-- actually different but you get the idea -->
<input type="text" name="customField" id="customField" />
{% endspaceless %}
{% endblock %}
{% block form_errors -%}
{% if errors|length > 0 -%}
{%- for error in errors -%}
<small class="help-block">
{{ error.message }}
</small>
{%- endfor -%}
{%- endif %}
{%- endblock form_errors %}
并且在显示表单的模板中,我添加了一些代码来显示附加到整个表单的错误而不是单个字段错误:
{{ form_start(formAdd) }}
{% if formAdd.vars.valid is same as(false) -%}
<div class="alert alert-danger">
<strong>Errors!</strong> Please correct the errors indicated below.
{% if formAdd.vars.errors %}
<ul>
{% for error in formAdd.vars.errors %}
<li>
{{ error.getMessage() }}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{%- endif %}
...
所有这一切的问题,这个特定字段的验证器,是将约束违规附加到表单对象而不是 customField 表单类型。这会导致错误最终与表单的一般错误一起显示,而不是显示为字段错误。
现在,这不是我添加的唯一自定义表单类型和验证器,但它是唯一显示此行为的,而我无法识别这一个和其他之间的区别。你能看出这里有什么问题吗?
你必须specify path in your validator:
$this->context
->buildViolation($constraint->message)
->atPath('customField')
->addViolation();
我自己解决了这个问题。它与约束或验证器无关。问题出在自定义表单类型(我没有在我的问题中描述)。问题是这个表单类型有 "form" 作为复合类型的父级。这意味着默认情况下(根据 docs),错误冒泡也是真的,这反过来意味着 "any errors for that field will be attached to the main form, not to the specific field".
您必须在自定义表单类型中将 'error_bubbling' 设置为 false
class CustomFieldType extends AbstractType
{
public function getName()
{
return 'customField';
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('error_bubbling', false);
}
}