我在验证引用其他模型的模型时遇到了问题。
我有一个"用户"模型和一个"配置文件"模型。我想创建配置文件,但我需要检查用户是否确实存在。
在我的配置文件模型中,我有一个方法"validateUser",但我必须将查询写入数据库中的特定表,或者我必须创建一个用户模型对象并调用 exists(id)。
这两种选择似乎都有很多缺点。表名称可能会更改,我必须检查使用它的所有模型。使用用户模式对象,我必须在配置文件模型中创建一个对象或注入它。
解决这个问题的最佳方法是什么?
末日领域 ..
在现实世界中,验证很少是一个简单的过程。相反,您有几个不相关的问题:
- 检查实例内的数据是否与业务规则一致
- 确保实例的状态不与其他域结构冲突
- 根据存储中的现有数据和约束验证信息的完整性
如果您使用活动记录来表示您的域模型(不要与 MVC 中的 M 混淆),那么这三个方面都将成为单个对象的责任。
这就是你现在拥有的。
但是有希望..
最好的选择是将所有这些责任分开(所有冰雹SRP)。基本上,您要做的是将当前设置划分为不同的结构组:
- 域
对象:用于处理域实体的特定规则
数据映射器:用于存储抽象
服务:用于域对象和映射器(或其他域对象)之间的交互
由于您的问题有些令人困惑(用户和配置文件以及保存和验证,然后不存在某些内容),我不确定我是否正确理解了它,但这里有一个小例子:
public function createProfile( $id, $email, $name )
{
$account = new Account;
$account->setId( $id );
$accountMapper = new AccountMapper( $pdo ); // explained below
if ( $accountMapper->fetch( $account ) === false )
{
$this->errors[] = .. something about missing account
return;
}
$profile = new Profile;
$profile->setEmail( $email )
->setName( $name );
if ( $profile->isValid() === false )
{
$this->errors[] = .. something about invalid profile
return;
}
try
{
$profileMapper = new ProfileMapper( $pdo ); // explained below
$profileMapper->store( $profile );
}
catch ( Exception $e )
{
$this->errrors[] = .. something about failing to create profile
return;
}
$account->addProfile( $profile );
$accountMapper->store( $account );
}
这是一个极其简化的示例。特别是在初始化映射器的情况下,因为在现实世界中,该部分将由某个工厂处理。有点像这篇文章中描述的。
这里的要点是,域数据的验证和数据库完整性的保险是分开完成的。用于与数据库交互的底层 API 实际上会返回错误代码,即您违反了UNIQUE KEY
或FOREIGN KEY
或任何其他约束,然后您可以使用这些约束来确定出了什么问题。
该方法本身将是服务的一部分(在本例中为管理用户帐户的某些服务)。
注意:如果您的应用程序需要为每个操作执行多个 SQL 交互,并且这些交互需要作为具有回滚功能的事务来完成,那么,您应该考虑实现工作单元,而不是直接使用数据映射器。要了解UoW,您必须阅读企业应用程序架构模式,因为它确实是广泛的主题。