DDDのトランザクション管理について
DDDではトランザクション管理をアプリケーション層で行うという認識でいます。
例えばUserとCompanyという2つのドメインモデルが存在し、
それぞれマスタ画面でDBへの登録処理があるとします。
登録処理をアプリケーションサービスクラスで行うときは
class UserRegisterService {
public function register(User $user)
{
// トランザクション開始
try {
// ユーザー登録処理
$this->userRepo->register($user);
commit
} catch {
rollback
}
}
}
class CompanyRegisterService {
public function register(Company $company)
{
// トランザクション開始
try {
// 会社登録処理
$this->companyRepo->register($company);
commit
} catch {
rollback
}
}
}
のように書くのではないかと思っています。
ここで更にUserとCompanyの2つを同じタイミングで登録する業務Xが存在した場合
Xサービスクラスで「UserRegisterService」と「CompanyRegisterService」
を呼んでしまうと、Userを登録したあとCompanyの登録でエラーが発生しても
rollbackするのは、当然CompanyServiceだけということになってしまいます。
かといって、Xサービスクラスで2つのサービスクラスと全く同じ処理を書いても
冗長なコードになってしまいます・・・。
こういった場合どうすればよいのでしょうか?
回答を受けての追記
あとわいと様、Vietta Toe様
サンプルのコードがだいぶ省略していて大変申し訳ないのですが
実際のクエリの発行はRepositoryというクラスが行うようになっています。(サンプルコードを編集しておきました)
つまり以下のような処理の流れになります。
View → Controller → Service → Repository → DB
サンプルのコードぐらいのシンプルなものだと
Xサービスクラスのregisterメソッドの中で、userRepoとcompanyRepoを呼び出せばいいだけの話だと思うのですが
実際の業務では登録をするためのデータの加工などをサービスクラス内で行った後、
加工したデータを引数にリポジトリを呼び出すということが多々あります。
その場合、Xサービスクラスのregisterメソッドで、データ加工処理を書いてしまうと
XサービスとUserサービスで同じ処理を書いてしまうことになってしまいます。
なので、できるだけサービスクラスを呼び出すだけにしたいのですが
このような場合でもサービスクラスの上のレイヤーにトランザクション管理を任せればよいのでしょうか?
その際、Vietta Toe様のご指摘のとおり、コントローラーでトランザクション管理をするのか、
それとも、コントローラーとサービスの間に1つレイヤーを作り、そこでトランザクションを行うのか
どうすればよいでしょうか?
説明が下手で申し訳ありません。伝わればいいのですが。。。