2015-11-16 55 views
1

我工作的一個collection form被稱爲目標,因爲他們想要的,這部分工作正常,我能夠顯示用戶可以添加儘可能多的目標/添加/編輯/只刪除目標我有細的Symfony無法驗證收集表格

enter image description here

的問題是如何驗證數據。在表格中有一個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; 
    } 
} 

從閱讀看來我需要添加約束Valid,我有內部validation.yml symfony的文檔。

goals: 
    - Valid: 

問題1

假設,當我進入saved to date是大於goal target對第一個目標,而不是讓錯誤只是針對這個目標我得到的錯誤對陣雙方目標。

注意第二個錯誤不應該有8000少於20000 enter image description here

問題2

假設針對這兩個目標,我給saved to date大於goal target然後我查看每個字段的2個錯誤。

enter image description here

這是我很無能我的視圖模板

{% 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

最後我能解決這個問題。

  1. 在創建自定義的驗證你需要訪問你需要添加下面的代碼在你的 Constraint類 整個類。在我的情況下,這是SavedToDate,我是 將它加入SavedToDateValidator這是錯誤的。

    public function getTargets() 
    { 
        return self::CLASS_CONSTRAINT; 
    } 
    
  2. 要確保正確顯示驗證錯誤對 領域與collection form工作時,我不得不 提高我的自定義Validator SavedToDateValidator,感謝validate()功能@Richard的小費。

    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()其中違反 是堅持錯誤的領域,我沒有這個更早,這是導致顯示錯誤消息 反對一切字段而不是唯一針對錯誤實際屬於的 字段。 atpath('fieldname')中的參數是您想要鏈接錯誤的屬性名稱。但爲了使 正常工作,您還需要關閉error_bubbling ,以免錯誤傳遞給父窗體。

    $builder 
         ->add('goals', 'collection', array(
           'type' => new GoalType(), 
           'allow_add' => true, 
           'by_reference' => false, 
           'error_bubbling' => false 
           )); 
    

該解決方案爲我工作,我必須承認這是真的很有趣它的工作,使我興奮。

+1

好東西,很高興你把它分類! – Richard

2

這是一個一流水平的約束,它會火你的目標類的每個實例從您的形式存在。

因爲您正在遍歷驗證程序中的所有對象(爲什麼?)對於目標類的每個實例,您都將檢查所有目標實體,這並不理想(對於2個實體,您將檢查每個實體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(); 
      } 
     } 
    } 
} 

有文件的讀取爲class constraint validators

+0

請編輯您的代碼示例,因爲ConstraintValidator沒有'getTargets()'函數。只有約束才能做到。 – DelphiLynx

+1

@DelphiLynx注意到並改變了 – Richard