2016-02-13 74 views
9

假設我有這個模型。 (我爲示範的目的,很簡單的。)PHP中需要與數據庫交互的模型驗證

class User 
{ 
    public $id; 
    public $email; 
    public $password; 
    public $errors = []; 

    public function isValid() 
    { 
     if (strpos($this->email, '@') === false) { 
      $this->errors['email'] = 'Please enter an email address'; 
     } 
     // ... 

     return !$this->errors; 
    } 
} 

而且讓我們說我有這樣的DAO檢索,添加,更新和刪除用戶。

class UserDAO 
{ 
    public function getUsers() { ... } 

    public function getUserById($id) { ... } 

    public function addUser(User $user) { ... } 

    public function updateUser(User $user) { ... } 

    public function deleteUser($id) { ... } 

    public function isEmailUnique($email) { ... } 
} 

當我處理一個形式,我通常做的是這樣的:

$userDAO = new UserDAO(); 
$user = new User(); 
$user->email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL); 
$user->password = filter_input(INPUT_POST, 'password'); 

if ($user->isValid()) { 
    if ($userDAO->addUser($user)) { 
     // ... 
    } else { 
     // ... 
    } 
} else { 
    // do something with $user->errors 
} 

現在,讓我們說我的用戶驗證的一部分應該是檢查郵件是否是獨一無二的,我怎麼使它用戶模型的一部分?因此,當調用$user->isValid()時,它還會檢查電子郵件是否唯一?還是我這樣做全錯了?

由於我對DAO的理解很差,DAO負責與數據庫的所有交互。那麼我如何使模型與數據庫一起工作呢?

+1

的S.Lott的回答可能幫助你http://stackoverflow.com/a/198032/3904215。這裏來自tutorialspoint的描述:http://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm – AMartinNo1

回答

2

我的建議是這樣的:在驗證User型號時不要考慮電子郵件地址的唯一性。唯一性是UserDAO問題,而不是User問題。

如果User可以驗證自己,它應該能夠孤立地這樣做;其驗證不應該涉及任何外部交互。

無論電子郵件地址是否唯一,唯一重要的時刻就是在您嘗試將其插入數據庫時​​。考慮到多個併發用戶的可能性,理論上可能用於驗證地址的唯一性,並在嘗試插入地址時使其不再是唯一的。

我認爲最直接和最可靠的方法是在數據庫的電子郵件地址上添加一個唯一的約束,然後在您的addUser()方法中,只需要try即可添加它。如果你的數據庫告訴你它不是唯一的,那麼你知道它不是唯一的。您事先不知道真的

+0

謝謝。你是對的。我過分複雜化了我的設計。 – Mikey

1

我認爲在這種情況下,驗證是應用程序邏輯的一部分,因爲您需要未存儲在模型中的數據。所以在不同的控制器功能中實現驗證邏輯會更好。

而且,與類似的答案已經是一個類似的問題:Best Place for Validation in Model/View/Controller Model?

0

的UserDAO的類必須實現的方法稱爲userExists。此方法僅檢查電子郵件地址是否已存在。它在BD中檢查它,所以它的位置在UserDAO類中。它必須是私有方法,並且addUser使用它返回正確的值或false/null

1

保留User類,因爲它本身就是一個很好的公民。

我會做的方法isEmailUnique私人(IFF它只是用於那些)並通過與內addUser該電子郵件中的User存在檢查。另一方面,這將把邏輯的責任推到DAO(參見:Responsibilities and use of Service and DAO Layers

所以,如果你改變isValid行爲檢查,如果用戶已經在數據庫中,你會打破你的設計。

0

我認爲你可以使用DAO作爲驗證函數的參數。

public function isValid($dao) 
{ 
    if (strpos($this->email, '@') === false) { 
     $this->errors['email'] = 'Please enter an email address'; 
    } 
    if ($dao->isEmailUnique($this->email) === false) { 
     $this->errors['email'] = 'Email address should be unique'; 
    } 
    // ... 

    return !$this->errors; 
} 

但是可能更好的方法是在你的用戶模型中使用DAO。添加到模型私有變量$ dao並在構造函數中初始化它。並在模型類中實現所有用於添加/編輯/刪除操作的方法。去這個

1

的一種方式,是去除方法用戶::完全IsValid的,有利於傳遞給它的構造函數中需要的一切,從那裏運行驗證:

class User 
{ 
    public function __construct($email) { 
     if (strpos($email, '@') === false) { 
      throw new \InvalidArgumentException("Invalid email"); 
     } 

     $this->email = $email; 
    } 
} 

如果您認爲關於它,是什麼讓用戶有效?如果這是一個有效的電子郵件地址,請確保在構建User對象時傳入一個。這使您的用戶對象始終有效。

確保這方面的一個更好的辦法,是使用的ValueObject它封裝了這個驗證邏輯,因此您可以在其他對象使用它,避免了大量的冗餘和樣板代碼:

class Email 
{ 
    public function __construct($email) 
    { 
     if (strpos($email, '@') === false) { 
      throw new \InvalidArgumentException("Invalid email"); 
     } 

     $this->email = $email; 
    } 
} 

class User 
{ 
    public function __construct(Email $email) 
    { 
     $this->email = $email; 
    } 
} 

class ProspectiveUser 
{ 
    public function __construct(Email $email) 
    { 
     $this->email = $email; 
    } 
} 

現在,在條款用數據庫驗證用戶,您可以完美地將其封裝在您的DAO中。 DAO可以執行檢查以確保用戶不在數據庫中,保持DAO使用者不知道它,除非它應該知道如何處理當用戶已經存在於數據庫中時發生錯誤的情況:

class UserDAO 
{ 
    public function recordNewUser(User $user) 
    { 
     if ($this->userExists()) { 
      throw new UserAlreadyExistsException(); 
     } 

     $this->persist($user); 
     $this->flush($user); 
    } 

    private function userExists(User $user) 
    { 
     $user = $this->findBy(['email' => $user->getEmail()]); 

     return !is_null($user); 
    } 
} 

正如你所看到的,DAO爲您提供了保存新的用戶界面,但如果電子郵件唯一的限制是不信納操作可能會失敗。

1

我會從User類中取出所有驗證問題,並轉到Controller層(可以調用UserDAO來檢查電子郵件唯一性)。最好是保持User類簡單地作爲一個實體類,並把所有其他的東西在其他類別 - 否則它會不斷地成長到不是維護了:)

檢查也是國家:https://en.wikipedia.org/wiki/Single_responsibility_principle