Đọc câu hỏi SO này , có vẻ như việc đưa ra các ngoại lệ để xác thực đầu vào của người dùng sẽ không được chấp nhận.
Nhưng ai nên xác nhận dữ liệu này? Trong các ứng dụng của tôi, tất cả các xác nhận được thực hiện trong lớp nghiệp vụ, bởi vì chỉ có chính lớp đó thực sự biết giá trị nào là hợp lệ cho mỗi một thuộc tính của nó. Nếu tôi đã sao chép các quy tắc để xác thực một thuộc tính cho bộ điều khiển, có thể các quy tắc xác thực thay đổi và bây giờ có hai nơi cần thực hiện sửa đổi.
Là tiền đề của tôi rằng xác nhận nên được thực hiện trên lớp kinh doanh sai?
Những gì tôi làm
Vì vậy, mã của tôi thường kết thúc như thế này:
<?php
class Person
{
private $name;
private $age;
public function setName($n) {
$n = trim($n);
if (mb_strlen($n) == 0) {
throw new ValidationException("Name cannot be empty");
}
$this->name = $n;
}
public function setAge($a) {
if (!is_int($a)) {
if (!ctype_digit(trim($a))) {
throw new ValidationException("Age $a is not valid");
}
$a = (int)$a;
}
if ($a < 0 || $a > 150) {
throw new ValidationException("Age $a is out of bounds");
}
$this->age = $a;
}
// other getters, setters and methods
}
Trong bộ điều khiển, tôi chỉ truyền dữ liệu đầu vào cho mô hình và bắt các ngoại lệ được ném để hiển thị (các) lỗi cho người dùng:
<?php
$person = new Person();
$errors = array();
// global try for all exceptions other than ValidationException
try {
// validation and process (if everything ok)
try {
$person->setAge($_POST['age']);
} catch (ValidationException $e) {
$errors['age'] = $e->getMessage();
}
try {
$person->setName($_POST['name']);
} catch (ValidationException $e) {
$errors['name'] = $e->getMessage();
}
...
} catch (Exception $e) {
// log the error, send 500 internal server error to the client
// and finish the request
}
if (count($errors) == 0) {
// process
} else {
showErrorsToUser($errors);
}
Đây có phải là một phương pháp xấu?
Phương pháp luân phiên
Có lẽ tôi nên tạo các phương thức cho isValidAge($a)
trả về true / false và sau đó gọi chúng từ bộ điều khiển?
<?php
class Person
{
private $name;
private $age;
public function setName($n) {
$n = trim($n);
if ($this->isValidName($n)) {
$this->name = $n;
} else {
throw new Exception("Invalid name");
}
}
public function setAge($a) {
if ($this->isValidAge($a)) {
$this->age = $a;
} else {
throw new Exception("Invalid age");
}
}
public function isValidName($n) {
$n = trim($n);
if (mb_strlen($n) == 0) {
return false;
}
return true;
}
public function isValidAge($a) {
if (!is_int($a)) {
if (!ctype_digit(trim($a))) {
return false;
}
$a = (int)$a;
}
if ($a < 0 || $a > 150) {
return false;
}
return true;
}
// other getters, setters and methods
}
Và bộ điều khiển về cơ bản sẽ giống nhau, chỉ thay vì thử / bắt ngay bây giờ nếu / khác:
<?php
$person = new Person();
$errors = array();
if ($person->isValidAge($age)) {
$person->setAge($age);
} catch (Exception $e) {
$errors['age'] = "Invalid age";
}
if ($person->isValidName($name)) {
$person->setName($name);
} catch (Exception $e) {
$errors['name'] = "Invalid name";
}
...
if (count($errors) == 0) {
// process
} else {
showErrorsToUser($errors);
}
Vậy, tôi nên làm gì?
Tôi khá hài lòng với phương pháp ban đầu của mình và các đồng nghiệp mà tôi đã chỉ ra nói chung đã thích nó. Mặc dù vậy, tôi có nên thay đổi sang phương pháp thay thế? Hay tôi đang làm điều này sai lầm khủng khiếp và tôi nên tìm cách khác?
IValidateResults
.
ValidationException
và các ngoại lệ khác