我在Zend Framework中创建一个简单的ORM,使用DbTable / Mapper / Model方法粗略地封装公共库应用程序。我不确定我使用与用户相关的类的方式是否正确,因为我在Mapper_User
中有一些逻辑,而Model_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
是从数据库中提取的,因为密码字段显然已经被哈希。
这就是我的混乱出现的地方。在我看来,所有与“与用户相关的字段”的逻辑应该存在于它的模型或Mapper中,但是在这里我在Mapper中有一些逻辑(默认字段),而在一些(字段操作)中模型。 这是正确的,还是应该尝试以某种方式获取模型中的默认字段或Mapper中的字段操作?
感谢您花时间阅读本文!
编辑@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');
}
}
?>
答案 0 :(得分:1)
这可能需要一段时间才能完全回答,但我会从setPassword
问题开始。
你当前的事:
public function setPassword($value) {
$this->password = md5($value);
}
现在这与惯例或最佳实践无关,但与实用性无关。
问问自己:检索用户对象的数据库记录并且该数据库记录包含散列密码时会发生什么?
答案:当您构造用户对象并调用$this->setPassword($password);
或同等对象时,您将把哈希应用于哈希。
因此,您几乎有义务在映射器的save()方法或用于更新密码的方法中散列密码。将数据库表中的哈希值视为密码,并将表单字段中输入的值作为该密码的占位符。
下一部分:
在我看来,与“与用户相关的字段”相关的所有逻辑都应该存在于其模型或Mapper中
这大多是正确的。
属于对象域的所有内容(Model_User) 应在域Model(Model_User)中进行处理。
映射器只是将( map )数据对象(数据库行,json字符串,xml文件,平面文件,csv文件...... )转换为表单可以实例化域对象(Model_User)。
因此,您最终可能会有一个可用于给定域对象的映射器,或者一个映射器可能映射到多个数据源。
如果您不再将数据视为“字段”,这可能会对您有所帮助,这可能会让您不知所措,而是根据属性或特性
因为当你达到最基本的水平时,Model_User
对象就是:
class Model_User {
protected $id;
protected $name;
protected $password;
//continue....
}
所有getter,setter,构造函数和其他方法都是如此,我们可以将值放入这些变量中。
答案 1 :(得分:1)
DataMapper
负责使用其数据填充对象,并将其持久化。当你调用$user->save()
时,似乎你正在混合东西,因为你在你的域对象中加入了持久性逻辑。当您使用ActiveRecord
模式而不是DataMappers
时,这是一种常见的方法,这是一件坏事。
您的DataMapper
应负责保存对象$mapper->save($user);
,并且只需更新已更改的属性。因此,只有在设置新哈希值时才会更新密码。
你说:
[...]试图在
Mapper_User->save();
方法中执行md5步骤会导致 如果从数据库中取出Model_User
作为密码,则会出现问题 字段显然已经被散列。
创建一个名为setPasswordHash()
的方法,并在从数据库中提取时使用它。
不是在映射器中查找数据库,而应该要求它。
public __construct(Zend_Db_Table $dbTable) {
$this->dbTable = $dbTable;
}
关于依赖注入。