2012-08-17 50 views
1

我的系統中有兩個實體:PersonPhone,如下面的代碼。在Symfony 2中可選的嵌入形式

class Person 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @ORM\Column(type="string", length=100) 
    */ 
    private $name; 

    /** 
    * @ORM\Column(type="string", length=100) 
    */ 
    private $lastName; 

    /** 
    * @ORM\OneToOne(targetEntity="Phone", cascade={"persist"}) 
    */ 
    private $phone; 
}; 

class Phone 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @ORM\ManyToOne(targetEntity="PhoneType") 
    */ 
    private $type; 

    /** 
    * @ORM\Column(type="integer") 
    */ 
    private $countryCode; 

    /** 
    * @ORM\Column(type="integer") 
    */ 
    private $regionCode; 

    /** 
    * @ORM\Column(type="integer") 
    */ 
    private $number; 
}; 

我也有一個表單創建和更新的人(用手機),所以我有一個PersonType有代表電話(PhoneType)一個嵌入形式。

我的問題是,一個人可以有一個電話,但如果該人有一部電話,所有的電話字段是必需的。因此,如果用戶在所有電話字段上都不寫任何內容,則表示沒有電話的人員,此情況有效。但是如果用戶填寫至少一個表單域,則所有其他域都是必需的。

我嘗試採取一種方法,通過將手機設置爲null,如果所有手機字段未被填充,則在setPhonePerson實體上實施。但有一個空手機,Symfony告訴我,所有的手機領域是必需的,但沒有填充。 我相信Symfony不會驗證手機,因爲我認爲Symfony會直接在人物實體上應用驗證。有一個空手機,爲什麼告訴我,所有的手機領域沒有填補?

有沒有辦法做我想做的事(最好不要修改我的所有控制器和表單類型,即在實體或驗證組件級別)?

編輯:對不起,沒有提到的東西,如果用戶填寫手機領域,所有手機領域需要與不同的驗證器(需單獨驗證檢查,如果一個字段是一個很好形成數,以檢查正確的長度等)。但是,如果用戶留下所有電話字段,則應忽略每場驗證。

謝謝!

回答

3

我想試試這個方法:

建立在你的手機實體另一種方法,如果所有字段爲空或所有字段不爲空(這兩種情況下是正確的),這驗證 - 然後返回true。如果某些字段爲空而有些不返回false。爲你的新方法添加一個斷言註解 - 這將是你的新約束。

/** 
* @Assert\True(message = "Fill all fields or leave all them blank") 
*/ 

而這應該工作。

欲瞭解更多信息,請看這裏: http://symfony.com/doc/master/book/validation.html#getters

編輯:

試試這個:

定義自定義的驗證方法(這其中一個檢查是否有手機領域的填充)作爲回調(在班級的頂部):

* @Assert\Callback(methods={"checkPhoneFields"}) 
*/ 
class Phone { 

接下來你需要標記的字段必須與驗證組驗證,例如。

/** 
* @ORM\Column(type="string", length=16, groups={"phone_validation"}) 
*/ 
private $number; 

而且過去的事,在你自定義的約束方法,你需要在「phone_validation」組切換如果有任何字段不爲空:

public function checkPhoneFields(ExecutionContext $context) { 
    if (/* fields are not empty */) { 
     $context->getGraphWalker()->walkReference($this, 'phone_validation', $context->getPropertyPath(), true); 
    } 

這應該工作。

+0

你能檢查一下編輯過的文章嗎? – eagleoneraptor 2012-08-21 16:04:03

0

這樣做:

首先在手機上的實體,聲明等領域爲「可空」是這樣的:

/** 
* @ORM\Column(type="integer", nullable=true) 
*/ 
private $countryCode; 

這將使這些領域有一個空值。

然後,你需要聲明一個驗證器將檢查字段沒有或所有的人都充滿

class Phone { 

... 
/** 
* @Assert\True(message = "Phone must be empty of fill all fields") 
*/ 
public function isPhoneOK() 
{ 
    // check if no field is null or all of them are 
    // return false if these conditions are not met 
} 
+0

你可以檢查編輯過的文章嗎? – eagleoneraptor 2012-08-21 16:04:26

+1

Cyprian給出的新解決方案應該可以工作,但是不要忘記將你的字段標記爲可空,否則在所有都爲空的情況下你將無法將它們保存到數據庫中 – 2012-08-21 19:01:05

0

也可以使用一個非常簡單的數據變壓器來解決這個問題。

  1. 創建您的手機數據轉換:

    class PhoneTransformer implements DataTransformerInterface 
    { 
        public function transform($phone) 
        { 
         if (is_null($phone)) 
          return new Phone(); 
    
         return $phone; 
        } 
    
        public function reverseTransform($phone) 
        { 
         if (is_null($phone)) 
          return null; 
    
         if (!$phone->getType() && !$phone->getCountryCode() /* ... Test if phone is not valid here */) 
          return null; 
    
         return $phone; 
    } 
    
  2. 然後簡單地追加該變壓器在PHONETYPE形式:

    class PhoneType extends AbstractType 
    { 
        public function buildForm(FormBuilder $builder, array $options) 
        { 
         $builder 
          /* Add fields here : 
          ->add(...) 
          */ 
          ->prependNormTransformer(new PhoneTransformer()) 
         ; 
        } 
    } 
    

http://symfony.com/doc/2.0/cookbook/form/data_transformers.html,詳細瞭解如何實現數據變壓器。

2

對於那些通過傳遞,與Symfony的較新版本,你可以這樣做:

/** 
* 
* @Assert\Callback() 
*/ 
public function validatePhone(ExecutionContextInterface $context) 
{ 
    if (/* Fields are not empty */) 
    { 
     $context->validate($this->getPhone(), 'phone', array("phone_validation")); 
    } 
} 
0

frankie567的答案是對我很有用。對於symfony> = 3.0:

/** 
* 
* @Assert\Callback() 
*/ 
public function validatePhone(ExecutionContextInterface $context) 
{ 
    if (/* Fields are not empty */) 
    { 
     $validator->inContext($context) 
      ->atPath('phone') 
      ->validate($this->getPhone(), null, array('phone_validation')); 
    } 
}