5

我正在 Zend Framework 中创建一个简单的 ORM,以使用 DbTable/Mapper/Model 方法粗略地封装一个公共库应用程序。不过,我不确定我执行与用户相关的课程的方式是否正确,因为我Mapper_UserModel_User.

映射器_用户

<?php
class Mapper_Users {

/*
createModelObject would be called by a Controller handling a Form_Regsiter's
data, to create a new Model_User object. This object'd then be saved by the
same Controller by calling Mapper_Users->save();
*/
    public function createModelObject(array $fields) {
        if(!isset($fields['date_registered']))
            $fields['date_registered'] = date('Y-m-d H:i:s');
        if(!isset($fields['max_concurrent_rentals']))
            $fields['max_concurrent_rentals'] = 3;
        return new Model_User($fields);
    }
}
?>

Model_User在从头开始创建新对象的方法中(例如,不是从数据库中提取记录,而是注册一个新用户),我Model_User使用表单提供的名称/用户名/密码实例化一个新对象,然后设置一些对象属性例如注册日期,“一次允许的最大书籍”等。该数据由 填充在Model_User中,然后在被调用Mapper_User时写入数据库。Mapper_User->save();Mapper 感觉是适合这个的地方 - 保持模型轻。

这是正确的,还是应该在内部设置这样的默认字段Model_User

模型_用户

<?php
class Model_User {

    public function setPassword($value) {
        $this->password = md5($value);
    }
}
?>

Model_User->setPassword($value);在设置用户对象的密码时,正如您所料,我在 中执行此操作,并$this->password = md5($value);在此方法中执行此操作。再一次,这感觉是对的 - 如果从数据库中提取一个,尝试在Mapper_User->save();方法中执行 md5 步骤会导致问题Model_User,因为密码字段显然已经被散列。

这就是我产生困惑的地方。在我看来,与“与用户有关的字段”有关的所有逻辑都应该存在于它的模型或映射器中,但这里我在映射器中有一些逻辑(默认字段),还有一些(字段操作)在模型。这是正确的,还是我应该尝试以某种方式获取模型中的默认字段或映射器中的字段操作?

感谢您抽时间阅读!


编辑@RockyFord:

Mapper_User 实际上扩展了我写的摘要,因为我不喜欢在 500 个Mapper_*.php文件中编写相同的基本代码,因此有一些官僚作风,但它的有效__construct() 非常简单:

<?php
class Mapper_Users {

    public function __construct() {
        $this->_db = new DbTable_Users();
        if(!$this->_db instanceof Zend_Db_Table_Abstract)
            throw new Exception('Invalid table data gateway provided');
    }
}
?>
4

2 回答 2

1

这可能需要一段时间才能完全回答,但我将从这个setPassword问题开始。

您当前的:

public function setPassword($value) {
        $this->password = md5($value);
    }

现在,这与惯例或最佳实践无关,而是实用性。

问你自己:

当您检索用户对象的数据库记录并且该数据库记录包含散列密码时会发生什么?

回答:当您构造用户对象并调用$this->setPassword($password);或等效时,您将哈希应用于哈希。

因此,您几乎有义务在映射器的 save() 方法或用于更新密码的方法中对密码进行哈希处理。将数据库表中的哈希值视为密码,将输入表单字段的值视为该密码的占位符。

下一部分:

在我看来,与“与用户有关的字段”有关的所有逻辑都应该存在于其模型或映射器中

这大多是正确的。

属于对象域 (Model_User) 的所有内容都应在域模型类 (Model_User) 中进行处理。

映射器仅将数据对象(数据库行、json 字符串、xml 文件、平面文件、csv 文件 ... )转换(映射)为可以实例化域对象 (Model_User) 的表单。

因此,您最终可能会得到一个以上的映射器可用于给定的域对象,或者一个映射器可能会映射到一个以上的数据源。

如果您不再将数据视为“字段”,这可能会对您有所帮助,这可能会使您的头脑停留在数据库中,而是根据属性特征来考虑您的对象。

因为当你深入到最基本的层次时,一个Model_User对象就是:

class Model_User {
    protected $id;
    protected $name;
    protected $password;
    //continue....
}

所有的 getter、setter、构造函数和其他方法都差不多,所以我们可以将值放入这些变量中。

于 2012-09-09T15:25:09.297 回答
1

The DataMapper is responsible for populating the object with its data, as well as persisting it. It seems like you're mixing things when you call $user->save() because you're putting persistence logic within your domain object. This is a common approach when you're using the ActiveRecord pattern instead of DataMappers, which is a bad thing.

Your DataMapper should be responsible for saving the object $mapper->save($user); and it needs to update just the changed properties. So, the password will be updated only if you set the new hash.

UPDATE:

You said:

[...] trying to do the md5 step in Mapper_User->save(); method would cause issues if the Model_User were one pulled from the DB, as the password field would clearly already be hashed.

Creates a method called setPasswordHash() and use it when pulling from the database.

Remember: Don't look for things!

Instead of looking for the database inside your mappers, you should ask for it.

public __construct(Zend_Db_Table $dbTable) {
    $this->dbTable = $dbTable;
}

It's all about Dependency Injection.

于 2012-09-09T15:28:58.390 回答