从今天起,我开始在模型层而不是在控制器中验证表单数据。我将尽可能缩短代码片段。
这是我User
域对象的一种方法(setLastName()
方法基本相同)
public function setFirstName($firstName) {
if(!$firstName) throw new \InvalidArgumentException('Some message');
if( strlen($firstName) < 2 || strlen($firstName) > 20 ) throw new \LengthException('Some message');
if(preg_match('/[^a-zA-Z\'.-\s]/', $firstName)) throw new FormatException('Some message');
$this->firstName = $firstName;
}
在我的控制器中,我有类似的东西
$userService = $this->serviceFactory->build('User');
try {
$userService->register('John', 'M');
}
catch(\InvalidArgumentException $ex) {
}
catch(\LengthException $ex) {
}
catch(etc etc)
在我的UserService
方法register()
中,我有类似
$user->setFirstName($firstName);
$user->setLastName($lastName);
运行setFirstName()
方法时,它将成功设置提供的名字。由于setLastName()
方法太短,LengthException
方法会抛出LengthException
。
这就是我想要的,但是当它回到服务层然后再回到控制器并且我抓住它时我知道抛出了{{1}}但是我不能给用户一个正确的消息,比如“提供的姓氏太短了“因为我不知道抛出异常的字段,只是异常的类型。
我如何解决这个问题?感谢。
答案 0 :(得分:1)
视图实例应该从模型层请求信息。控制器不负责传递信息。
这也意味着你强迫使用异常会导致你的抽象层泄漏,这将是完全没有意义的。 “错误”只是模型层的状态。这是预期的情况,不是例外。
MVC中的控制器负责更改模型层的状态和(很少)当前视图实例的状态。他们不应该从服务中收到任何反馈。
答案 1 :(得分:0)
为什么不返回有用的错误消息,例如“提供的名字太短”,而不是返回某些消息。然后可以将其返回给用户。
或者你可以看到extending exceptions时你可以指定其他信息,例如数字代码 - 你当然可以使用它。
当然,你也可以为不同的情况创建一个Exception的子类,但最终可能会有数百个Exception
子类,这些子类当然会很混乱。
答案 2 :(得分:0)
我有同样的问题。我认为大多数人都认为应该在模型中完成所有验证,但他们自己从未开发过完整的PHP MVC应用程序,只知道书籍和理论。从来没有看到关于该主题的代码。
无论如何,我想到了一个可能的解决方案。您如何看待以下代码:
// Controller
$user = User::make(
$_POST['lastname'], $_POST['firstname'],
$_POST['gender'], [...]
);
if(is_array($user)) {
// store the errors in a view variable and forward, or store in session and redirect
$_SESSION['errors'] = $user;
$this->_redirect('add');
exit;
}
// Model
public static make($lastname, $firstname, $gender, [...]) {
$errors = array();
if(/* test firstname */) $errors[] = 'model_error_firstname';
if(/* test lastname */) $errors[] = 'model_error_lastname';
if(!empty($errors)) return $errors;
return new User($lastname, $firstname, $gender, [...]);
}
该模型将有一个静态函数,如果出现错误,将返回一个包含错误的数组,如果验证正常,则返回一个新的模型对象。
在您的控制器中,您可以测试是否返回了数组。
也许我会将User的构造函数设置为private,因为如果您直接使用构造函数构建用户,则会跳过所有验证。但这并不意味着它变成了单身人士。
也许我还会清理表单字段并在将它们传递给模型之前使其安全。
像model_error_xyz这样的键可以在带有相应文本的翻译文件中找到。
更新
实际上我认为你可以从构造函数中抛出一个自定义异常,它包含一组消息。但是我没有提出这个问题的原因是它导致了半构造的对象,至少在Java中是这样,但是嘿,PHP不是Java ......
您还必须验证每个setter函数:(在模型实例中进行验证似乎很乏味。
欢迎任何想法。