安装流程和脚本文件
本节概述了扩展安装过程,以及如何编写脚本文件与之交互。
安装脚本文件是一个包含 5 个函数的类。
- preflight - 在安装过程开始时调用
- install, update, uninstall - 在过程进行中调用
- install 在操作是扩展的初始安装时调用
- update 在操作是现有扩展的安装时调用
- uninstall 在操作是扩展的删除时调用
- postflight - 在安装过程结束时调用
您还可以通过编写安装插件来与过程进行交互,这些插件监听以下事件。
安装流程
在 Joomla 中安装扩展有各种方法,以及各种类型的扩展,但最终,安装过程对所有扩展都遵循类似的模式。
当您去安装扩展并选择一个要安装的扩展的压缩文件时,以下是发生的情况概述:(如果您想在调试器中逐步完成此过程,请在 administrator/components/com_installer/src/Model/InstallModel.php::install 处设置断点)
- 导入 "installer" 类型的插件,并触发 'onInstallerBeforeInstallation' 事件
- 压缩文件存储在 Joomla /tmp 文件夹中,然后解压缩到 /tmp 的子文件夹中
- 触发 'onInstallerBeforeInstaller' 事件
- 触发 'onExtensionBeforeInstall' 事件
- 从新安装文件中加载 .sys.ini 语言文件(或者如果失败,则从现有扩展目录加载)
- 从清单文件中读取有关扩展的基本信息,例如,扩展的类型
- 对安装脚本文件执行
require_once
- 调用脚本文件
preflight
函数 - 将扩展文件从 /tmp 文件夹复制到它们在 Joomla 实例中的位置 - 例如,当安装站点模块 mod_example 时,代码将被复制到 /modules/mod_example
- 在数据库中写入/更新扩展记录(即此扩展在
#__extensions
表中的记录) - 执行特定于该扩展类型的任何功能。例如,对于模块的新安装,它会在
#__modules
表中创建一个记录 - 应用此安装所需的任何数据库更改。
- 调用脚本文件
install
/update
/uninstall
函数 - 整理
- 如果
#__updates
表中有一条记录表明此扩展存在新版本,则将其删除。 - 它将清单文件复制到目标扩展目录(对于组件,它将是 /administrator 下的组件目录)
- 如果
- 调用脚本文件
postflight
函数 - 触发 'onExtensionAfterInstall' 事件
- 触发 'onInstallerAfterInstaller' 事件
- 执行一些进一步的整理,例如删除临时安装文件
示例脚本文件
编写脚本文件的最简单方法是使用 libraries/src/Installer/InstallerScriptInterface.php 中的 \Joomla\CMS\Installer\InstallerScriptInterface 定义。您只需返回一个实现 5 个安装函数的类的实例。
您可以:
- 返回一个实现 InstallerScriptInterface 的匿名脚本文件类,或者
- 返回一个匿名服务提供者类,该类使用键 InstallerScriptInterface::class 将脚本文件类放入依赖注入容器。然后 Joomla 将从 DIC 获取该脚本文件类。
以下示例使用第二种方法。
有关第一种方法的示例,请参阅 模块教程步骤 6。
<?php
use Joomla\CMS\Application\AdministratorApplication;
use Joomla\CMS\Installer\InstallerAdapter;
use Joomla\CMS\Installer\InstallerScriptInterface;
use Joomla\CMS\Language\Text;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Exception\FilesystemException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
return new class () implements ServiceProviderInterface {
public function register(Container $container)
{
$container->set(
InstallerScriptInterface::class,
new class (
$container->get(AdministratorApplication::class),
$container->get(DatabaseInterface::class)
) implements InstallerScriptInterface {
private AdministratorApplication $app;
private DatabaseInterface $db;
public function __construct(AdministratorApplication $app, DatabaseInterface $db)
{
$this->app = $app;
$this->db = $db;
}
public function install(InstallerAdapter $parent): bool
{
$this->app->enqueueMessage('Successful installed.');
return true;
}
public function update(InstallerAdapter $parent): bool
{
$this->app->enqueueMessage('Successful updated.');
return true;
}
public function uninstall(InstallerAdapter $parent): bool
{
$this->app->enqueueMessage('Successful uninstalled.');
return true;
}
public function preflight(string $type, InstallerAdapter $parent): bool
{
return true;
}
public function postflight(string $type, InstallerAdapter $parent): bool
{
$this->deleteUnexistingFiles();
return true;
}
private function deleteUnexistingFiles()
{
$files = []; // overwrite this line with your files to delete
if (empty($files)) {
return;
}
foreach ($files as $file) {
try {
File::delete(JPATH_ROOT . $file);
} catch (\FilesystemException $e) {
echo Text::sprintf('FILES_JOOMLA_ERROR_FILE_FOLDER', $file) . '<br>';
}
}
}
}
);
}
};