欢迎任何想法/反馈:)
我遇到了如何在大型Symfony2 应用程序中处理围绕我的Doctrine2 实体的业务逻辑的问题。(对不起,帖子长度)
在阅读了许多博客、食谱和其他资源后,我发现:
- 实体可能仅用于数据映射持久性(“贫血模型”),
- 控制器必须尽可能纤薄,
- 领域模型必须与持久层解耦(实体不知道实体管理器)
好的,我完全同意它,但是: 在哪里以及如何处理域模型上的复杂业务规则?
一个简单的例子
我们的领域模型:
- 组可以使用角色
- 一个角色可以被不同的组使用
- 一个用户可以属于许多具有许多角色的组,
在SQL持久层中,我们可以将这些关系建模为:
我们的具体业务规则:
- 仅当角色附加到组时,用户才能在组中拥有角色。
- 如果我们从组 G1中分离角色 R1 ,则必须删除组 G1 和角色 R1 的所有UserRoleAffectation
这是一个非常简单的示例,但我想知道管理这些业务规则的最佳方式。
找到的解决方案
1- 服务层的实现
使用特定的服务类:
class GroupRoleAffectionService {
function linkRoleToGroup ($role, $group)
{
//...
}
function unlinkRoleToGroup ($role, $group)
{
//business logic to find all invalid UserRoleAffectation with these role and group
...
// BL to remove all found UserRoleAffectation OR to throw exception.
...
// detach role
$group->removeRole($role)
//save all handled entities;
$em->flush();
}
- (+) 每个类/每个业务规则一项服务
- (-) API 实体不代表域:可以
$group->removeRole($role)
从该服务中调用。 - (-) 大型应用程序中的服务类太多?
2 - 在域实体管理器中的实现
将这些业务逻辑封装在特定的“域实体管理器”中,也称为模型提供者:
class GroupManager {
function create($name){...}
function remove($group) {...}
function store($group){...}
// ...
function linkRole($group, $role) {...}
function unlinkRoleToGroup ($group, $role)
{
// ... (as in previous service code)
}
function otherBusinessRule($params) {...}
}
- (+) 所有业务规则都是中心化的
- (-) API 实体不代表域:可以从服务中调用 $group->removeRole($role) ...
- (-) 域管理员变成 FAT 管理员?
3 - 尽可能使用监听器
使用 symfony 和/或 Doctrine 事件监听器:
class CheckUserRoleAffectationEventSubscriber implements EventSubscriber
{
// listen when a M2M relation between Group and Role is removed
public function getSubscribedEvents()
{
return array(
'preRemove'
);
}
public function preRemove(LifecycleEventArgs $event)
{
// BL here ...
}
4 - 通过扩展实体实现富模型
使用实体作为领域模型类的子/父类,它封装了许多领域逻辑。但是这个解决方案对我来说似乎更困惑。
对您而言,管理此业务逻辑的最佳方式是什么,专注于更干净、解耦、可测试的代码?您的反馈和良好做法?你有具体的例子吗?
主要资源: