Files

208 lines
6.4 KiB
PHP
Raw Permalink Normal View History

2026-08-31 11:33:59 +08:00
<?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);
}
}