我正在研究一个名为目标的collection form,用户可以根据需要添加任意数量的目标,这部分工作正常,我可以很好地显示/添加/编辑/删除目标< / p>
我遇到的问题是如何验证数据。在表单上有一个goal target
(整数)字段和saved to date
(整数)字段。
规则是saved to date
的值不能超过goal target
,为此,我创建了custom validation,并且在提交表单时正在挑选该类。
SavedToDate.php
namespace MyBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
class SavedToDate extends Constraint
{
public $message = '"%string%" Saved to date cannot be greater than target date.';
}
SavedToDateValidator.php
namespace MyBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class SavedToDateValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
$values = $this->context->getRoot()->getdata()->getGoals()->getValues();
foreach($values as $item ){
$target = $item->getTarget();
$savedToDate = $item->getReached();
if ($savedToDate > $target) {
$this->context->buildViolation($constraint->message)
->setParameter('%string%', $value)
->addViolation();
}
}
}
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
}
通过阅读symfony文档,我似乎需要在validation.yml
中添加约束Valid。
goals:
- Valid:
问题1
假设我输入的saved to date
大于goal target
对抗第一个目标,而不是仅针对该目标获取错误,我会针对这两个目标获得错误。
问题2
假设我同时针对两个目标saved to date
大于goal target
,那么我会看到针对每个字段的2个错误。
这是我的视图模板
{% for goals in form.goals %}
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
{% if(form_errors(goals.target)) %}
<div class="alert alert-danger" role="alert">{{ form_errors(goals.target) }}</div>
{% endif %}
{% if(form_errors(goals.reached)) %}
<div class="alert alert-danger" role="alert">{{ form_errors(goals.reached) }}</div>
{% endif %}
</div>
</div>
</div>
<div class="row">
<div class="col-xs-2" style="padding-top: 5%">
<label class="" for="exampleInputEmail2">Goal target</label>
<div class="form-group input-group">
{{ form_widget(goals.target, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="col-xs-2" style="padding-top: 5%">
<label class="" for="exampleInputEmail2">Saved to date</label>
<div class="form-group input-group">
{{ form_widget(goals.reached, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="col-xs-2" style="padding-top: 5%">
<label class="" for="exampleInputEmail2">Goal deadline</label>
<div class="form-group input-group">
{{ form_widget(goals.deadline, {'attr': {'class': 'form-control dp'}}) }}
</div>
</div>
<div class="col-xs-2" style="padding-top: 5%">
<label class="" for="exampleInputEmail2">Savings</label>
<div class="form-group input-group">
{{ form_widget(goals.allocated, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
</div>
{% endfor %}
这是我的行动
public function prioritiseGoalsAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
//get user id of currently logged in user
$userId = $this->getUser()->getId();
//get survey object of currently logged in user
$userGoalsInfo = $em->getRepository('MyBundle:survey')->findOneByuserID($userId);
//create the form
$form = $this->createForm(new GoalsType(), $userGoalsInfo);
$form->handleRequest($request);
if ($request->isMethod('POST')) {
if ($form->isValid()) {
$em->persist($userGoalsInfo);
$em->flush();
$this->get('session')->getFlashBag()->add(
'notice',
'Your Goals information has been saved'
);
return $this->render('MyBundle:Default/dashboard:prioritise-my-goals.html.twig', array(
'form' => $form->createView(),
));
}
}
return $this->render('MyBundle:Default/dashboard:prioritise-my-goals.html.twig', array(
'form' => $form->createView(),
));
}
此时我很无能为力,因为我花了好几个小时试图解决这个问题,我将非常感谢你们的帮助。
答案 0 :(得分:2)
这是一个类级别限制,它将针对您从表单中保留的每个目标类实例触发。
因为您为了目标类的每个实例而遍历验证器中的所有对象(为什么?),您将检查所有目标实体,这不是理想的(对于2x实体,您将检查每个实体2x,对于3x实体,您将检查每个实体3x等)。
请注意,此处<$>的$ value是您的类对象,因此无需查看验证程序中的其他实体。
public function validate($value, Constraint $constraint)
您应该编写类似的验证器(我没有检查语法):
class SavedToDateValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
// value should already be an instance of Goal but you could put in a sanity check like
if (!$value instanceof Goal) {
// throw an exception or whatever
}
$target = $value->getTarget();
$savedToDate = $value->getReached();
if ($savedToDate > $target) {
$this->context->buildViolation($constraint->message)
->setParameter('%string%', $value)
->addViolation();
}
}
}
}
的文档
答案 1 :(得分:0)
最后我能够解决问题。
创建自定义验证和时,您需要访问
您需要在整个课程中添加以下代码
Constraint
课程。在我的情况下,这是SavedToDate
我是
在SavedToDateValidator
中添加它是错误的。
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
确保验证错误正确显示
我必须在使用http://www.parallelcodes.com/connect-android-to-ms-sql-database-2/时使用字段
改进自定义validate()
的{{1}}功能
Validator
,感谢@Richard提示。
SavedToDateValidator
上述功能的一个重要部分是public function validate($value, Constraint $constraint)
{
if ($value instanceof Goals) {
$target = $value->getTarget();
$savedToDate = $value->getReached();
if ($savedToDate > $target) {
$this->context->buildViolation($constraint->message)
->setParameter('%goalname%', $value->getName())
->setParameter('%reached%', $value->getReached())
->setParameter('%targetamount%', $value->getTarget())
->atPath('reached')
->addViolation();
}
}
}
此->atPath('reached')
将错误粘贴到违规的字段
是的,我之前没有这个,这导致了显示
对所有字段的错误消息而不是唯一的
错误实际属于的字段。 atPath()
中的参数是您要将错误链接到的属性名称。但为了得到这个
工作你还需要关闭collection form
所以错误不会传递给父表单。
atpath('fieldname')
这个解决方案对我有用,我必须承认在它上面工作非常有趣,让我很兴奋。