拆分Symfony 2项目?

时间:2015-11-16 17:12:31

标签: php symfony doctrine-orm domain-driven-design decoupling

我们有一个非常大的Symfony 2 Web应用程序,它有许多不同的端点和功能:

  • api来自我们的旧产品的数据
  • 用于我们旧产品的网络组件
  • api到我们的新iOS POS
  • api to忠诚度最终用户门户网站
  • 忠诚度最终用户门户网站界面
  • (单独)发票最终用户门户网站的网络界面
  • 配置上述所有
  • 的大型管理区域

这个数据库层(在Doctrine中)是紧密耦合的。来自POS和我们的旧产品的交易在忠诚度最终用户门户中使用,并且发票基于相同的交易。显然,还有许多实体仅用于应用程序的特定部分。

我们最初决定使用单一app + bundle方法来简化编程,这对我们在开发整个平台方面起到了很好的作用。不幸的是,主要的缺点是:

  • 非常糟糕的性能(虽然进一步缓存,最小化资产等问题可以提供帮助,但我们认为拥有这样一个臃肿的捆绑包需要能够处理所有内容并且还包含仅用于特定部分的不同第三方库应用程序正在减慢一切。)
  • 我们使用持续集成并生成新版本并运行所有功能测试需要20多分钟......而且我们仍有许多课程缺乏(正确)测试。
  • 当我们改变应用程序的一部分时,另一部分容易破坏。虽然越来越多的解耦和功能测试对此有所帮助,但它仍然远非理想。

我已经做了一些研究,将Symfony项目分成多个项目(每个项目都有自己的github),并使用SOA连接它们。到目前为止,我对SOA的个人经验是,在从标准的Symfony 2表单(我非常喜欢)中迁移时,它很难完全测试并增加了很多开销。

我还在考虑通过与共享实体和存储库创建共享包来实现另一种解决方案。这将使测试代码和共享公共服务(经理)变得更加容易,尽管我也听过针对大型经理的论证。这样做的一大缺点是我们不能简单地使用doctrine:schema:update,因为共享数据库并使用较低版本的共享包更新数据库,将删除字段..导致数据丢失。同样在这种方法中,我一直无法找到任何示例或用例......这让我想知道它是否会有更多的缺点。

所以我的问题是:分割这样一个大项目的常用方法和解决方案是什么?并且:有没有理由可能不应该分开?

2 个答案:

答案 0 :(得分:1)

虽然我回答了你的问题,但很难为你的问题找到一个神奇的解决方案。这不是试图解决您的所有问题,也不是强迫您遵循它。这不是唯一可行的解​​决方案,实际上这甚至可能无法解决您的问题。那就是说,让我们开始吧。

我将项目拆分为4层:

  • 表示层:桌面应用程序,Web界面(无论是否 是PHP,C#,如果它使用Symphony或任何其他框架和第三 库组件),移动应用程序,最终用户可以看到的一切 与(也称为GUI)交互。这些人只与他们沟通 应用程序/服务请求某些内容,例如可用列表 产品,在某处更新一些数据,为客户发送电子邮件。 这里的关键是他们真的不知道如何以及在哪里 应用程序/服务层将执行请求的操作。
  • 应用程序/服务层:我将此视为控制器,它可以接收来自表示层和外部Web服务的请求。它们看起来像API,并且决定是否必须通过Repository访问/操纵数据,或使用某些SMPT服务发送电子邮件。它们只是在GUI或外部Web服务之间进行通信,这可能会占用您的API和Domain / Infra层。然而,他们实际上并不知道他们正在使用什么SMPT服务,或者数据将在何处存储以及如何(在MySql中通过Doctrine?在Sql Server中通过实体框架?在NoSql数据库中?文件?)。应用程序层通常具有自己的模型(也称为ViewModels),它们向世界公开并返回给请求者(GUI或外部Web服务),代表域模型的部分。这种映射(将Domain类转换为Application类)可以使用Facade和Adapters(也称为Anti-corruption层)之类的模式完成,并且有很多软件包可以解决这个问题(对于C#,有自动映射,对于PHP可能有存在某种东西)。你为什么需要这个?避免将您的完整域名暴露给全世界。假设您拥有发票和忠诚度最终用户,但您希望将它们视为一个独特的域类"用户"与他们相应的属性在一起。您可以在应用程序中创建一个LoyaltyUser和一个InvoiceUser类,每个类只包含用于此目的的必要属性,然后使用此Mapping技术将域User类映射到它们中的每一个。因此,应用程序层通常包含身份验证和授权规则,因此只有忠诚度最终用户才有权访问控制器处理LoyaltyUser模型的操作。在控制器中的单个操作中,您不应采取不同的路径/方式,具体取决于请求者(对于移动设备,执行此操作,对于网站,请执行此操作)。相反,您可能对每个操作都有不同的操作,并且表示层将知道他们想要请求的内容。
  • 域层:这是您的核心,包含所有业务逻辑。这是为您的业务提供价值的东西。域层容器 代表你的世界,接口的真实实体的模型/类 用于服务和存储库。域必须是最干净的 自然可能。他们无法知道应用程序在询问什么 某事,也没有使用何种类型的基础设施。他们只是做生意 逻辑。 Domain层不知道您是使用Doctrine还是Laravel作为ORM,也不知道该应用程序是使用Symphony或Android Native App完成的php网站。
  • Infra Layer:在这里,您可以实现数据库,SMPT服务,日志记录以及应用程序可能需要的其他内容。 学说会留在这里。因此,您将创建存储库 实现域的存储库接口的类。该 存储库实现使用Doctrine来完成工作。这些 实现是提供给应用层(通常是通过 依赖注入)。这意味着应用层不应该 知道是Doctrine还是Laravel,这就是应用程序使用的原因 存储库(因此封装了访问数据库的逻辑)。

您的网络界面将驻留在演示文稿中。如果您在Web中使用的框架必须使用MVC并因此具有控制器,则这些控制器应该分派到应用层(我知道它听起来是多余的)。您的API将驻留在应用程序层中。

这是非常分离的,如果您需要从Doctrine更改为Laravel,您不需要更改域名或应用程序。如果您需要从Symphony更改为其他任何内容,甚至将您的网站从PHP更改为ASP或Java,您的域名都不必更改。

添加更多图层,映射对象,使用DI不应该使请求变慢,考虑到现在的硬件价格和容量,时间的差异几乎察觉不到。您应该努力改善您的域名,从而为业务带来价值。分离层可以改善解耦,改变部分应用程序破坏其他部分的可能性,提高扩展应用程序的灵活性,并使测试更容易。

答案 1 :(得分:0)

Rein,你最终得到的解决方案是什么?你真的拆分了你的项目吗?

这方面确实缺乏信息,我刚刚找到一篇合理的文章https://ig.nore.me/presentations/2015/04/splitting-a-symfony-project-into-separate-tiers/