使用Git和Composer处理PHP框架组件之间依赖关系的最佳方法

web*_*eat 6 php git dependencies frameworks composer-php

背景

我正在用PHP开发一个框架.我首先将每个组件分开制作,以便可以独立于框架使用.

创建四个库A,B,CD后:

  • A没有依赖关系

  • BC需要A

  • D需要A,BC.

现在我在发布一个库的新版本时遇到了一些问题,我可能不得不改变其他库的依赖关系,并且必须为它们发布新版本.例如:A的新版本意味着B,CD的新版本.

我看了像SymfonyLaravel这样的其他框架是如何解决这个问题的.我了解到他们正在使用subtreeGit的replace功能和Composer 的功能.它的工作原理如下:

  • 每个组件都在自己的只读存储库中 composer.json

  • 每个组件都可以需要其他组件,但不需要replace它们.

  • 框架存储库用于subtrees包括所有组件.所以不需要require他们使用作曲家.但它应该是require所有依赖项(因为这不再由Compser处理).

  • 框架replace的所有组件.

我也注意到了

  • 组件存储库仅包含源代码(无单元测试!)

  • Laravel使组件Contracts只是为了存储所有组件的所有交互,每个组件都需要它.

问题

  1. 我对Laravel和Symfony如何解决这个问题的解释是正确的吗?

  2. 我是否真的必须从组件存储库中删除测试并将它们放在框架中?

  3. 如果是,那么只想使用单个组件的人如何确保它通过测试而不管整个框架是否通过了测试?

  4. 我是否必须确保所有组件依赖项是兼容的并且在框架中手动需要它们composer.json

  5. 为接口提供组件有什么意义?这不能单独使用!

  6. 有没有更好的方法来解决这个问题?

PS:这里是A,B,CD的链接

Jen*_*och 5

现在我在发布一个库的新版本时遇到了一些问题,我可能不得不改变其他库的依赖关系,并且必须为它们发布新版本.例如:A的新版本意味着B,C和D的新版本.

  • 你有一个多回购的方法.
  • 在B,C和D中编辑A =>新版本的A =>版本凹凸.

我认为最重要的是dev-master,一旦它们被稳定并准备好脱离开发阶段,就要远离正确使用和版本化组件.然后,您可以使用Composers范围运算符(插入符号^和波形符号~)自动更新到某个major.minor版本范围内的最新发布版本.这有很大帮助,并且需要繁琐的手动版更新工作.

  1. 我对Laravel和Symfony如何解决这个问题的解释是正确的吗?
  • 这不对.基础开发概念,包的发布和消费的工作方式不同,然后根据您的描述.
  • 他们使用整体回购开发风格.它是一个单独的存储库,包含一组包的代码.与之相反的mono-repomany-repo方法.替代方案是git submodules.
  • 框架和框架核心/内核的所有模块/包都在一个存储库中!对于Laravel来说,它是https://github.com/laravel/framework/tree/5.4/src/Illuminate
  • 每个模块/ bundle文件夹包含一个composer.json并且框架本身包含一个composer.json
  • 这允许将模块文件夹"拆分"为独立的只读存储库.使用自定义git帮助程序,例如git subsplit publishLaravel,使用https://github.com/laravel/framework/blob/636020a96a082b80fa87eed07d45c74fa7a4ba70/build/illuminate-split-full.shsplitsh https://github.com/splitsh/lite,如Symfony使用
  • 开发发生在主要的回购中.
  • 最后,从用户/消费者的角度(在CMS/app的composer.json中),您只需要"独立只读存储库"源中的模块/包.这是多回购,因为您的应用程序依赖于许多存储库.

使用Composer更新依赖关系时,Composer会使用较新的版本替换您的包.

  1. 我是否真的必须从组件存储库中删除测试并将它们放在框架中?

不可以.您也可以将测试留在/moduleA/tests文件夹中并调整您的单元测试收集器.

  1. 如果是,那么只想使用单个组件的人如何确保它通过测试而不管整个框架是否通过了测试?

两件事情.受试者是:

  • (a)该组件,理想地是可独立测试的
  • (b)框架,它消耗许多组件并测试功能,这些组件依赖于来自多个组件(例如核心/内核)的功能.一旦内核稳定并且可以独立测试,您也可以将内核拆分出来.(例如你的组件D)
  1. 我是否必须确保所有组件依赖项是兼容的并且在框架composer.json中手动需要它们?

monorepo开发人员的观点:当框架的所有组件测试和框架本身的所有单元测试通过时,框架的开发人员/维护人员只能发布新版本,对吗?然后,他可以启动子树拆分并自动对新组件进行版本化.

应用程序开发人员的观点:是.作为monorep组件的用户,您只是在使用standaloen依赖(来自只读的repos).这意味着您必须composer.json手动或自动维护所需组件的版本.

  1. 为接口提供组件有什么意义?这不能单独使用!

好问题!

  • 也许开发人员想要以不同的方式做事并"保持事物分类"

  • 或者,他们的想法有一个糟糕的优化想法:

有人可能会说接口只是开发合同.当所有组件都针对接口编写时,您可以在测试之后和生产发布之前简单地拔出插件.换句话说:当您要发布生产时,您可以离开interfaces存储库并运行接口删除.

离开接口repo将导致"未找到接口X"致命错误.然后在其余类上运行"优化器传递"并删除所有"implements interfaceX"字符串.减少要包含的文件.减少要解析的代码.减少IO.现在我可能会在评论部分通过建议这个来杀死:)不,Laravel或Symfony都没有这样做.

  1. 有没有更好的方法来解决这个问题?

我建议执行以下操作:对于包含<5个组件的项目,请使用multi-repo.如果> 5个组件,去monorepo.

一般来说,解决这个问题的方法并不多:

  1. git子模块
  2. 单回购
  3. 多回购

每种方法都有pro和con:

  • 更新git子模块,即git版本碰撞和子模块更新会导致git疯狂,因为它会不断被破坏.而git madness导致了黑暗的一面.:)
  • Mono-repo易于维护且易于发布.它为开发人员提供了轻松的维护,为消费者提供了多回购.您可以立即替换/重命名/重构所有模块/组件.
  • 当您拥有大量组件时,很多repo很难维护.

也可以看看: