【发布时间】:2013-10-09 21:18:46
【问题描述】:
欢迎任何想法/反馈 :)
我在一个大型 Symfony2 应用程序中遇到了如何处理围绕我的 Doctrine2 实体 的业务逻辑 的问题。 (抱歉帖子太长了)
在阅读了许多博客、食谱和其他资源后,我发现:
- 实体可能仅用于数据映射持久性(“贫血模型”),
- 控制器必须尽可能纤薄,
- 域模型必须与持久层解耦(实体不知道实体管理器)
好的,我完全同意,但是: 在哪里以及如何处理域模型上的复杂业务规则?
一个简单的例子
我们的领域模型:
- 组可以使用角色
- 一个角色可以被不同的组使用
- 一个用户可以属于许多具有许多角色的组,
在 SQL 持久层中,我们可以将这些关系建模为:
我们的具体业务规则:
- 用户可以在组中拥有角色仅当角色附加到组时。
- 如果我们从 Group G1 中分离 Role R1,则必须删除 Group G1 和 Role 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 - 通过扩展实体实现富模型
使用实体作为领域模型类的子/父类,它封装了许多领域逻辑。但是这个解决方案对我来说似乎更困惑。
对您而言,管理此业务逻辑的最佳方式是什么,专注于更干净、解耦、可测试的代码?您的反馈和良好实践?你有具体的例子吗?
主要资源:
- Symfony managing entities
- Symfony2/Doctrine, having to put business logic in my controller? And duplicating controller?
- Extending Doctrine Entity in order to add business logic
- http://iamproblematic.com/2012/03/12/putting-your-symfony2-controllers-on-a-diet-part-2/
- http://l3l0.eu/lang/en/2012/04/anemic-domain-model-problem-in-symfony2/
- https://leanpub.com/a-year-with-symfony
【问题讨论】:
标签: php symfony doctrine-orm domain-driven-design