朋友您好! PHP中流行的依赖项管理器的出现是PHP社区中最重要的事件之一。 Composer将时间划分为“之前”-当我们的自写库位于zip存档中或只是分散在文件夹中并由“ pens”复制时,仅在极少数情况下使用git或PEAR,而在开始使用composer时则为“ after”。 但是,如果您使用特定的CMS,却不“知道”什么作曲家该怎么办?
前言
我是一个小型网络工作室的团队负责人,大约一年前,我不得不重新考虑使用团队中最佳实践的方法。 对于项目的开发,可以将其70%以上的功能称为标准功能(网站,在线商店),我们使用1C-Bitrix。 像所有流行的CMS 1C-Bitrix一样,它具有模块化结构并支持第三方模块的安装。 听起来不错,但实际上有点不同。 您可以通过将源代码复制到所需的文件夹并一次在控制面板中安装一个模块来开发自己的模块并将其存储在归档中,也可以在为此提供的1C-Bitrix Marketplace网站上发布这些模块。 要发布模块,您只需要签订合伙协议并签署将描述您责任的协议即可。 而且我们不是在谈论模块的任何依赖关系,而是在安装依赖关系链。
这个问题或多或少是“之前”开发的所有CMS固有的问题。 这不利于小模块的开发(在我们看来,“此简单功能”不应转变为模块),并且需要单独的文档。
在本文中,我将告诉您如何组织团队/公司中的最佳实践的存储和使用。 对于那些遇到类似问题的人,使用CMS开发网站的人,开发自己的CMS的人以及仅使用PHP开发项目的人来说,这将是有趣的。 走吧
第一部分 模块的公共放置
需要解决的第一个任务是在哪里存储模块。 模块源代码可以存储在任何git,mercurial或svn存储库中。 对于公共模块,我建议使用GitHub。 在GitHub上,您将有机会轻松查看源代码并以Markdown格式维护文档。 要使用composer,您需要创建并填充composer.json文件。 这可以在编辑器中,在IDE中或通过调用composer init命令来完成。 在下文中,我不会深入研究基本功能和composer命令,如果您不熟悉composer,请阅读本文 。
创建模块(例如,现在暂时为空)并将其代码发布到GitHub后,您需要在packagist.org上注册该模块。 Packagist将为您提供配置GitHub挂钩的功能,以便在对存储库进行更改时,可在packagist.org上更新有关模块的信息。
第二部分 安装方式 这里最有趣的
当然,您对使用的CMS非常熟悉,这意味着您知道在其中安装模块的所有细节。 在1C-Bitrix中,模块的安装分为两个阶段:
- 将模块的源代码放在特定的目录
<project_dir>/local/modules/<company_name>.<mod_mame>
- 调用RegisterModule函数(<company_name>。<mod_mame>)。 通常,所有模块安装操作均在负责安装和卸下模块的类的DoInstall方法中描述。
<project_dir>/local/modules/<company_name>.<mod_mame>/install/index.php
第二部分是一个。 将包裹隐藏在安全的地方
默认情况下,如果composer位于项目的根目录中并且不执行任何挂钩,则composer将所有软件包安装在<project_dir>/vendor
目录中。 但这很容易改变。
我们需要将composer.json文件放置在项目根目录中:
{ "name": "sites/<sitename>", "description": "<SiteName>", "authors": [ { "name": "<developerName>", "email": "<developerEmail>" } ], "minimum-stability": "dev", "require": {}, "config": { "vendor-dir": "local/vendor" } }
在1C-Bitrix中,开发人员编写的代码通常位于<project_dir>/local
目录中。 因此,我们通过在config部分中的条目将vendor
文件夹移到了那里。 现在,所有第三方软件包都将托管在此处。 但是我们的模块必须放在目录<project_dir>/local/modules/<company_name>.<mod_mame>
,该怎么办?
第二部分,第二部分。 模块安装插件
Composer有几种类型的软件包,其中一种composer-plugin是composer本身的扩展。 为了按照CMS的要求安装我们的模块,我们需要编写自己的插件。 为此,请创建一个单独的项目并将composer.json放在其根目录中:
{ "name": "<my_name>/installer", "description": "Plugin for custom installing", "type": "composer-plugin", "license": "MIT", "homepage": "<link to homepage github>", "version": "0.0.1", "authors": [ { "name": "<name>", "email": "<email>" } ], "require": { "composer-plugin-api": "^1.0" }, "require-dev": { "composer/composer": "^1.0" }, "autoload": { "psr-4": { "<my_name>\\installer\\": "" } }, "extra": { "class": "<my_name>\\installer\\Plugin" } }
此文件中有3个关键点:
- “ type”:“ composer-plugin” -告诉作曲家它是一个插件
- 自动加载 -描述自动加载类的规则
- extra-指示哪个类是插件
该插件将包含两个类:
- 插件本身。 他将自己的安装程序添加到作曲家中
- 安装程序,将用于安装模块
该插件仅添加安装程序(文件: Plugin.php )
namespace company_name\installer; use Composer\Composer; use Composer\EventDispatcher\EventSubscriberInterface; use Composer\IO\IOInterface; use Composer\Plugin\PluginInterface; class Plugin implements PluginInterface { public function activate(Composer $composer, IOInterface $io) { $composer->getInstallationManager()->addInstaller(new Bitrix($io, $composer)); } }
接下来,安装程序本身( company_name\installer\Bitrix
)。 该类必须继承自Composer\Installer\LibraryInstaller
并包含以下方法:
- 支持 -如果安装程序支持这种类型的软件包,则返回true
- getInstallPath-返回要放置程序包源代码的路径
- 安装/卸载/更新 -软件包安装/卸载/更新挂钩
我们所有的模块都是bitrix-module类型,安装程序应该可以使用它们。
public function supports($packageType) { return $packageType === 'bitrix-module'; }
我决定保留模块名称的完整性(模块名称由以小数点分隔的company_name和mod_name组成),并将包命名为<my_name>/<company_name>.<mod_mame>
或<company_name>/<company_name>.<mod_mame>
。 如果我们采用软件包名称并用斜杠将其断开,那么第二部分将是模块的名称
public function getInstallPath(PackageInterface $package) { $name = explode("/", $package->getName()); return "local/modules/{$name[1]}/"; }
initBitrix和getModule方法实现与1C-Bitrix API一起使用以安装模块。 根据您拥有的CMS,如何发布模块更新以及计划执行它们的方式(文件: Bitrix.php )来实现更新方法。
namespace company_name\installer; use Composer\Installer\LibraryInstaller; use Composer\Package\PackageInterface; use Composer\Repository\InstalledRepositoryInterface; class Bitrix extends LibraryInstaller { public function supports($packageType) { return $packageType === 'bitrix-module'; } public function install(InstalledRepositoryInterface $repo, PackageInterface $package) { parent::install($repo, $package); $name = explode("/", $package->getName()); $this->initBitrix(); $module = $this->getModule($name[1]); $module->DoInstall(); } public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) { $name = explode("/", $package->getName()); $this->initBitrix(); $module = $this->getModule($name[1]); $module->DoUninstall(); parent::uninstall($repo, $package); } public function getInstallPath(PackageInterface $package) { $name = explode("/", $package->getName()); return "local/modules/{$name[1]}/"; } protected function initBitrix() { $_SERVER['DOCUMENT_ROOT'] = __DIR__ . "/../../../../"; define('STOP_STATISTICS', true); define("NO_KEEP_STATISTIC", "Y"); define("NO_AGENT_STATISTIC","Y"); define("NOT_CHECK_PERMISSIONS", true); require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php'); $GLOBALS['APPLICATION']->RestartBuffer(); } protected function getModule($module) { include_once $_SERVER['DOCUMENT_ROOT'] . "/local/modules/" . $module . "/install/index.php"; $class = str_replace(".", "_", $module); $module = new $class(); return $module; } }
检查插件后,可以将代码上传到GitHub并在Packagist中注册。
第二部分,第三部分。 模组
让我们回到在第一部分中提到的模块本身。 更确切地说,是他的composer.json 。
{ "name": "<my_name>/<company_name>.<mod_mame>", "type": "bitrix-module", "description": " ", "version": "1.0.0", "time": "11.09.2018", "minimum-stability": "dev", "license": "MIT", "homepage": "<link to homepage github>", "authors": [ { "name": "<name>", "email": "<email>" } ], "require": { "<my_name>/installer": "*" } }
模块的名称必须符合CMS的要求,必须指定安装程序可以使用的类型(在我们的示例中为bitrix-module ),并且在依赖项中模块必须具有插件( require部分)。 创建模块本身并检查其操作后,在GitHub上填写其代码并向Packagist注册。
第二部分,第四部分。 使用
让我提醒您,项目(站点)本身大约具有以下composer.json
{ "name": "sites/<sitename>", "description": "<SiteName>", "authors": [ { "name": "<developerName>", "email": "<developerEmail>" } ], "minimum-stability": "dev", "require": {}, "config": { "vendor-dir": "local/vendor" } }
现在我们可以在require部分列出我们需要的所有模块或调用命令
composer require "<my_name>/<company_name>.<mod_mame>" "*"
如果您必须例如通过在SMS中发送密码将授权模块添加到项目中,则可以充分感受到所做工作的有用性

该模块本身包含负责授权逻辑的代码,您不应在其中包含SMS发送代码,因为其他模块(例如,通知模块)也会发送SMS,因此最好将SMS分离为一个单独的模块,以使其代码不会重复。 REST服务也是如此。 也可以由其他模块使用。 有了所有这些复杂的方案,当您的模块再拉四个时,它的安装就变得一样简单。 只需运行一个命令:
composer require "<my_name>/<company_name>.<mod_mame>" "*"
以及以什么以及以什么顺序下载和安装,让作曲者决定。
第三部分。 专用模块
朋友,如果您不希望以上所有内容都属于公共领域,那么我们会尽快对其进行修复。 要组织模块的hello存储,您将需要两个工具:
首先,安装GitLab并将模块的源代码转移到其中。 然后安装Satis并在satis.json中描述所有模块
{ "name": "ropoName", "homepage": "https://composer.<company_name>.ru/", "repositories": [ { "type": "vcs", "url": "https://gitlab.<company_name>.ru/<my_name>/installer" }, { "type": "vcs", "url": "https://gitlab.<company_name>.ru/<my_name>/<company_name>.<mod_name>" } ], "config": { "gitlab-domains": [ "gitlab.<company_name>.ru" ], "gitlab-token": { "gitlab.<company_name>.ru": "GitLab Token" } }, "require-all": true }
在GitLab中,您需要创建一个可供api使用的令牌,并在satis.json中指定它。 完成所有这些操作后,运行命令:
php bin/satis build satis.json ./web
然后在Web文件夹中,获取一个静态存储库,该存储库可以在https:// composer 。<company_name> .ru /发布。
该站点的composer.json的不同之处仅在于它将具有一个存储库部分
{ "name": "sites/<sitename>", "description": "<SiteName>", "authors": [ { "name": "<developerName>", "email": "<developerEmail>" } ], "minimum-stability": "dev", "require": {}, "config": { "vendor-dir": "local/vendor" }, "repositories": [ { "type": "composer", "url": "https://composer.<company_name>.ru/" } ] }
后记
朋友,我真的希望这篇文章对您有所帮助。 而且,无论使用哪个CMS都无所谓,您将能够正确地组织代码的存储,严格地对其进行文档化,将“厚”模块划分为许多“薄”格式依赖项,并且不再难以安装或更新模块。 祝你好运