gpt4 book ai didi

php - SF3 文件夹结构中的 DDD

转载 作者:可可西里 更新时间:2023-11-01 12:26:56 26 4
gpt4 key购买 nike

我正在考虑一个广告网站,用户可以在其中登录、发布新列表和搜索现有列表。我将把它作为我的第一个完全遵循 DDD 原则的项目。我以前从未在 Symfony 中做过任何 DDD。

以下是我对此的看法。您能否告诉我这是否正确以及关于更好方法的建议?

我可以看到两个域:用户和列表

搜索/显示/发布功能将存在于列表域中。在用户域中实时登录/注销。

SF3目录示例结构为

app/
ListingBundle/
src/
Listing.php
SearchService.php
ListingRepositoryInterface.php
Controller/
public/
ListingController.php
protected/
ListingController.php
Resource/
view/
public/
detail.twig.html
protected/
edit.twig.html

UserBundle/
src/
User.php
AuthService.php
UserRepositoryInterface.php
Controller/
public/
UserController.php
protected/
UserController.php
Resource/
view/
public/
login.twig.html
protected/
dashboard.twig.html

PersistenceBundle
src/
UserRepository.php
ListingRepository.php

我的主要问题是:

  • 这个结构是否正确?
  • 使用相同名称的独立 protected Controller 和公共(public) Controller 是个好主意吗?
  • 网站用户后端部分的页面在哪里显示用户最近发布的列表?这两个域之间的边界在哪里?
  • PersistenceBundle 是个好主意还是我应该在 User 和 Listing bundle 中保留持久性?

最佳答案

框架和 DDD

您在这里做出了错误的假设,即“我将使用 Symfony 框架以类似 DDD 的方式实现我的应用程序”

不要这样做,Frameworks are just an implementation detail并为您的应用程序提供一种(或多种)交付方式。我的意思是应用程序在 Hexagonal Architecture 的上下文中.

如果您从我们的一个上下文中查看以下示例,您会发现我们的 ApiClient 上下文包含三层(顶级目录结构)。 Application(包含用例服务)、Domain(包含模型和行为)和Infrastructure(包含持久性和交付等基础设施问题)。我在这里专注于 Symfony 集成和持久性,因为这是 OP 最初的问题:

src/ApiClient
├── Application
│   ├── ApiClient
│   │   ├── CreateApiClient
│   │   ├── DisableApiClient
│   │   ├── EnableApiClient
│   │   ├── GetApiClient
│   │   ├── ListApiClient
│   │   ├── RemoveApiClient
│   │   └── ChangeApiClientDetails
│   ├── ClientIpAddress
│   │   ├── BlackListClientIpAddress
│   │   ├── CreateClientIpAddress
│   │   ├── ListByApiClientId
│   │   ├── ListClientIpAddresses
│   │   └── WhiteListClientIpAddress
│   └── InternalContactPerson
│   ├── CreateInternalContactPerson
│   ├── GetInternalContactPerson
│   ├── GetByApiClientId
│   ├── ListContacts
│   ├── ReassignApiClient
│   └── Remove
├── Domain
│   └── Model
│   ├── ApiClient
│   ├── ClientIpAddress
│   └── InternalContactPerson
└── Infrastructure
├── Delivery
│   └── Http
│   └── SymfonyBundle
│   ├── Controller
│   │   ├── ApiClientController.php
│   │   ├── InternalContactController.php
│   │   └── IpAddressController.php
│   ├── DependencyInjection
│   │   ├── Compiler
│   │   │   ├── EntityManagerPass.php
│   │   │   └── RouterPass.php
│   │   ├── Configuration.php
│   │   ├── MetadataLoader
│   │   │   ├── Adapter
│   │   │   │   ├── HateoasSerializerAdapter.php
│   │   │   │   └── JMSSerializerBuilderAdapter.php
│   │   │   ├── Exception
│   │   │   │   ├── AmbiguousNamespacePathException.php
│   │   │   │   ├── EmptyMetadataDirectoryException.php
│   │   │   │   ├── FileException.php
│   │   │   │   ├── MalformedNamespaceException.php
│   │   │   │   └── MetadataLoadException.php
│   │   │   ├── FileMetadataLoader.php
│   │   │   ├── MetadataAware.php
│   │   │   └── MetadataLoaderInterface.php
│   │   └── MFBApiClientExtension.php
│   ├── DTO
│   │   └── ApiClient
│   │   └── ChangeInternalContact
│   │   ├── ChangeInternalContactRequest.php
│   │   └── ChangeInternalContactResponse.php
│   ├── MFBApiClientBundle.php
│   ├── Resources
│   │   ├── config
│   │   │   ├── domain_services.yml
│   │   │   ├── metadata_loader.yml
│   │   │   ├── routing.yml
│   │   │   └── services.yml
│   │   ├── hateoas
│   │   │   └── ApiClient
│   │   │   ├── Application
│   │   │   │   ├── ApiClient
│   │   │   │   │   ├── CreateApiClient
│   │   │   │   │   │   └── CreateApiClientResponse.yml
│   │   │   │   │   └── ListApiClient
│   │   │   │   │   └── ListApiClientResponse.yml
│   │   │   │   ├── ClientIpAddress
│   │   │   │   │   ├── CreateClientIpAddress
│   │   │   │   │   │   └── CreateClientIpAddressResponse.yml
│   │   │   │   │   ├── ListByApiClientId
│   │   │   │   │   │   └── ListByApiClientIdResponse.yml
│   │   │   │   │   └── ListClientIpAddresses
│   │   │   │   │   └── ListClientIpAddressesResponse.yml
│   │   │   │   └── InternalContactPerson
│   │   │   │   ├── Create
│   │   │   │   │   └── CreateResponse.yml
│   │   │   │   └── List
│   │   │   │   └── ListResponse.yml
│   │   │   └── Domain
│   │   │   ├── ApiClient
│   │   │   │   └── ApiClient.yml
│   │   │   ├── ClientIpAddress
│   │   │   │   └── ClientIpAddress.yml
│   │   │   └── InternalContactPerson
│   │   │   └── InternalContactPerson.yml
│   │   └── serializer
│   │   ├── ApiClient
│   │   │   ├── Application
│   │   │   │   ├── ApiClient
│   │   │   │   │   ├── CreateApiClient
│   │   │   │   │   │   ├── ContactPersonRequest.yml
│   │   │   │   │   │   ├── CreateApiClientRequest.yml
│   │   │   │   │   │   └── CreateApiClientResponse.yml
│   │   │   │   │   └── GetApiClient
│   │   │   │   │   └── GetApiClientResponse.yml
│   │   │   │   ├── ClientIpAddress
│   │   │   │   │   └── CreateClientIpAddress
│   │   │   │   │   ├── CreateClientIpAddressRequest.yml
│   │   │   │   │   └── CreateClientIpAddressResponse.yml
│   │   │   │   └── InternalContactPerson
│   │   │   │   ├── Create
│   │   │   │   │   ├── CreateRequest.yml
│   │   │   │   │   └── CreateResponse.yml
│   │   │   │   ├── Get
│   │   │   │   │   └── GetResponse.yml
│   │   │   │   ├── List
│   │   │   │   │   └── ListResponse.yml
│   │   │   │   └── ReassignApiClient
│   │   │   │   └── ReassignApiClientRequest.yml
│   │   │   └── Domain
│   │   │   ├── ApiClient
│   │   │   │   ├── ApiClient.yml
│   │   │   │   └── ContactPerson.yml
│   │   │   ├── ClientIpAddress
│   │   │   │   └── ClientIpAddress.yml
│   │   │   └── InternalContactPerson
│   │   │   └── InternalContactPerson.yml
│   │   └── Bundle
│   │   └── DTO
│   │   └── ApiClient
│   │   └── ChangeInternalContact
│   │   └── ChangeInternalContactRequest.yml
│   └── Service
│   └── Hateoas
│   └── UrlGenerator.php
└── Persistence
├── Doctrine
│   ├── ApiClient
│   │   ├── ApiClientRepository.php
│   │   └── mapping
│   │   ├── ApiClientId.orm.yml
│   │   ├── ApiClient.orm.yml
│   │   ├── CompanyName.orm.yml
│   │   ├── ContactEmail.orm.yml
│   │   ├── ContactList.orm.yml
│   │   ├── ContactName.orm.yml
│   │   ├── ContactPerson.orm.yml
│   │   ├── ContactPhone.orm.yml
│   │   └── ContractReference.orm.yml
│   ├── ClientIpAddress
│   │   ├── ClientIpAddressRepository.php
│   │   └── mapping
│   │   ├── ClientIpAddressId.orm.yml
│   │   ├── ClientIpAddress.orm.yml
│   │   └── IpAddress.orm.yml
│   └── InternalContactPerson
│   ├── InternalContactPersonRepository.php
│   └── mapping
│   ├── InternalContactPersonId.orm.yml
│   └── InternalContactPerson.orm.yml
└── InMemory
├── ApiClient
│   └── ApiClientRepository.php
├── ClientIpAddress
│   └── ClientIpAddressRepository.php
└── InternalContactPerson
└── InternalContactPersonRepository.php

94 directories, 145 files

相当多的文件!

可以看到我是把bundle作为Application的Port来使用的(命名有点偏,应该不是Http传递,因为在六边形架构的严格意义上,它是一个App-To-App Port)。我强烈建议您阅读 DDD in PHP book所有这些概念实际上都用 PHP 中的富有表现力的示例进行了解释(假设您已经阅读了蓝皮书和红皮书,尽管这本书作为独立的书使用,但仍然提供引用)。

关于php - SF3 文件夹结构中的 DDD,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38900497/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com