208 lines
6.4 KiB
PHP
208 lines
6.4 KiB
PHP
<?php
|
||||
|
|
|
|||
|
|
/**
|
|||
|
|
*+------------------
|
|||
|
|
* madong
|
|||
|
|
*+------------------
|
|||
|
|
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
|||
|
|
*+------------------
|
|||
|
|
* Author: Mr. April (405784684@qq.com)
|
|||
|
|
*+------------------
|
|||
|
|
* Official Website: http://www.madong.tech
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
namespace app\service\core\plugin;
|
|||
|
|
|
|||
|
|
use core\base\BaseService;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 插件基类服务
|
|||
|
|
*
|
|||
|
|
* 提供基础路径属性和插件方法执行能力
|
|||
|
|
* CLI 和在线模式共享同一套逻辑
|
|||
|
|
*/
|
|||
|
|
abstract class PluginBaseService extends BaseService
|
|||
|
|
{
|
|||
|
|
/**
|
|||
|
|
* 插件临时目录基础路径
|
|||
|
|
*/
|
|||
|
|
const RUNTIME_PLUGIN_PATH = 'install/plugin';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取插件构建目录
|
|||
|
|
*/
|
|||
|
|
public static function getPluginBuildPath(): string
|
|||
|
|
{
|
|||
|
|
return self::RUNTIME_PLUGIN_PATH . '/build';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取插件包输出目录
|
|||
|
|
*/
|
|||
|
|
public static function getPluginPackagesPath(): string
|
|||
|
|
{
|
|||
|
|
return self::RUNTIME_PLUGIN_PATH . '/packages';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取插件终端输出目录
|
|||
|
|
*/
|
|||
|
|
public static function getPluginTerminalPath(): string
|
|||
|
|
{
|
|||
|
|
return self::RUNTIME_PLUGIN_PATH . '/terminal';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 插件根目录
|
|||
|
|
*/
|
|||
|
|
protected string $plugin_path;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 项目根目录(前端和后端的父级目录)
|
|||
|
|
* 注意:此路径已不再直接指向前端目录
|
|||
|
|
* 前端目录统一在 $project_path/frontend 下,如 admin、web、uni-app 等
|
|||
|
|
*/
|
|||
|
|
protected string $project_path;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 后端根目录
|
|||
|
|
*/
|
|||
|
|
protected string $server_path;
|
|||
|
|
|
|||
|
|
public function __construct()
|
|||
|
|
{
|
|||
|
|
$this->plugin_path = base_path('plugin');
|
|||
|
|
$this->project_path = dirname(base_path()); // 项目根目录(前端和后端的父级)
|
|||
|
|
$this->server_path = base_path(); // 后端根目录
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取前端基础目录
|
|||
|
|
* 前端代码统一在 frontend 目录下
|
|||
|
|
*
|
|||
|
|
* @return string 前端基础目录
|
|||
|
|
*/
|
|||
|
|
public function getFrontendPath(): string
|
|||
|
|
{
|
|||
|
|
return $this->project_path . DIRECTORY_SEPARATOR . 'frontend';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取前端指定项目目录
|
|||
|
|
*
|
|||
|
|
* @param string $frontendType 前端类型(admin/web/uni-app)
|
|||
|
|
* @return string 前端项目目录
|
|||
|
|
*/
|
|||
|
|
public function getFrontendProjectPath(string $frontendType): string
|
|||
|
|
{
|
|||
|
|
return $this->getFrontendPath() . DIRECTORY_SEPARATOR . $frontendType;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取插件配置(兼容 ConfigTrait)
|
|||
|
|
*
|
|||
|
|
* @param string $code 插件编码
|
|||
|
|
* @return array|null
|
|||
|
|
*/
|
|||
|
|
protected function getPluginConfig(string $code): ?array
|
|||
|
|
{
|
|||
|
|
$configFile = $this->plugin_path . DIRECTORY_SEPARATOR . $code . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'info.php';
|
|||
|
|
if (is_file($configFile)) {
|
|||
|
|
return include $configFile;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 执行插件 Install 类方法
|
|||
|
|
*
|
|||
|
|
* 统一调用插件的 install/uninstall/update 方法
|
|||
|
|
* CLI 和在线模式都通过此方法调用
|
|||
|
|
*
|
|||
|
|
* @param string $code 插件编码
|
|||
|
|
* @param string $action 方法名 (install/uninstall/update)
|
|||
|
|
* @param string|null $version 版本(对于 install 是目标版本,对于 update 是新版本)
|
|||
|
|
* @param string|null $oldVersion 旧版本(仅 update 时使用)
|
|||
|
|
* @param bool $silent 是否静默执行失败(true: 失败不抛出异常, false: 失败抛出异常)
|
|||
|
|
* @return bool 是否成功执行
|
|||
|
|
* @throws \Exception 当 silent=false 且执行失败时抛出异常
|
|||
|
|
*/
|
|||
|
|
protected function executePluginMethod(string $code, string $action, ?string $version = null, ?string $oldVersion = null, bool $silent = false): bool
|
|||
|
|
{
|
|||
|
|
$className = "plugin\\" . $code . "\\Install";
|
|||
|
|
if (!class_exists($className)) {
|
|||
|
|
// 插件未提供 Install 类,静默跳过
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
$pluginConfig = $this->getPluginConfig($code);
|
|||
|
|
$version = $pluginConfig['version'] ?? ($version ?? '1.0.0');
|
|||
|
|
|
|||
|
|
// 实例化插件 Install 类
|
|||
|
|
$installInstance = new $className();
|
|||
|
|
|
|||
|
|
switch ($action) {
|
|||
|
|
case 'install':
|
|||
|
|
if (method_exists($installInstance, 'install')) {
|
|||
|
|
$installInstance->install($version);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'uninstall':
|
|||
|
|
if (method_exists($installInstance, 'uninstall')) {
|
|||
|
|
$installInstance->uninstall($version);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'update':
|
|||
|
|
if (method_exists($installInstance, 'update')) {
|
|||
|
|
$installInstance->update($oldVersion ?? '1.0.0', $version);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
default:
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
} catch (\Exception $e) {
|
|||
|
|
// 插件方法执行失败,记录日志
|
|||
|
|
$logLevel = $silent ? 'warning' : 'error';
|
|||
|
|
\support\Log::$logLevel('插件方法执行失败', [
|
|||
|
|
'plugin' => $code,
|
|||
|
|
'action' => $action,
|
|||
|
|
'version' => $version,
|
|||
|
|
'old_version' => $oldVersion,
|
|||
|
|
'exception' => $e->getMessage(),
|
|||
|
|
'file' => $e->getFile(),
|
|||
|
|
'line' => $e->getLine(),
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// 静默模式不抛出异常,非静默模式抛出异常
|
|||
|
|
if (!$silent) {
|
|||
|
|
throw $e;
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 调用插件 Install 类的方法(兼容 CLI 模式)
|
|||
|
|
*
|
|||
|
|
* 此方法专门用于 CLI 命令直接调用插件方法
|
|||
|
|
* 与在线模式的区别:CLI 模式不需要 SSE 返回,直接执行
|
|||
|
|
*
|
|||
|
|
* @param string $code 插件编码
|
|||
|
|
* @param string $action 方法名 (install/uninstall/update)
|
|||
|
|
* @param string|null $version 版本
|
|||
|
|
* @param string|null $oldVersion 旧版本(仅 update 时使用)
|
|||
|
|
* @return bool 是否成功
|
|||
|
|
* @throws \Exception
|
|||
|
|
*/
|
|||
|
|
public function callPluginInstallMethod(string $code, string $action, ?string $version = null, ?string $oldVersion = null): bool
|
|||
|
|
{
|
|||
|
|
return $this->executePluginMethod($code, $action, $version, $oldVersion, false);
|
|||
|
|
}
|
|||
|
|
}
|