大规模 Laravel 应用

文章转发自专业的Laravel开发者社区,原始连接:learnku.com/laravel/t/3…php

(若是你只想查看解决方案, 单击此处 )laravel

Laravel是迄今为止最流行的PHP框架,目录结构明确清晰,语法优雅。在中小型项目中使用Laravel提供的默认目录结构效果是很是好的,可是当有一个超过50个模型的大型应用,代码库可能就有点让人窒息。程序员

维护一个大型的应用程序并不简单,尤为是当组织错乱,而Laravel的默认结构对这样的场景确定没有很大帮助。web

首先,咱们看看Laravel默认结构以及它对大型应用程序的影响。json

Laravel的默认应用程序结构:api

|- app/
   |- Console/
      |- Commands/
   |- Events/
   |- Exceptions/
   |- Http/
      |- Controllers/
      |- Middleware/
   |- Jobs/
   |- Listeners/
   |- Providers/
   |- User.php
|- database/
   |- factories/
   |- migrations/
   |- seeders/
|- config/
|- routes/
|- resources/
   |- assets/
   |- lang/
   |- views/
复制代码

结构没什么问题。可是,当咱们在大型应用程序中工做时,咱们一般将业务逻辑划分为存储库、转换器等……以下所示:bash

|- app/
   |- Console/
      |- Commands/
   |- Events/
   |- Exceptions/
   |- Http/
      |- Controllers/
      |- Middleware/
   |- Jobs/
   |- Listeners/
   |- Models/
   |- Presenters/
   |- Providers/
   |- Repositories/
   |- Services/
   |- Transformers/
   |- Validators/
|- database/
   |- factories/
   |- migrations/
   |- seeders
|- config/
|- routes/
|- resources/
   |- assets/
   |- lang/
   |- views/
复制代码

这显然是一个结构良好的Laravel项目。如今,让咱们看看models文件夹:架构

|- app/
  |- Models/
     |- User.php
     |- Role.php
     |- Permission.php
     |- Merchant.php
     |- Store.php
     |- Product.php
     |- Category.php
     |- Tag.php
     |- Client.php
     |- Delivery.php
     |- Invoice.php
     |- Wallet.php
     |- Payment.php
     |- Report.php
复制代码

咱们还需处理全部业务逻辑的服务。还有Repositories, Transformers, Validators文件夹,其中包含相同或更多的类。可是,处理单个Entity/Model须要浏览不一样的文件夹和文件。app

问题不在于浏览不一样的文件夹,而在于维护代码和服务之间的通讯。composer

分析代码库,咱们发现:

  • 它是一个总体 应用程序
  • 对于开发人员来讲很难 维护
  • 开发效率 低 (须要时刻考虑相互联系)
  • Scaling 存在问题

解决方案显而易见-微服务。即便咱们使用soa(面向服务的体系结构),咱们仍然必须将咱们的总体应用程序分解成更小的独立部分来分别扩展它们。

一般分离服务须要两个简单的步骤:

  • 将服务的子程序 (Models, Repositories, Transformers etc.) 移动到一个新的较小的php微服务应用程序中。
  • 从新设置服务函数调用,将目标重定向到微服务(例如:建立http请求).

如今须要找到与该服务相关的全部文件,你可能会发现经过绕过该服务而在代码中的其余地方使用了它的模型或存储库。总结一下可能遇到的问题:

  • 要考虑的文件繁多
  • 犯错的概率很高
  • 产生烦躁
  • 有时须要从新考虑域逻辑
  • 有新的程序员祭天

最后一个缘由很是重要,由于新开发人员很难在短期内掌握整个应用程序。可是,项目经理不会给他太多时间。这会致使胡乱打补丁,错误的代码放置,让下一个新开发人员将更加困惑。

幸运的是,咱们已经有了一个解决方案 -HMVC。将整个应用程序分红较小的部分,每一个部分都有本身的文件和文件夹(例如 app/ 文件夹),可是HMVC增长了更多的复杂性,而且当咱们要将特定模块移入微服务时也是如此。咱们仍然须要将控制器,中间件等保留在主代码库中。在大多数状况下,转向微服务须要从新定义路由和控制器。所以,咱们必须作多余的工做。所以,我不是这种结构的忠实拥护者。由于,我只想分开我(必须)没必要分开的东西。并经过composer.json自动加载方式加载,以下所示:

|- auth/
   |- Exceptions/
   |- Http/
   |- Listeners/
   |- Models/
   |- Presenters/
   |- Providers/
   |- Repositories/
   |- Services/
   |- Transformers/
   |- Validators/
|- merchant/
   |- Console/
   |- Events/
   |- Exceptions/
   |- Http/
   |- Jobs/
   |- Listeners/
   |- Models/
   |- Presenters/
   |- Providers/
   |- Repositories/
   |- Services/
   |- Transformers/
   |- Validators/
|- database/
   |- factories/
   |- migrations/
   |- seeders
|- config/
|- routes/
|- resources/
   |- assets/
   |- lang/
   |- views/
复制代码

可是HMVC增长了更多的复杂性,而且当咱们要将特定模块移入微服务时也是如此。咱们仍然须要将控制器,中间件等保留在主代码库中。在大多数状况下,转向微服务须要从新定义路由和控制器,咱们必须作多余的工做。可是,我只想分开我(必须)不得不分开的东西。

领域驱动设计

本文再也不对领域驱动设计作过多介绍,Developerul DeLaUnu 在 这里对DDD进行了很好的描述。

以本文的观点,DDD(能够)将Laravel应用程序分为4部分(或3…  参见) :

  • 应用程序 — 一般包含,控制器,中间件,路由
  • 领域 — 一般包含业务逻辑(模型,存储库,变压器,策略等)
  • 基础架构 —一般拥有经常使用服务,例如日志记录,电子邮件等
  • 界面 —一般包含视图,语言,资产

若是咱们这样构造应用程序并使用命名空间会产生什么结果呢?

|- app/
   |- Http/ (Application)
      |- Controllers/
      |- Middleware/
|- Domain/
   |- Models/
   |- Repositories/
   |- Presenters/
   |- Transformers/
   |- Validators/
   |- Services/
|- Infrastructure/
   |- Console/
   |- Exceptions/
   |- Providers/
   |- Events/
   |- Jobs/
   |- Listeners/
|- resources/ (Interface)
   |- assets/
   |- lang/
   |- views/
|- routes/
   |- api.php
   |- web.php
复制代码

将项目化分红这样的文件夹是行不通的,这意味着咱们只添加了一个父命名空间。

解决方案

以下:

|- app/
   |- Http/
      |- Controllers/
      |- Middleware/
   |- Providers/
   |- Account/
      |- Console/
      |- Exceptions/
      |- Events/
      |- Jobs/
      |- Listeners/
      |- Models/
         |- User.php
         |- Role.php
         |- Permission.php
      |- Repositories/
      |- Presenters/
      |- Transformers/
      |- Validators/
      |- Auth.php
      |- Acl.php
   |- Merchant/
   |- Payment/
   |- Invoice/
|- resources/
|- routes/
复制代码

该  Auth.php和  Acl.php 是内部的服务文件  app/Account/ 夹。控制器将仅访问这两个类并调用其函数。其余类(域以外)将不会访问到app/Account/ 文件夹中的其余剩余类  。这些服务中的功能将只接受基本的PHP数据类型,例如  array,  string,  int,  bool 和POPO(Plain Old PHP Object),但没有类的实例。例如:

public function register(array $attr) {
    ...
}
public function login(array $credentials) {
    ... 
}
public function logout() {
    ...
}
复制代码

须要注意,该  register 函数接收的  array 属性而不是  User 对象。由于另外一个正在调用该函数的类不该该知道该User 模型的存在  。这是整个结构的基本规则。

当咱们想要分离代码时

咱们的应用开始变得庞大而后咱们想要将 Account域单独分离成一个微服务,而且将其转化为OAuth服务.

因此,咱们只需移动如下部分-

|- Account/
   |- Console/
   |- Exceptions/
   |- Events/
   |- Jobs/
   |- Listeners/
   |- Models/
      |- User.php
      |- Role.php
      |- Permission.php
   |- Repositories/
   |- Presenters/
   |- Transformers/
   |- Validators/
   |- Auth.php
   |- Acl.php
复制代码

到一个新的 Laravel (或者 Lumen) 应用-

|- app/
   |- Http/
      |- Controllers/
      | - Middleware/
   |- Account/
      |- Events/
      |- Jobs/
      |- Listeners/
      |- Models/
         |- User.php
         |- Role.php
         |- Permission.php
      |- Repositories/
      |- Presenters/
      |- Transformers/
      |- Validators/
      |- Auth.php
      |- Acl.php
|- routes/
|- resources/
复制代码

固然,咱们必须在控制器和路由编写代码使其成为一个咱们须要的OAuth服务.

可是咱们须要在主代码库中修改什么呢?

咱们只须要保留Auth.phpAcl.php的服务文件,并将其函数中的代码更改成针对新建立的微服务的 HTTP 的请求(或者其余消息传递的方法)。

...
public function login(array $credentials) {
 // change the code here
}
...
复制代码

整个应用程序将保持不变. 应用程序结构以下所示 -

|- app/
   |- Console/
   |- Exceptions/
   |- Http/
      |- Controllers/
      |- Middleware/
   |- Providers/
   |- Account/
      |- Auth.php
      |- Acl.php
   |- Merchant/
   |- Payment/
   |- Invoice/
|- resources/
|- routes/
复制代码

经过这一较少的努力,您能够将代码的一部分移动到彻底独立的微服务中。我没法想象还有其余方法来经过更少的操做将代码的一部分移动到另外一个微服务中去.

权衡

就像我以前所说的, 任何事情都须要权衡,这个解决方案也不例外. 这里咱们有一个关于迁移的问题! 由于在上面的文件结构中(在分离以前),全部的迁移文件都在放置在database/migrations/目录. 可是当咱们想要分离一个域名时,咱们也须要识别这些文件而且移动到新的域名下. 这多是很困难的事情,由于咱们没有任何明确的迹象代表哪一个迁移文件属于哪一个域名. 咱们须要知道如何在迁移文件中放置标识符.

该标识符能够是域名前缀. 好比, 咱们能够给迁移文件命名为xxxxxxxxx_create_account_users_table.php而不是xxxxxxxxx_create_users_table.php . 若是须要,咱们还可使用account_users 表名代替users. 我更倾向于肯定哪些表须要在分离中移动. 分离迁移文件可能有点使人沮丧,可是若是咱们使用前缀或者其余类型的标记,这个过程将会变得不那么痛苦.

我仍然在试验这个迁移结构,并计划构建一个 Laravel 包,它将提供 artisan 命令在分离过程当中来自动生成文件 . 完成后我讲在这里放上包的连接.

相关文章
相关标签/搜索