1

从今天开始,我开始在模型层而不是控制器中验证表单数据。我将尽可能缩短代码片段。

这是来自我的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()方法将抛出 aLengthException因为它太短了。

这就是我想要的,但是当它返回到服务层然后返回到控制器并且我抓住它时,我知道 aLengthException被抛出但我不能给用户一个正确的消息,比如“提供的姓氏太短”因为我不知道哪个字段抛出了异常,只知道异常的类型。

我该如何解决这个问题?谢谢。

4

3 回答 3

1

视图实例应该从模型层请求信息。控制器不负责传递信息。

这也意味着你强迫性地使用异常,这会导致你的抽象层泄漏,这将是完全没有意义的。“错误”只是模型层的一种状态。这是预期的情况,而不是例外。

MVC 中的控制器负责改变模型层的状态和(很少)当前视图实例的状态。他们不应该收到来自服务的任何反馈。

于 2013-02-23T18:37:09.230 回答
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 的构造函数设为私有,因为如果您直接使用构造函数构建用户,您将跳过所有验证。但这并不意味着它变成了 Singleton。

也许我还会在将表单字段传递给模型之前对其进行清理并使其安全。

像 model_error_xyz 这样的键可以在带有适当文本的翻译文件中找到。

更新:

实际上,我认为您可以从构造函数中抛出一个自定义异常,其中包含一组消息。但我没有提出这个的原因是,它导致了半构造对象,至少在 Java 中是这样,但是,嘿,PHP 不是 Java ......

您还必须验证每个 setter 函数 :( 在模型实例中进行验证似乎很乏味。

欢迎任何想法。

于 2013-06-21T02:43:19.713 回答
0

与其返回一些消息,不如返回一个有用的错误消息,例如“提供的名字太短”。然后可以将其返回给用户。

或者,您可以看到,在扩展异常时,您可以指定其他信息,例如数字代码 - 您当然可以使用它。

或者,当然你可以为不同的情况创建一个 Exception 的子类,但你最终可能会得到数百Exception个子类,这些子类当然会很混乱。

于 2013-02-23T18:25:17.373 回答