Files
MrleeAdmin/backend/app/service/core/plugin/PluginBaseService.php
T
2026-08-31 11:33:59 +08:00

208 lines
6.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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);
}
}