我最近几天对DDD(领域驱动设计)感兴趣,但我无法弄清楚谁创建和验证实体的责任。我会打破这些问题以涵盖不同的情景。
常规实体(可能带有价值对象)。举个例子,我们可以选择一个由Email识别的用户。我有一个UserFactory接收一个数据数组(可能来自表单POST),并返回一个新的UserEntity。工厂应该验证数据的完整性(例如:作为电子邮件提供的字符串是真实的电子邮件,密码字段1和字段2中的密码匹配等)?工厂是否应该验证不存在此类用户(我们不想使用相同的电子邮件注册两个用户)?如果是,它应该是我自己还是使用UserRepository?
汇总实体。让我们假设我们有一个Post实体和Comments实体。我希望在帖子12中发表所有评论,所以我做了类似
的事情$ post = $ postRepository-> getById(12);
如何实施getById?像这样:
public function getById($id) {
$postData = $this->magicFetchFromDB($id);
$comments = (new CommentRepository())->getForPost(12);
return new PostEntity($postData, $comments);
}
也许是负责懒惰创建评论的帖子,如:
class PostEntity {
public function getComments() {
if(is_null($this->_comments)) $this->_comments = (new CommentRepository())->getForPost($this->_id);
return $this->_comments;
}
}
? 我在这里很丢失,并且没有足够的信息提供PHP中的DDD示例,所以任何帮助都将不胜感激!
非常感谢, skwee。
答案 0 :(得分:4)
工厂仅关心创建实体。我个人更喜欢在我的视图和模型层中进行验证。我会使用像jQuery的验证插件这样的库来在客户端进行一些必要的验证(比如检查必需字段是否有数据)。然后对模型进行“硬核”验证。 我这样做是通过使用所有实体扩展的简单BaseEntity抽象类,并且因为你问了一个例子,这里是:
abstract class BaseEntity {
public function isValid();
}
class MyEntity extends BaseEntity {
public function isValid() {
//actual validation goes here
}
}
您还可以使用带有一些基本验证方法的静态助手类:
class ValidationHelper {
public static function isValidPhonenumber($value) {
//check valid phonenumber, using a regex maybe
}
public static function isAlphanumeric($value) {
//check for letters and numbers only
}
}
许多人反对静态方法,因为它们可以破坏单元测试,但在这种情况下,它们非常基本,并且没有外部依赖性,从而使它们“更安全”。
在检查现有实体时,您可以通过在添加/更新之前查询数据库以查看实体是否已经存在,或者(我喜欢这样做)您可以添加对那些无法在数据库中重复的列的unique
索引,然后将创建或更新查询包装在try-catch块中(如果两个用户具有相同的e,则查询将抛出唯一的约束违例例如,邮件)然后显示正确的错误消息
关于你的最后一个问题,归结为一个偏好问题。如果您的数据库在1分钟内会获得一百万次点击,那么使用延迟加载可能会更好,以避免在需要之前获取不必要的数据。但是,如果您的数据库相对较小,您可以完全使用急切加载而不会牺牲太多性能。 同样,这是个人偏好的问题。
答案 1 :(得分:1)
最好和最简单的方法是使用Doctrine2。也许第一个小时会很难,但是一旦掌握了Doctrine2,所有这些关系和聚合都是小菜一碟。
您可以找到有关PHP&的大量信息。 http://giorgiosironi.blogspot.com/上的DDD或Doctrine2,或者只是通过Google搜索。
RE:验证 - 考虑单一责任原则,我们使用验证对象。验证可能很复杂,可能需要其他存储库或实体,因此最好将其与实际实体区分开来 - 验证的主题是为了避免创建膨胀对象。您可以使用访客或规范设计模式。
此处有很多关于这些主题的帖子 - 尝试使用上述关键字。