symfony2 实体、存储库、服务混乱

Posted

技术标签:

【中文标题】symfony2 实体、存储库、服务混乱【英文标题】:symfony2 entity, repository, service confusion 【发布时间】:2013-02-22 16:33:27 【问题描述】:

我对服务、实体和存储库以及我应该将我正在从事的项目的内容放在哪里有点困惑。我想我错过了一些东西,我担心我会以错误的方式去做。我不认为原则映射表名称非常适合报告,因为有很多列,并且这些列通常是其他 groupby 在日期、月份、年份等上的结果。

项目的简要简化概述是基于 Web 的报告的集合(作为捆绑包)。

为了创建报告,我必须使用销售日志包预先构建数据。销售日志从事务数据库中获取数据并将其放入准备好由各种其他报告运行的表中,即具有自定义索引等的报告。数据聚合是解释它的更好方法。数据源拥有数百万年前的预订数据,因此直接基于源的报告效率不高,因此销售日志就派上用场了。

SalesJournalBundle      - fetches data from source and puts it into a table ready for other reports
WeeklyConversionReportBundle  - exports sales journal into weekly conversion report table has functions for totals for the week, totals for month, etc
OtherReportBundle             - etc

销售日志

类来运行销售日志并从大表导出到另一个表。

createQuery($parameters);
runQuery($exportTableName);

WeeklyConversionBundle

// runs the sales journal and saves to the report.  Entity? Or Service or Repoistory?
runSalesJournalQuery();  

// generates conversion figures and saves the to the table? Entity Or Service or Repoistory?
generateConversions();   


getWeekTotals();         // used when displaying the report..
getMonthTotals($month)   // used when displaying the report..
getTotals()              // used when displaying the report..
etc.

所以当我开始项目时,我假设所有函数都属于实体类。但是我不确定它们是否是严格的模型,因为它们需要数据库访问和对其他类的访问?困惑在哪里放置类/方法。任何反馈将不胜感激。

【问题讨论】:

【参考方案1】:

当您谈到运行销售日志并将其从一个大表导出到另一个表时,我认为您的意思是让不同的 Services 做一些小事并共同完成这项大任务。

假设您需要这样的结构:

ExportSalesJournalService - 这需要依赖于可以访问数据库的Repository 类。它可能是一个SalesJournalRepository,带有一些自定义方法来运行自定义查询。

ImportSalesJournalService - 这也需要与另一个相同的依赖项。

RunSalesJournalService - 无论您所说的 running the sales journal 是什么意思。如果它需要数据库,请通过依赖 Repository 来解决这个问题。如果不是,那只是一个纯粹的老式 php 类,它可以完成一些任务。

请记住尽可能多地尝试解耦事物,这样您就可以拥有独立的对象。这对可维护性、可测试性和其他方面也有好处。

另一件要考虑的事情是你真的不需要遵循默认的 Symfony 标准应用程序结构,就像我在 this post 中提到的那样。这将为您提供更低耦合的架构。

Entities 也是代表某些东西的纯 PHP 类。在大多数情况下,它们应该是愚蠢的对象。绝不,绝不,将业务特定代码或数据库访问权限放入其中。

对于转换生成,自定义Service 可能也是要走的路。名为 ConversionGenerationService 或类似名称的名称。

请记住在其类名中提供对象的意图。这真的很重要。

关于报告,我可能会根据特定的Repositories 创建一个Service 来生成它们。请记住通过构造函数或设置器明确解决依赖关系。

【讨论】:

感谢您的回复。我认为关键字运行有帮助。销售日记帐查询的运行需要成为一项服务。当您扩展存储库时,这是否意味着您必须使用学说 sql? 存储库是由教义提供的用于管理查询的类。你可以通过添加自定义方法来扩展它。 如何将依赖项添加到服务中以便可以运行查询? 您只需通过服务构造函数或 setter 方法传递依赖项。 如何通过服务构造函数实现?【参考方案2】:

    假设您在这里使用 Doctrine。

    实体中不应有查询。它们保存数据,也许还有一些业务逻辑。所以把它们从你的名单上划掉。

    通常,存储库是放置查询的地方。所以从 runSalesJournalQuery 开始

    generateConversions 可能属于服务。我猜它必须在持久化结果之前进行大量处理。

    get 内容可以放在存储库或服务中。如果它主要是一个查询,那么从存储库中开始。如果它主要处理查询的结果,那么服务可能会更好。

还请记住,您实际上只能拥有一个存储库。跨多个服务分发内容可能会使您的代码更易于管理。

【讨论】:

实体真的不应该持有业务逻辑。它们被认为是存储数据和表示某些东西的愚蠢对象。业务逻辑应该放在domain model 或service layer 中。 这很容易沦为那些宗教战争的东西之一。恕我直言,实体可以而且经常确实拥有业务逻辑。但这与问题并不真正相关。我们似乎都同意数据库查询不应该进入实体。 我正在使用学说,但对于某些查询,我使用原始 sql 仅仅是因为查询太大。将非原则查询放在存储库中是一种好习惯吗? 这真的取决于。但是,如果您要处理数千条(或更多)记录,那么您将很快遇到内存限制(使用原则)。您可能应该只将数据库连接对象注入服务并让您的东西在没有教义的情况下运行。特别是如果您只有一张桌子要处理。 考虑接受@drgomesp 的回答。我认为您的原始问题已得到解答。如果您卡在特定的实施细节上,请打开一个新的。

以上是关于symfony2 实体、存储库、服务混乱的主要内容,如果未能解决你的问题,请参考以下文章

如何在 LoginListener 中的 onSecurityInteractiveLogin 方法中重定向 - Symfony2

Symfony 2 Doctrine 内存使用情况

symfony2 createQueryBuilder

Symfony 2.0 在实体内部获取服务

Symfony2,学说和数据域

Symfony2与列的实体关系