2016-02-13 22 views
9

Giả sử tôi có mô hình này. (Tôi đã làm cho nó rất đơn giản cho mục đích trình diễn.)Xác thực mẫu trong PHP yêu cầu tương tác với cơ sở dữ liệu

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; 
    } 
} 

Và giả sử tôi có DAO này để truy xuất, thêm, cập nhật và xóa người dùng.

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) { ... } 
} 

Khi tôi xử lý một hình thức, tôi thường làm một cái gì đó như thế này:

$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 
} 

Bây giờ, giả sử phần xác nhận của tôi sử dụng nên kiểm tra xem email là duy nhất, làm thế nào để làm cho nó một phần của mô hình Người dùng? Vì vậy, khi $user->isValid() được gọi, nó cũng kiểm tra xem email có phải là duy nhất không? Hoặc tôi làm điều này tất cả sai?

Từ sự hiểu biết yếu kém của tôi về DAO, DAO chịu trách nhiệm về mọi tương tác với cơ sở dữ liệu. Vậy làm thế nào để làm cho mô hình làm việc với cơ sở dữ liệu từ bên trong?

+1

Các câu trả lời của S.Lott có thể giúp bạn http://stackoverflow.com/a/198032/3904215. Và đây là một mô tả từ tutorialspoint: http://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm – AMartinNo1

Trả lời

2

Đề xuất của tôi là: không xem xét tính duy nhất của địa chỉ email khi xác thực mô hình User của bạn. Tính duy nhất là sự cố UserDAO, không phải là sự cố User.

Nếu User có thể xác thực chính nó, nó sẽ có thể thực hiện việc đó một cách độc lập; xác thực của nó không nên được quan tâm với bất kỳ tương tác bên ngoài nào.

Thời gian duy nhất quan trọng là địa chỉ email có phải là duy nhất hay không ngay lập tức bạn cố chèn nó vào cơ sở dữ liệu. Xem xét khả năng của nhiều người dùng đồng thời, có thể là về mặt lý thuyết để xác thực tính duy nhất của địa chỉ và không còn là duy nhất vào thời điểm bạn cố gắng chèn nó.

Tôi nghĩ cách đơn giản và đáng tin cậy nhất để làm điều này là thêm ràng buộc duy nhất vào địa chỉ email trong cơ sở dữ liệu của bạn, sau đó trong phương thức addUser(), chỉ cần try để thêm. Nếu cơ sở dữ liệu của bạn cho bạn biết nó không phải là duy nhất, thì bạn biết nó không phải là duy nhất. Bạn không thể thực sự biết trước.

+0

Cảm ơn. Bạn đúng. Tôi đang quá phức tạp thiết kế của tôi không có gì. – Mikey

1

Tôi nghĩ rằng xác thực, trong trường hợp này, là một phần của logic ứng dụng khi bạn yêu cầu dữ liệu không được lưu trữ trong mô hình. Vì vậy, nó sẽ được tốt hơn để thực hiện xác nhận logic trong một chức năng điều khiển khác nhau.

Hơn nữa, có một câu hỏi tương tự với câu trả lời tương tự đã: Best Place for Validation in Model/View/Controller Model?

0

Lớp UserDAO phải thực hiện một phương pháp gọi là userExists. Phương thức này chỉ kiểm tra xem địa chỉ email đã tồn tại chưa. Nó kiểm tra điều này trong BD để vị trí của nó nằm trong lớp UserDAO. Nó phải là một phương thức riêng và addUser sử dụng nó để trả lại một giá trị chính xác hoặc false/null

1

Giữ lớp User vì nó là một công dân tốt.

tôi sẽ làm cho các phương pháp isEmailUniquetin(khi và chỉ khi nó được sử dụng chỉ cho điều đó) và kiểm tra bằng sự tồn tại của một User với e-mail bên addUser. Mặt khác, điều này sẽ kéo trách nhiệm của logic vào DAO. (Xem: Responsibilities and use of Service and DAO Layers)

Vì vậy, nếu bạn thay đổi hành vi của isValid để kiểm tra xem người dùng đã vào cơ sở dữ liệu, bạn sẽ phá vỡ thiết kế của bạn.

0

Tôi nghĩ bạn có thể sử dụng DAO làm đối số cho chức năng xác thực.

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; 
} 

Nhưng có thể cách tốt hơn là sử dụng DAO bên trong Mô hình người dùng của bạn. Thêm vào mô hình biến private $ dao và init nó trong constructor. Và thực hiện tất cả các phương thức để thêm/sửa/xóa hoạt động trong lớp mô hình.

1

Một cách để đi về việc này, sẽ là để loại bỏ các phương pháp tài khoản :: IsValid hoàn toàn, có lợi cho đi tất cả những gì nó cần trong constructor của nó, chạy xác nhận từ đó:

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

     $this->email = $email; 
    } 
} 

Nếu bạn nghĩ về điều đó, điều gì làm cho người dùng hợp lệ? Nếu đó là địa chỉ email hợp lệ, hãy đảm bảo bạn chuyển một địa chỉ vào khi bạn xây dựng đối tượng Người dùng. Điều đó làm cho đối tượng User của bạn luôn hợp lệ.

Cách tốt hơn để đảm bảo này, sẽ được sử dụng một ValueObject mà gói gọn logic xác nhận này để bạn có thể sử dụng nó trong các đối tượng khác, tránh được rất nhiều khả năng dự phòng và soạn sẵn mã:

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; 
    } 
} 

Bây giờ, trong điều kiện xác nhận người dùng với cơ sở dữ liệu, bạn hoàn toàn có thể đóng gói trong DAO của mình. DAO có thể thực hiện kiểm tra đảm bảo rằng người dùng không có trong cơ sở dữ liệu, giữ cho người tiêu dùng DAO bất khả tri, ngoại trừ thực tế là nó phải biết cách xử lý trường hợp lỗi khi người dùng đã tồn tại trong DB :

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); 
    } 
} 

Như bạn có thể thấy, DAO cung cấp cho bạn với một giao diện để tiết kiệm một người dùng mới, nhưng đó hoạt động có thể thất bại nếu các hạn chế của email độc đáo là không hài lòng.

1

Tôi sẽ lấy tất cả các vấn đề xác thực ra khỏi lớp User và di chuyển đến Lớp điều khiển (có thể gọi UserDAO để kiểm tra tính duy nhất của email). Nó là tốt nhất để giữ User lớp đơn giản là một lớp Entity và đặt tất cả những thứ khác trong lớp khác - nếu không nó sẽ phát triển và phát triển để tình trạng đó không phải là duy trì nữa :)

Kiểm tra thêm: https://en.wikipedia.org/wiki/Single_responsibility_principle

Các vấn đề liên quan