2009-11-14 98 views
0

目前,我創建一個對象並使用其setter來設置從客戶端接收到的獲取/發佈數據。並呼籲像這樣保存()函數之前調用的validate():在PHP模型驗證的常見模式是什麼?

//member registration 
$m=new Member(); 
$m->setName($_POST['name']); 
$m->setBirthDate($_POST['birthdate']); 
$m->setAddress($_POST['address']); 

$arrOfErrMsgs=$m->validate(); 

if(!empty($arrOfErrMsgs)){ 
//echo some error messages to client or redirect to a page that shows the error 
exit(); 
} 

$saveSuccess=$m->save(); //to be safe, inside this save function, it will also call validate() again before saving, so that even someone forgot to call validate() before calling save() by mistake, no dirty data will appear in the database 

if($saveSuccess){ 
//echo a success message to client or redirect to a success page 

}else{ 
//echo save failed message to client (normally this should not happen unless db server suddenly fails) 
} 

exit(); 

雖然這個工作,但應該有一些替代品。例如,也許一些驗證可以在setters中完成。

我想知道什麼模式驗證模式在PHP是最常見的?

回答

1
<?php 

abstract class Model { 

    protected $errors = array(); 

    public function validate() { 
     // Implement validation logic, overriden in subclasses 
    } 

    public function isValid() { 
     $this->validate(); 
     return empty($this->errors); 
    } 

    public function save() { 
     if (!$this->isValid()) { 
      return false; 
     } 

     // Perform the saving operation 
    } 
} 

class Member extends Model { 

    // setters and getters and constructor 

    public function validate() { 
     if (empty($this->name)) { 
      $this->errors[] = 'name can not be empty'; 
     } 
    } 
} 

$member = new Member(array(
    'name' => 'Hanse' 
)); 

if ($member->save()) { 
    // Print success messages 
} else { 
    // Print error messages 
    print_r($member->getErrors()); 
} 

我更喜歡上面代碼的方法。給你一個乾淨靈活的API。

2

控制器應該驗證,模型不應該處理任何不可信的數據。

+6

我認爲你錯了!模型應該執行邏輯(在這種情況下是驗證),控制器應該將用戶重定向到他或她應該去的地方! – AntonioCS 2009-11-14 11:40:35

+0

@AntonioCS控制器應該進行與用戶輸入相關的驗證,而不是業務邏輯。如果驗證是驗證購買的產品數量是否超過用戶限制,則必須在模型中完成,但如果驗證是驗證提交的數據不包含可能存在的XSS漏洞,則必須在控制器中進行驗證。 – JCM 2012-03-20 22:22:06

1

我認爲這是執行業務驗證的完美方式。如果數據無效,也許你的save()方法可能返回一個帶有錯誤信息的字符串,否則返回true(保存多餘的validate()調用)。這是我現在採取的方法 - 雖然這取決於你想如何設計你的API。只要它是可預測的並且合理。

與erenon一樣,該模型不應該執行低級驗證,例如檢查整數,日期格式,惡意代碼等 - 這些屬於其他地方(例如Zend_Form)。但對於像member must be over 21 years old這樣的業務驗證,我沒有看到問題。

2

我不建議這種驗證模型的方法。

首先,讓控制器驗證輸入,以確保它是一個字符串時它應該是,它應該是一個整數,等等。但不是業務邏輯。

當您創建新成員時,我建議將所有信息通過構造函數傳入。這樣構造函數可以檢查OVERALL模型的一致性,而setter方法應該對它們負責的每個數據進行一致性檢查。例如,如果您有另一條信息,比如firstHeardOf(他們第一次聽到他們正在加入的任何網站),那麼制定者應該確保它是有效日期,並且是在出生日期之後,至少。這會創建方法的順序問題,並且要求以特定順序調用方法不是好的做法,而是可以使用構造函數來保證調用的順序。

保存方法現在只是一個簡單的方法,它保存的數據,真的爲什麼它應該有任何其他責任。最多它應該再次檢查構造成員是否仍然有效,這是您可能想要將構造函數驗證代碼拖入私有/受保護的驗證方法的地方,並在兩個地方調用它。

上的責任一個快字,以及他們如何打破這裏,在我的腦海至少:

  • 的構造函數負責創建一個有效/正確初始化成員對象
  • 的制定者有責任爲基準
  • save方法的成員對象內設定有效數據負責保存有效成員對象