mvcでは、モデルはレイヤーであり、すべてのドメインビジネスロジックが含まれています。
ドメイン駆動設計では、ビジネスロジックは次のようなさまざまな構成要素に分割できます。
ドメイン駆動設計では、ドメインモデルはです。
ドメインモデルは、知識、影響、または活動の領域(ドメイン)の選択された側面を記述する抽象化のシステムです。その後、モデルを使用して、そのドメインに関連する問題を解決できます。
開発者はドメイン駆動設計を読んだか、Doctrine2またはHibernateを使用しており、通常はDDDのドメインモデルに重点を置いています。mvcフレームワークでは、モデルレイヤーはDDDのドメインモデルと重複しています。つまり、のモデルフォルダーにドメインモデルを実装できます。 mvcフレームワーク
このような実装を以下に示します。モデルフォルダの構造を示します
Model(this can model or domain)
|
|----Entities
| |---BlogPost.php
| |---Comment.php
| |---User.php
|
|----Repositories
| |---BlogPostRepository.php
| |---CommentRepository.php
| |---UserRepository.php
|
|----Services
| |---UserService.php
|
|----factories
| |---userfactory.php
|
|----dataMappers
| |---userDataMapper.php // this inherit from Eloquent model
|
|----ValueObject
mvcでは、モデルはレイヤーであり、すべてのドメインビジネスロジックが含まれています。
MVCパターン自体がドメインについて何か特別なことを宣言しているとは思えません。モデルをプロパティのバッグとして操作し、モデルがどのように作成され、どのように不変条件を保護するかを気にしません。
同時に オニオンアーキテクチャ は、ドメインをアプリケーションサービス(MVCフレームワーク)から分離することが重要であると述べています。だから私はエンティティ、値オブジェクト、を含むドメインレイヤーを配置するのが好きですドメインイベントおよびAggregatesを別のモジュールまたはトップレベルフォルダーに。
ドメインをMVCのものとは別に配置するもう1つの理由は、各コンテキストに独自のモジュール/フォルダーが必要なため、複数の 制限付きコンテキスト を簡単に管理できるようになることです。
this ASP MVC project 構造。有名なDDDエキスパートによって設計されました。ドメインの他に、MVC部分がどのようになっているのかを確認することをお勧めします。組織化されています。これは、最近ますます人気が高まっている 機能スライス アプローチを利用しており、非常に便利です。
私はDDDの世界にまったく慣れていませんが、アプリケーションを徐々にDDD指向の構造に移行する過程で、ディレクトリ構造の問題にも直面しました。完全に概念的ではないことがわかった情報をつなぎ合わせて、次の簡略化されたディレクトリ構造(CRUD指向のLaravelアプリケーション)内に存在)を思いつきました。十分に:
app/
ProjectName/
Core/
Application/
Domain/
Infrastructure/
User/
Application/
Services/
CreateUserService.php
FindUserService.php
UpdateUserService.php
Domain/
Role.php
RoleDAO.php
User.php
UserDAO.php
UserNotCreated.php
UserNotFound.php
UserNotUpdated.php
UserWasCreated.php
UserWasUpdated.php
Infrastructure/
EloquentRoleDAO.php
EloquentUserDAO.php
特定の懸念事項に対処するために、リポジトリインターフェイスとエンティティは、アプリケーションの分離可能な各コンポーネント(例:ユーザー)の下のドメインフォルダ内に配置されました。さらに、これは私がドメインイベントと例外を配置した場所です。リポジトリの実装は、各インフラストラクチャフォルダの下に配置されました。アプリケーションサービスは、アプリケーションディレクトリの下のサービスディレクトリ内に配置されます。
私自身のアプリケーションのハイブリッドな性質(ORMに依存するDAO /エンティティ、トランザクションスクリプトを使用し、いくつかの転換を示すために値オブジェクトを回避している)は別として、これは潜在的なDDDディレクトリの大まかなアイデアとして役立つ可能性がありますMVCアプリ内の構造。
@Zharroの提案に同意します。
良い構造は以下のようなものです:
1)ビューパーツアクセスはCoreBundleのみであり、データベースの動作は変更されません。
2)コアパーツアクセスBuisnessLogicおよびエンティティ
3)BuisnessLogicパーツアクセスのみエンティティ
4)エンティティ部分はデータベースにのみアクセスします。
最初の仮定は正しくありません。MVCは実際にはDDDに適合しません。より良いアプローチは、CQRSパターンを使用することです。
2番目の仮定も正しくありません。ビルディングブロックがすべてドメインモデルフォルダーにあるわけではありません。実際、プロジェクトに適した構造は次のとおりです。
ProjectName/
Application/
Blog/
Command/
CommentToBlogPostCommand.php
ChangeCommentContent.php
DescribeBlogPostCommand.php
NewBlogPostCommand.php
...
Data/
BlogPostData.php
BlogPostCommentsData.php (POPO containing BlogPost infos and the comments array)
CommentData.php (Single comment infos)
BlogPostApplicationService.php
BlogPostQueryService.php
CommentApplicationService.php
CommentQueryService.php
Identity/
Command/
AuthenticateUserCommand.php
ChangeEmailAddressCommand.php
ChangeUserPasswordCommand.php
ChangeUserPersonalNameCommand.php
DefineUserEnablementCommand.php
RegisterUserCommand.php
UserApplicationService.php (this defines the actions that can be done by your application related to user domain, injected in presentation layer responding to user events)
UserQueryService.php (this will usually be injected in your presentation layer)
Domain/
Model/
Blog/
BlogPost.php
BlogPostClosed.php (this could be a list of possible events)
BlogPostDescriptionChanged.php
BlogPostModeratorChanged.php
BlogPostReopened.php
BlogPostStarted.php
BlogPostRepository.php (interface)
Comment.php (this is an Entity, or Aggregate Root)
CommentContentAltered.php (this could be an event)
CommentAuthor.php (this could be a ValueObject, containing the username)
CommentRepository.php (interface)
CommentedToBlogPost.php (this could be another event when adding a comment to a blogpost)
...
Identity/
ContactInformation.php (VO or Person)
Enablement.php (VO of User)
EmailAddress.php (VO of ContactInformation)
FullName.php (VO or Person)
Person.php (ValueObject of User)
User.php (constructor visibility might be package-protected)
UserFactory.php
UserRepository.php (this is an interface)
UserService.php (this is a domain service)
Infrastructure/
Persistence/
LavarelBlogPostRepository.php (this implements BlogPostRepository)
LavarelCommentRepository.php (this implements CommentRepository)
LavarelUserRepository.php (this implements UserRepository)
Interfaces/
...
そうすれば、疑似MVCを維持できますが、ViewとControllerがInterfacesパッケージにあり、RichModelがdomain/modelパッケージにあるという違いがあります。モデルを操作できるのは、アプリケーションサービスを介して、およびクエリサービスを介してモデルをクエリすることだけです。クエリサービスは、モデル表現への高速アクセスを提供し、コマンドはアプリケーションサービスに送信されてコントローラーとして動作します。
CommentAuthorクラスは、データベースのユーザーIDではなく、一意のユーザー名を含む値オブジェクトである可能性があることに注意してください。ユーザー集約ルートは別のパッケージからのものであるため、これはドメインPointOfViewから意味があります。これをID(またはユーザー名)と呼ぶことができます。これは、理想的にはUserテーブルの一意の列にマップされますが、Commentテーブルのインデックス値になります。
別のオプションは、ブログである同じ概念の一部としてブログパッケージのユーザーを使用することですが、DDDはこのアプローチを推奨していません。実際には、IdentityとAccessを別の制限されたコンテキストに配置することをお勧めしますが、作成しているアプリケーションのコンテキストでは、コメントの一部としてユーザーをマッピングしても問題ない可能性があります。
インフラストラクチャ層では、永続性プロバイダーを定義します。そうすれば、Doctrineに切り替えたい日に、このパッケージの実装のみを変更する必要があります。
アプリケーション層は、セキュリティの管理、トランザクションコンテキストのスパン、および高レベルのイベントのログ記録を担当します。
いくつかの説明が必要な場合は、クラスの内部についてより多くの洞察を提供できます。また、これを機能させるには、インフラストラクチャまたはサポートフレームワークが必要になる場合があります。
MVCのモデルは、ViewModelとコマンドの組み合わせであると考えています。着信要求は、適切な集計を取得してその上で適切なメソッドを呼び出し、トランザクションをコミットする「書き込み」レイヤーにディスパッチされるコマンドにマップされます。
ViewModelは、ユーザーインターフェイス用のプレゼンテーション対応形式でデータを伝送するためだけに存在します。データベースビューまたはテーブルにクエリを実行し、結果をクライアントに返す非常に単純な「読み取り」レイヤーを作成できます。これにより、ゲッターとセッターを介してすべての状態を公開しないドメインモデルを作成できます。