在第一章中,我提到过面向领域的Laravel项目的一个特点是:
[…]最重要的是,你开始以相关业务概念的组为单位进行思考,而不是以具有相同技术属性的代码组为基础进行思考。
换言之:根据代码在现实世界中的相似性对代码进行分组,而不是基于代码库中的用途。
我还写道,域代码和应用程序代码是两回事。而且,如果应用程序需要向最终用户公开域功能,则允许它们一次使用多个域组。
但是到底什么属于这个应用层呢?我们在那里如何分组代码?这些问题将在本章中得到解答。
我们进入应用层。
多个应用程序
最重要的事是要明白,一个项目可以有多个应用程序。实际上,默认情况下,每个 Laravel 项目已经有两个:HTTP 和控制台应用程序。尽管如此,你项目的其他部分仍可以视为独立应用程序:每个第三方集成,REST API,前端客户端门户,管理员后台以及其他功能。
所有这些都可以看作是单独的应用程序,它们针对各自的独特用例公开和展示该域。实际上,我倾向于将 artisan 控制台视为此列表中的另一个:它是开发人员用于处理和操纵项目的应用程序。
因为我们从事的是 web 开发,所以我们主要关注的可能是与 http 相关的应用程序。那么它们都包含了什么呢?让我们看一看:
- Controllers
- Requests
- Application-具体特定的验证规则
- Middleware
- Resources
- ViewModels
- QueryBuilders — 用于解析URL查询
我甚至认为 blade 视图、JavaScript 和 CSS 文件属于一个应用程序,不应该放在 resources
文件夹中。我知道这对很多人来说都太过分了,但至少我想提一下。
记住,应用程序的目的是获取用户的输入,将其传递给域,并以用户可用的方式表示输出。在对领域代码进行了几章深入的研究之后,大多数应用程序代码仅仅是结构化的,通常是枯燥的代码;将数据从一个点传递到另一个点也不奇怪。
尽管如此,关于上述几个概念仍有很多要讲的:ViewModels,第三方集成,以及任务(job)。我们将在以后的章节中讨论这些主题,但是现在,我们希望专注于应用程序层背后的主要思想以及它们的一般概述。
结构化 HTTP 应用程序
在继续之前,我们需要讨论一个非常重要的问题:通常如何构造 HTTP 应用程序?我们应该遵循 Laravel 的惯例,还是需要再考虑一下?
因为我用了一章的一节来讨论这个问题,你大概可以猜出答案。那么让我们看看 Laravel 在默认情况下会推荐你做什么。
App/Admin
├── Http
│ ├── Controllers
│ ├── Kernel.php
│ └── Middleware
├── Requests
├── Resources
├── Rules
└── ViewModels
这种结构在小项目中很好,但说实话,它不能很好地扩展。为了阐明我的意思,我将向你展示我们的一个客户项目中的一个管理应用程序的文档结构。显然我不能透露太多关于这个项目的信息,所以我把大部分的类名都涂掉了。由于在整个系列中我们一直使用发票作为示例,所以我在管理应用程序中突出显示了一些与发票相关的类。看看。
哦,滚动条快乐!
App/Admin
├── Controllers
│ ├── █████████
│ │ ├── ███████████████████.php
│ │ ├── ████████████████████████████████.php
│ │ ├── ███████████████████████.php
│ │ ├── ██████████████████████████████████.php
│ │ ├── ███████████████████████.php
│ │ ├── █████████████████████████.php
│ │ ├── ███████████████████████.php
│ │ ├── ███████████████████████████████.php
│ │ ├── ██████████████████.php
│ │ └── ████████████████.php
│ ├── ████████████
│ │ ├── ████████████████████████████████.php
│ │ ├── ████████████████
│ │ │ ├── ████████████████████████████████.php
│ │ │ ├── █████████████████████████████████████████.php
│ │ │ ├── ██████████████████████████████.php
│ │ │ ├── ████████████████████████████████.php
│ │ │ ├── ███████████████████████████████.php
│ │ │ └── ████████████████████████████████.php
│ │ ├── █████████████████████████████████.php
│ │ ├── ██████████████████████████████████.php
│ │ ├── █████████████████████████████████.php
│ │ ├── ██████████████████████████████.php
│ │ ├── █████████████████████████████.php
│ │ ├── █████████████████████████████████████████.php
│ │ ├── █████████████████████████████████████.php
│ │ ├── ██████████████████████████████████.php
│ │ ├── █████████████████████████████████████████.php
│ │ ├── ████████████████████████████████████.php
│ │ ├── █████████████
│ │ │ ├── █████████████████████████████.php
│ │ │ ├── ███████████████████████████.php
│ │ │ ├── █████████████████████████████.php
│ │ │ ├── ███████████████████████████████████████████.php
│ │ │ ├── ███████████████████████████████████████.php
│ │ │ ├── ████████████████████████████.php
│ │ │ └── █████████████████████████████.php
│ │ ├── ██████████████████████████████.php
│ │ └── █████████████████████████.php
│ ├── ███
│ │ ├── ████████████████████.php
│ │ ├── ██████████████████████.php
│ │ ├── █████████████████████.php
│ │ ├── █████████████.php
│ │ ├── █████████████████████.php
│ │ ├── ██████████████████.php
│ │ ├── ██████████████████.php
│ │ ├── ██████████████████████.php
│ │ ├── ██████████████████████.php
│ │ ├── ███████████████████.php
│ │ ├── ████████████████████.php
│ │ ├── ██████████████████.php
│ │ ├── ██████████████████████████.php
│ │ ├── ████████████████████.php
│ │ ├── ██████████████████.php
│ │ └── ████████████████.php
│ ├── ███████████████████.php
│ ├── █████████████████████.php
│ ├── ████████████
│ │ ├── ███████████████████████.php
│ │ ├── ██████████████████.php
│ │ ├── ████████████████████.php
│ │ ├── ████████████████████.php
│ │ ├── ████████████████████████
│ │ │ ├── █████████████████████████████████████████.php
│ │ │ ├── ██████████████████████████████████████.php
│ │ │ ├── █████████████████████████████████.php
│ │ │ ├── ██████████████████████████████.php
│ │ │ ├── ███████████████████████████████.php
│ │ │ ├── ███████████████████████████████████████.php
│ │ │ ├── ███████████████████████████████.php
│ │ │ ├── ████████████████████████████████████████.php
│ │ │ └── █████████████████████████████████████.php
│ │ ├── Invoices
│ │ │ ├── ████████████████████████████████████.php
│ │ │ ├── █████████████████████.php
│ │ │ ├── IgnoreMissedInvoicesController.php
│ │ │ ├── ██████████████████████.php
│ │ │ ├── ████████████████████.php
│ │ │ ├── InvoiceStatusController.php
│ │ │ ├── InvoicesController.php
│ │ │ ├── MissedInvoicesController.php
│ │ │ ├── ████████████████████████.php
│ │ │ └── RefreshMissedInvoicesController.php
│ │ ├── ████████
│ │ │ └── █████████████████████.php
│ │ ├── ██████████████████.php
│ │ └── ██████████████████.php
│ ├── ███████████████████
│ │ ├── ████████████████████████.php
│ │ ├── ████████████████████████████.php
│ │ ├── ███████████████████.php
│ │ ├── ████████████████████.php
│ │ ├── ████████████████████.php
│ │ ├── ██████████████████████████.php
│ │ ├── ███████████████████████████.php
│ │ ├── ██████████████████████████████████.php
│ │ ├── ███████████████████████████████████.php
│ │ ├── ██████████████████████████.php
│ │ ├── ███████████████████████████████.php
│ │ ├── ████████████████████████████████.php
│ │ ├── ████████████████████████.php
│ │ ├── ████████████████████████.php
│ │ ├── █████████████████████.php
│ │ ├── ██████████████████████████.php
│ │ ├── ██████████████████████████████.php
│ │ ├── ██████████████████████████.php
│ │ ├── ███████████████████████.php
│ │ ├── ██████████████████████.php
│ │ ├── ████████████████████████████.php
│ │ ├── ███████████████████████.php
│ │ ├── █████████████████████████████.php
│ │ ├── ██████████████████████.php
│ │ ├── ███████████████████████████████.php
│ │ ├── ███████████████████████.php
│ │ ├── ███████████████████████.php
│ │ ├── ███████████████████████████████.php
│ │ ├── ████████████████████████.php
│ │ ├── ██████████████████████████████.php
│ │ ├── ███████████████████████████████.php
│ │ ├── █████████████████████████.php
│ │ ├── ██████████████████████.php
│ │ ├── ███████████████████████████.php
│ │ ├── █████████████████████████████████.php
│ │ ├── ███████████████████████████.php
│ │ ├── ████████████████████████████.php
│ │ ├── ████████████████████.php
│ │ └── ███████████████.php
│ ├── ███████████████.php
│ ├── ███████████████.php
│ ├── █████████████
│ │ ├── █████████████████████.php
│ │ ├── █████████████████████████████.php
│ │ ├── ████████████████████████████.php
│ │ ├── ███████████████████████████.php
│ │ ├── ██████████████████████████.php
│ │ ├── ██████████████████████████.php
│ │ └── █████████████████████████.php
│ ├── ██████████████████.php
│ ├── █████████████████.php
│ ├── █████████████████████████.php
│ ├── ██████████████████████.php
│ ├── ████████
│ │ ├── ███████████████████.php
│ │ ├── ███████████████████████████.php
│ │ ├── █████████████████████.php
│ │ └── █████████████████.php
│ ├── ███████████████
│ │ ├── █████████████████.php
│ │ ├── ███████████████.php
│ │ ├── ██████████████.php
│ │ ├── ████████████████████████.php
│ │ ├── ██████████████████████████.php
│ │ ├── ██████████████████████████.php
│ │ └── ███████████████████.php
│ ├── ████████████████████.php
│ ├── ██████████
│ │ ├── ███████████████████████████.php
│ │ ├── ██████████████████.php
│ │ ├── ███████████████████.php
│ │ ├── ███████████████.php
│ │ ├── ████████████████████████.php
│ │ ├── █████████████████████████████.php
│ │ ├── ████████████████████████.php
│ │ ├── █████████████████████.php
│ │ ├── ████████████████████.php
│ │ ├── ████████████████████████.php
│ │ ├── ████████████████████████████.php
│ │ ├── ███████████████████████.php
│ │ ├── ███████████████████.php
│ │ ├── ███████████████████████.php
│ │ ├── ████████████████.php
│ │ ├── ██████████████████.php
│ │ ├── █████████████████.php
│ │ ├── ██████████████████.php
│ │ ├── █████████████████████████████.php
│ │ ├── ██████████████████████.php
│ │ ├── ████████████████████.php
│ │ ├── ████████████████████████.php
│ │ ├── ███████████████████.php
│ │ ├── ███████████████.php
│ │ └── ██████████████████.php
│ ├── ███████
│ │ └── ████████████████.php
│ └── ███████████████.php
├── Filters
│ ├── ████████████████████.php
│ ├── ███████████████████████████.php
│ ├── █████████████████████████.php
│ ├── ██████████████████████████████████.php
│ ├── ██████████████████████.php
│ ├── █████████████████████████████.php
│ ├── ██████████████████████████.php
│ ├── ████████████████.php
│ ├── ███████████.php
│ ├── ███████████.php
│ ├── ████████████████.php
│ ├── InvoiceMonthFilter.php
│ ├── InvoiceOfferFilter.php
│ ├── InvoiceStatusFilter.php
│ ├── InvoiceYearFilter.php
│ ├── █████████████████████.php
│ ├── ███████████.php
│ └── ███████████████████.php
├── Middleware
│ ├── ██████████████████████████.php
│ ├── █████████████████████.php
│ ├── █████████████████████████████████.php
│ ├── █████████████████████████████████████.php
│ ├── EnsureValidHabitantInvoiceCollectionSettingsMiddleware.php
│ ├── EnsureValidInvoiceDraftSettingsMiddleware.php
│ ├── ██████████████████████████████████.php
│ ├── EnsureValidOwnerInvoiceCollectionSettingsMiddleware.php
│ ├── ██████████████████████.php
│ ├── █████████████████████.php
│ ├── █████████████████████████████.php
│ ├── █████████████████████████████████.php
│ ├── ████████████████████.php
│ ├── ███████████████████.php
│ └── █████████████████.php
├── Queries
│ ├── ██████████████████.php
│ ├── ███████████████████████████.php
│ ├── ██████████████████.php
│ ├── ████████████████████████.php
│ ├── ██████████████████████.php
│ ├── ██████████████████.php
│ ├── ██████████████████████.php
│ ├── ███████████████████.php
│ ├── ████████████████████████.php
│ ├── █████████████████████████████.php
│ ├── ████████████████████████.php
│ ├── ████████████████████.php
│ ├── █████████████████████.php
│ ├── ███████████████████.php
│ ├── ████████████████████.php
│ ├── █████████████████████████.php
│ ├── ██████████████████████.php
│ ├── ███████████████████████.php
│ ├── ██████████████████.php
│ ├── ██████████████████████████████████.php
│ ├── ███████████████████████████.php
│ ├── █████████████████████.php
│ ├── InvoiceCollectionIndexQuery.php
│ ├── InvoiceIndexQuery.php
│ ├── █████████████████████████████.php
│ ├── ███████████████████████.php
│ ├── ███████████████.php
│ ├── ████████████████████████████.php
│ ├── ████████████████████████.php
│ ├── ██████████████████.php
│ ├── █████████████████████.php
│ ├── █████████████████████████████.php
│ ├── ████████████████████.php
│ ├── ████████████████.php
│ ├── ██████████████████.php
│ ├── █████████████████████████.php
│ ├── ████████████████████████.php
│ ├── █████████████████████.php
│ ├── ██████████████████.php
│ ├── ███████████████████.php
│ ├── ███████████████.php
│ └── ███████████████.php
├── Requests
│ ├── █████████████████████████.php
│ ├── █████████████████████.php
│ ├── ██████████████.php
│ ├── ██████████████.php
│ ├── ██████████████.php
│ ├── ████████████████.php
│ ├── ██████████████████████████████.php
│ ├── ███████████████████████.php
│ ├── ███████████████████████████████.php
│ ├── █████████████████████████████.php
│ ├── InvoiceRequest.php
│ ├── ██████████████████████.php
│ ├── ███████████████████.php
│ ├── █████████████████████.php
│ ├── ████████████.php
│ ├── ████████████████████.php
│ ├── ████████████████████████████████████.php
│ ├── ██████████████████████████████████.php
│ ├── ██████████████████.php
│ ├── ███████.php
│ ├── ██████████████████████.php
│ ├── ████████████.php
│ ├── ███████████.php
│ └── ████████████████████████.php
├── Resources
│ ├── ████████████████.php
│ ├── ███████████████.php
│ ├── ██████████████.php
│ ├── ███████████████████████.php
│ ├── █████████████████████████████.php
│ ├── ███████████████████████████.php
│ ├── ███████████████████.php
│ ├── ███████████████.php
│ ├── ████████████████████████████.php
│ ├── ██████████████████████.php
│ ├── ████████████████████████████████████.php
│ ├── ████████████████████.php
│ ├── █████████████████████████████████.php
│ ├── ███████████████.php
│ ├── █████████████████████████████.php
│ ├── ████████████████████.php
│ ├── ████████████████████.php
│ ├── █████████████████████████████████████.php
│ ├── ████████████████████████.php
│ ├── ████████████████.php
│ ├── ████████████████████.php
│ ├── █████████████████████████████████████.php
│ ├── ███████████████████████████████.php
│ ├── ███████████████████████████.php
│ ├── ████████████████████.php
│ ├── █████████████████████.php
│ ├── █████████████████████████.php
│ ├── █████████████████████.php
│ ├── █████████████████.php
│ ├── █████████████████████.php
│ ├── ██████████████████.php
│ ├── █████████████████████████.php
│ ├── █████████████████.php
│ ├── ████████████████.php
│ ├── ████████████████████.php
│ ├── ███████████████████████████████.php
│ ├── ████████████████████████████████.php
│ ├── ████████████████████████████████.php
│ ├── █████████████████████████████.php
│ ├── ███████████████████████████████.php
│ ├── ████████████████████████.php
│ ├── ████████████████████████████.php
│ ├── ████████████████.php
│ ├── █████████████████████.php
│ ├── ███████████████████████.php
│ ├── █████████████████.php
│ ├── Invoices
│ │ ├── InvoiceCollectionDataResource.php
│ │ ├── InvoiceCollectionResource.php
│ │ ├── InvoiceDataResource.php
│ │ ├── InvoiceDraftResource.php
│ │ ├── InvoiceLineDataResource.php
│ │ ├── InvoiceLineResource.php
│ │ ├── InvoiceResource.php
│ │ ├── ██████████████████.php
│ │ ├── █████████████████.php
│ │ └── █████████████.php
│ ├── InvoiceIndexResource.php
│ ├── InvoiceLabelResource.php
│ ├── InvoiceMainOverviewResource.php
│ ├── InvoiceeResource.php
│ ├── ████████████████████.php
│ ├── █████████████.php
│ ├── ███████████████.php
│ ├── ██████████████████████████.php
│ ├── ████████████████████.php
│ ├── ██████████████████.php
│ ├── ██████████████.php
│ ├── █████████████████████████████.php
│ ├── ██████████████████████████.php
│ ├── █████████████████████.php
│ ├── █████████████████████████.php
│ ├── █████████████.php
│ ├── ██████████████████████.php
│ ├── ███████████████████.php
│ ├── ███████████████.php
│ ├── ███████████████.php
│ ├── ███████████████.php
│ ├── █████████████████████.php
│ ├── █████████████.php
│ ├── █████████████████.php
│ ├── ███████████████████.php
│ ├── ███████████████████████.php
│ ├── ██████████████.php
│ ├── ██████████████████████████.php
│ ├── █████████████████.php
│ ├── ██████████████████████.php
│ ├── █████████████.php
│ ├── █████████████████.php
│ ├── ████████████.php
│ ├── ███████████████████████.php
│ ├── ████████████████.php
│ ├── ████████████████████.php
│ ├── ████████████████████████████.php
│ ├── █████████████████████.php
│ ├── ██████████████████████████.php
│ ├── █████████████████.php
│ ├── █████████████████████.php
│ ├── ███████████████████.php
│ ├── ████████████.php
│ ├── ████████████████.php
│ ├── ████████████.php
│ └── █████████████████████.php
└── ViewModels
├── █████████████████.php
├── ███████████████.php
├── ████████████████████████.php
├── █████████████████.php
├── ████████████████████.php
├── █████████████████████████████████.php
├── ████████████████████████████.php
├── ██████████████████████████.php
├── ██████████████████████████████.php
├── ████████████████████████.php
├── █████████████████.php
├── ██████████████████████████████.php
├── █████████████████████████.php
├── █████████████████████.php
├── █████████████.php
├── ████████████████.php
├── ██████████████████.php
├── █████████████████████.php
├── ██████████████████████.php
├── ██████████████████████████.php
├── ██████████████████████.php
├── ██████████████████.php
├── ████████████████████.php
├── ███████████████████.php
├── ██████████████████.php
├── █████████████████████████████.php
├── ██████████████████████████.php
├── █████████████████████.php
├── █████████████████.php
├── ██████████████████████████.php
├── ███████████████.php
├── ███████████████████████████.php
├── ████████████████████████
│ ├── ████████████████.php
│ ├── █████████████████.php
│ ├── ██████████████████.php
│ └── ███████████████████████.php
├── █████████████████████████.php
├── ███████████████████████████████.php
├── ███████████████████████████████.php
├── ███████████████████████.php
├── ██████████████████.php
├── InvoiceCollectionHabitantContractPreviewViewModel.php
├── InvoiceCollectionOwnerContractPreviewViewModel.php
├── InvoiceCollectionPreviewViewModel.php
├── InvoiceDraftViewModel.php
├── InvoiceIndexViewModel.php
├── InvoiceLabelsViewModel.php
├── InvoiceStatusViewModel.php
├── █████████████████.php
├── █████████████████████.php
├── ██████████████████████.php
├── █████████████.php
├── ██████████████████.php
├── ███████████████████.php
├── ██████████████.php
├── ██████████████████████.php
├── ████████████████████████████.php
├── ██████████████████████████████████████.php
├── ████████████████.php
├── █████████████████.php
├── ████████████████████████.php
├── ████████████████████████.php
├── █████████████████████.php
├── ██████████████████.php
├── ████████████████████.php
├── ██████████████████████████████.php
├── █████████████████████████.php
├── ███████████████████████████████.php
├── ██████████████████.php
├── ███████████████.php
├── ██████████████.php
├── ████████████████████.php
├── ████████████████████████.php
├── █████████████████.php
├── █████████████████████████.php
├── ██████████████████.php
├── ████████████████████████████.php
├── █████████████████████████████.php
├── █████████████████████.php
├── ██████████████████████.php
├── ██████████████████.php
├── ██████████████████████.php
├── █████████████████████████.php
├── ██████████████████████.php
├── █████████████████.php
├── █████████████.php
├── █████████████.php
├── ██████████████████████.php
├── █████████.php
└── █████████████████.php
你好,我们又见面了!
滚动浏览的内容太多了。我不是在开玩笑——这是我们其中一个项目经过一年半的开发后的实际样子。请记住,这只是管理应用程序代码,它不包括任何域相关的东西。
那么,这里的核心问题是什么?它实际上与第1章中的域代码相同:我们根据技术属性而不是其实际含义来对代码进行分组。带有控制器的控制器,带有请求的请求,带有视图模型的视图模型,等等。
发票之类的概念再次分布在多个目录中,并与其他几十个类别混合在一起。即使有最好的 IDE 支持,也很难将应用程序作为一个整体来理解,也没有办法对正在发生的事情有一个全面的了解。
解决方案?我希望这里没有什么意外;这和我们对域的处理一样:将属于一起的代码组合在一起。在本例中,发票:
Admin
└── Invoices
├── Controllers
│ ├── IgnoreMissedInvoicesController.php
│ ├── InvoiceStatusController.php
│ ├── InvoicesController.php
│ ├── MissedInvoicesController.php
│ └── RefreshMissedInvoicesController.php
├── Filters
│ ├── InvoiceMonthFilter.php
│ ├── InvoiceOfferFilter.php
│ ├── InvoiceStatusFilter.php
│ └── InvoiceYearFilter.php
├── Middleware
│ ├── EnsureValidHabitantInvoiceCollectionSettingsMiddleware.php
│ ├── EnsureValidInvoiceDraftSettingsMiddleware.php
│ └── EnsureValidOwnerInvoiceCollectionSettingsMiddleware.php
├── Queries
│ ├── InvoiceCollectionIndexQuery.php
│ └── InvoiceIndexQuery.php
├── Requests
│ └── InvoiceRequest.php
├── Resources
│ ├── InvoiceCollectionDataResource.php
│ ├── InvoiceCollectionResource.php
│ ├── InvoiceDataResource.php
│ ├── InvoiceDraftResource.php
│ ├── InvoiceIndexResource.php
│ ├── InvoiceLabelResource.php
│ ├── InvoiceLineDataResource.php
│ ├── InvoiceLineResource.php
│ ├── InvoiceMainOverviewResource.php
│ ├── InvoiceResource.php
│ └── InvoiceeResource.php
└── ViewModels
├── InvoiceCollectionHabitantContractPreviewViewModel.php
├── InvoiceCollectionOwnerContractPreviewViewModel.php
├── InvoiceCollectionPreviewViewModel.php
├── InvoiceDraftViewModel.php
├── InvoiceIndexViewModel.php
├── InvoiceLabelsViewModel.php
└── InvoiceStatusViewModel.php
你觉得怎么样?当你处理发票时,你有一个地方可以去了解哪些代码对你可用。我倾向于称这些组为“应用模块”,或者简称为”模块“;我的经验告诉你,当你在这个规模的项目中工作时,他们会让你的生活变得更容易。
这是否意味着模块应该在域上一一映射?绝对不是!请注意,可能有一些重叠,但不是必需的。例如,我们在管理应用程序中有一个设置模块,它一次涉及多个域组。将单独的设置控制器、视图模型等分散在多个模块中是没有意义的:当我们处理设置时,它本身就是一个功能;而不是为了与域同步而跨多个模块分布一个功能。
对于这种结构,可能出现的另一个问题是如何处理通用类。像基本请求类、到处都在使用的中间件……还记得第一章中的 Support
命名空间吗?这就是它的目的! Support
保存着所有应该在全球范围内访问的代码,但它也可以成为框架的一部分。
既然你已大致了解了我们如何构建应用程序,现在该看看为简化我们的生活而使用的一些模式。下一次,当我们谈论视图模型时,我们将开始讨论。