4

正如标题所示,我在实现 3 结构模型(域对象、数据映射器和服务)时遇到了一些小问题。

过去,当有人在我的网站上注册时,我会简单地做

$user->register($firstName, $lastName, $emailAddress, $username...);

并且该方法将按这样的步骤运行

1. Check if the form sent was valid.
2. Check if all the required fields were filled.
3. Check the if the lengths of strings were valid and the range of integers etc.
4. Check if the input is in the correct format (regex).
5. Check if the username is already taken and if the email address already exists
   in the database
6. etc. etc.

所有这一切都很好,但我试图摆脱这样做,因为我希望我的代码更可重用和可测试。

现在,使用这 3 个结构模型,域对象和数据映射器应该通过服务进行通信,以使它们彼此隔离,所以这是我对用户服务的想法

class UserService {

    public function register($firstName, $lastName, $email...) {

        $userDO= $this->domainObjectFactory->build('User');
        $mapper  = $this->dataMapperFactory->build('User');

        // Is this where I start doing my validation like in the steps above???
        // And if this is where I start doing my checks, when I get to the part
        // where I have to check if the username they want is already taken how
        // how do I do that check?

    }    

}

然后实际运行,我会像这样从我的控制器中执行它

$userService = $this->serviceFactory->get('user');
$result = $userService->register($_POST['firstName']....);

逻辑(if's 和 else's)必须register()放在我UserService班级的方法中,对吗?因为如果当我到达需要数据库进行一些检查的阶段时他们进入域对象,例如用户名是否已经存在,我将如何访问数据库?我真的不知道,因为域对象不应该知道有关数据源的任何信息。

必须有一种方法可以访问数据库以进行小型查询,例如检查用户名或电子邮件地址是否已经存在以及需要完成的大量其他小型查询。

我有很多实体/域对象需要执行大量小查询,过去我的模型可以从任何方法中访问数据库并且可以执行这些查询,但这似乎不允许使用这 3 结构模型我很想知道什么是正确的方法,因为必须有一种方法。

我一直在飞行,直到我发现模型是一个分为 3 个结构的层。

任何帮助或朝着正确的方向推动将不胜感激,尤其是现实生活中的好例子。互联网似乎缺少针对我的特定问题的那些。

谢谢。

4

2 回答 2

1

我正在经历与您现在相同的事情(很有趣,对于这个确切的问题 - 用户注册/授权)。

我的一条建议是,您不应将模型限制为仅 3 层(在本例中为 3 个类)。一个模型应该有尽可能多的类,以便在保持 SRP(单一责任原则)完整性的同时完成工作。

例如,您可能还希望使用 UserTableGateway 类来补充 UserDataMapper,并使用 UserCollection 类来允许潜在的分页功能或一般用户列表。所有这些都可能是您的模型和 UserService 层的一部分。

要回答您关于注册过程特定逻辑的问题,是的,最合适的位置是在 UserService 类的注册方法中。

说了这么多,您可能想在这里考虑一下您的域结构。UserService 是最适合注册的地方(以及扩展名、登录、恢复密码、更改密码等)吗?

也许这些东西可能是与帐户相关的完全不同模型的一部分。服务类可能是这样的:

class Account 
{
    // Think of this as AccountService, it will have a number of collaborators,
    // including an Authenticator class for loggin in, a Session class for managing the session
    // and of course various persistence classes for storing the user, session and credentials


    public function register(UserInterface $user) {}
    public function login($email, $password) {}
    public function logout(UserInterface $user, $session_id) {}
    public function changePassword($user_id, $old_password, $new_password) {}
    public function recoverPassword($user_id, $email) {}
}

鉴于 UserService 可能要负责许多其他事情,因此将与用户帐户相关的所有内容保存在其自己的服务类中是有意义的。

从概念上讲,无论如何,一个帐户与用户是不同的,如果它在概念上有所不同,它应该有自己的类别。

现在,就获取 Account 服务类所需的依赖项而言,在我对复杂系统设计的理解中,这超出了现阶段的范围。

于 2013-11-04T08:42:27.270 回答
0

This is an interesting question. I suppose your user Data Mapper has methods for finding & loading users based on some criteria (like username). Therefore, in this case I would do the check inside UserService::register by trying to find a user having the provided username (if it exists):


if ($mapper->findUserByUsername($username)) { 
    // username is already taken, handle this special case
}

By the way, I don't know if you read this, but a very good guide is Martin's Fowler book - Patterns of Enterprise Application Architecture. You will find good answers for many of your questions.

于 2013-01-06T00:20:30.323 回答