我有一个应用服务器,它就像一个博客系统(我的wordpress杀手)。它是基于php托管在github和使用composer来管理依赖关系。每个安装都托管在我的服务器上(我为它们进行安装)。当客户端需要一个新的"插件/插件"时,我创建一个新的包,并将其托管在一个私有存储库托管中。当我需要添加新包时,问题就出现了:
Client 1.
- package for calculate prices
Client 2.
- package for show a welcome message
Client 3.
- package for add a calendar
我的应用程序将有每个包准备在所有实例中使用,因为我需要它们通过composer:
"require": {
"killer/calculate": "dev-master",
"killer/message": "dev-master",
"killer/calendar": "dev-master"
}
现在想象一下,如果我有2K个客户,他们每个人都在请求定制包。我如何提供一个应用程序(大规模克隆),但在每个安装中只保留每个客户机需要的包?
假设的解决方案我正在搜索(如果可能的话)类似以下的东西。对于每个安装,手动创建一个文件,其内容指定所需的包。例如,假设每个客户机的安装都有如下内容:
//composer.json
"require": {
}
//plugins.json (this file is ignored via .gitignore)
{
"killer/calculate": "dev-master"
}
然后,以某种方式告诉composer.json
需要plugins.json
的数据。通过这种方式,我避免了为所有客户端创建一个巨大的composer.json
共享不必要的包。
有一个特性请求允许composer.json
扩展另一个文件。你应该去评论一下,引起人们的注意。
使用该特性的方法是创建一个default.json
文件,其中包含所有常规composer.json
内容,包括列出所需所有常用软件包的require
部分。
// default.json
{
"require": {
"php": ">=5.4.0"
}
}
然后为每个扩展和/或覆盖default.json
的项目创建一个composer.json
文件,如下所示:
// composer.json
{
"require": {
"killer/calculate": "dev-master"
},
"extends": "default.json"
}
最后的结果将是:
{
"require": {
"php": ">=5.4.0",
"killer/calculate": "dev-master"
}
}
如果你不能等待合并请求,那么你可以从合并请求的作者那里签出编译器分支并尝试它。
听起来你已经创建了自己的包生态系统。因此,您可以独立于Packagist工作,并简单地自己托管所有包,可能使用Satis。
我的主要建议是将您的应用程序作为一个包引入这个生态系统。
您的应用程序composer.json
只包含与应用程序本身相关的包。
{
"name": "better/application",
"require": {
"another/library": "1.0.0",
"another/framework": "1.2.3",
"another/generator": "2.1.3"
},
"require-dev" : {
"phpunit/phpunit" : "4.*",
}
}
我认为,为客户/客户端"克隆"应用程序不是一个好主意,因为它忽略了插件依赖于应用程序的特定版本,而该版本并不总是"最新"或"dev-master"。让Composer为每个客户端按版本提取应用程序。
通过这种方式,我避免了为所有客户端创建一个巨大的
composer.json
共享不必要的包。
- 为每个新客户/客户创建一个存储库
- 在
composer.json
中添加应用程序本身和客户端请求的包 - 在顶部添加客户端配置
composer.json
:
{
"name": "better/application-for-client1",
"require": {
"better/application": "1.0.0",
"better/app-calculate": "1.2.3"
}
}
例如,Client2的composer.json
:
{
"name": "better/application-for-client2",
"require": {
"better/application": "1.0.1",
"better/app-calculate": "1.2.4",
"better/app-message": "2.0.0"
}
}
每个客户可能有自己的设置,需要不同版本的应用程序和不同的附加应用程序包/插件(这里使用前缀"app-"表示)。
最后,您为客户提供了两个基本文件:一个编写器。Json和配置文件。
应用程序如何检测可用模块是另一回事。至少,当你在应用程序的引导过程中注册composer自动加载器时,自动加载将会开箱工作。(旁注:如果您的应用程序是一个多站点应用程序,那么您可以将"克隆"替换为"符号链接"。多站点是指使用站点id(通常是客户id)从一个中心位置运行的应用程序。如果您将包含所有开发包的应用程序文件夹放在一个整体文件夹中,那么通过清除开发内容来构建一个发布文件夹,这样您就可以得到一个带有空白默认配置的发布版本。然后将应用程序和请求的包符号链接到客户文件夹,并在上面放置一个配置。这种方法可以节省相当多的磁盘空间,并且根本不涉及Composer。
我还鼓励您使用Jens a . Koch在他的回答中提出的方法,即拥有一个作曲家。Json文件为每个客户,并要求主应用程序和所有所需的插件。Composer很好地支持这种场景,我想向您指出起点:
<<h3>作曲家类型/h3>Composer允许为包指定类型。您可以定义自己的类型来标记应用程序的插件。许多开源项目(例如Symfony with bundles)已经在他们的插件生态系统中采用了这种方法。
自定义安装
您可以注册自定义安装程序,可以执行特定的type
的composer包(即您为您的插件定义的类型)。然后,您可以自定义插件的安装过程,这意味着您可以:
- 移动自定义插件到指定位置,
- 自动调整插件配置,
- 和最重要的:提供一个机制,允许主应用程序看到哪些插件可用。
嗯…
这意味着一个大的composer.json
与你的系统运行/与你的系统兼容。也许你还需要引入一个版本控制系统。所以你最终可以得到v1_composer.json
..
但是对于每个客户端只加载所需的包。例如,为每个客户端生成一个requires.php
,其中包含链接到共享库的必要require语句。这将是最快和最有效的解决方案,因为你共享了你可以共享的代码,你只在需要的时候加载它
尽可能多地共享代码…但是当你不需要的时候就不要使用它。