アイデア/フィードバックは大歓迎です:)
大きなSymfony2 アプリケーションでDoctrine2 エンティティの周りのビジネス ロジックを処理する方法で問題が発生しました。(文章長くてすみません)
多くのブログ、クックブック、その他のリソースを読んだ後、次のことがわかりました。
- エンティティは、データ マッピングの永続化 (「貧血モデル」) にのみ使用される場合があります。
- コントローラーは可能な限りスリムにする必要があり、
- ドメイン モデルは永続層から分離する必要があります (エンティティはエンティティ マネージャを認識しません)。
わかりました、私はそれに完全に同意し ますが、ドメインモデルの複雑なビジネスルールをどこでどのように処理しますか?
簡単な例
私たちのドメインモデル:
- グループはロールを使用できます
- ロールは異なるグループで使用できます
- ユーザーは、多くのロールを持つ多くのグループに所属できます。
SQL永続層では、これらの関係を次のようにモデル化できます。
私たちの特定のビジネスルール:
- ロールがグループに関連付けられている場合にのみ、ユーザーはグループ内でロールを持つことができます。
- グループ G1からロール R1を切り離す場合、グループ G1 とロール R1 を持つすべてのUserRoleAffectation を削除する必要があります。
これは非常に単純な例ですが、これらのビジネス ルールを管理するための最良の方法を知りたいです。
見つかった解決策
1- サービス層での実装
特定の Service クラスを次のように使用します。
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();
}
- (+) クラスごと/ビジネス ルールごとに 1 つのサービス
- (-) 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
- Symfony2/Doctrine、コントローラーにビジネス ロジックを配置する必要がありますか? そして、コントローラーを複製しますか?
- ビジネスロジックを追加するために Doctrine Entity を拡張する
- 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