refactor: enhance plugin mechanism for better extensibility

This commit is contained in:
xboard
2025-01-26 02:31:57 +08:00
parent e858a7c6db
commit 0141c68167
6 changed files with 144 additions and 89 deletions
+34 -17
View File
@@ -2,24 +2,22 @@
namespace App\Services\Plugin;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\File;
use Symfony\Component\HttpFoundation\Response;
abstract class AbstractPlugin
{
protected array $config = [];
/**
* 插件启动时调用
*/
public function boot(): void
{
// 子类实现具体逻辑
}
protected string $basePath;
protected string $pluginCode;
/**
* 插件禁用时调用
*/
public function cleanup(): void
public function __construct($pluginCode)
{
// 子类实现具体逻辑
$this->pluginCode = $pluginCode;
$reflection = new \ReflectionClass($this);
$this->basePath = dirname($reflection->getFileName());
}
/**
@@ -39,11 +37,19 @@ abstract class AbstractPlugin
}
/**
* 注册事件监听器
* 注册动作钩子监听器
*/
protected function listen(string $hook, callable $callback): void
protected function listen(string $hook, callable $callback, int $priority = 20): void
{
HookManager::register($hook, $callback);
HookManager::register($hook, $callback, $priority);
}
/**
* 注册过滤器钩子
*/
protected function filter(string $hook, callable $callback, int $priority = 20): void
{
HookManager::registerFilter($hook, $callback, $priority);
}
/**
@@ -53,4 +59,15 @@ abstract class AbstractPlugin
{
HookManager::remove($hook);
}
}
/**
* 中断当前请求并返回新的响应
*
* @param Response|string|array $response
* @return never
*/
protected function intercept(Response|string|array $response): never
{
HookManager::intercept($response);
}
}
+58 -11
View File
@@ -2,32 +2,78 @@
namespace App\Services\Plugin;
use Illuminate\Support\Facades\Event;
use TorMorten\Eventy\Facades\Events as Eventy;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
class HookManager
{
/**
* 触发钩子
* 拦截响应
*
* @param string $hook 钩子名称
* @param mixed $payload 传递给钩子的数据
* @return mixed
* @param SymfonyResponse|string|array $response 新的响应内容
* @return never
* @throws \Exception
*/
public static function call(string $hook, mixed $payload = null): mixed
public static function intercept(SymfonyResponse|string|array $response): never
{
return Event::dispatch($hook, [$payload]);
if (is_string($response)) {
$response = response($response);
} elseif (is_array($response)) {
$response = response()->json($response);
}
throw new InterceptResponseException($response);
}
/**
* 注册钩子监听器
* 触发动作钩子
*
* @param string $hook 钩子名称
* @param mixed $payload 传递给钩子的数据
* @return void
*/
public static function call(string $hook, mixed $payload = null): void
{
Eventy::action($hook, $payload);
}
/**
* 触发过滤器钩子
*
* @param string $hook 钩子名称
* @param mixed $value 要过滤的值
* @param mixed ...$args 其他参数
* @return mixed
*/
public static function filter(string $hook, mixed $value, mixed ...$args): mixed
{
return Eventy::filter($hook, $value, ...$args);
}
/**
* 注册动作钩子监听器
*
* @param string $hook 钩子名称
* @param callable $callback 回调函数
* @param int $priority 优先级
* @return void
*/
public static function register(string $hook, callable $callback): void
public static function register(string $hook, callable $callback, int $priority = 20): void
{
Event::listen($hook, $callback);
Eventy::addAction($hook, $callback, $priority);
}
/**
* 注册过滤器钩子
*
* @param string $hook 钩子名称
* @param callable $callback 回调函数
* @param int $priority 优先级
* @return void
*/
public static function registerFilter(string $hook, callable $callback, int $priority = 20): void
{
Eventy::addFilter($hook, $callback, $priority);
}
/**
@@ -38,6 +84,7 @@ class HookManager
*/
public static function remove(string $hook): void
{
Event::forget($hook);
Eventy::removeAction($hook);
Eventy::removeFilter($hook);
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Services\Plugin;
use Exception;
use Symfony\Component\HttpFoundation\Response;
class InterceptResponseException extends Exception
{
protected Response $response;
public function __construct(Response $response)
{
parent::__construct('Response intercepted');
$this->response = $response;
}
public function getResponse(): Response
{
return $this->response;
}
}
+7 -1
View File
@@ -5,6 +5,7 @@ namespace App\Services\Plugin;
use App\Models\Plugin;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\View;
class PluginManager
{
@@ -89,6 +90,11 @@ class PluginManager
if (File::exists($routesFile)) {
require $routesFile;
}
// 注册视图
$viewsPath = $this->pluginPath . '/' . $pluginCode . '/resources/views';
if (File::exists($viewsPath)) {
View::addNamespace($pluginCode, $viewsPath);
}
// 初始化插件
if (method_exists($plugin, 'boot')) {
@@ -150,7 +156,7 @@ class PluginManager
require_once $pluginFile;
$className = "Plugin\\{$pluginCode}\\Plugin";
return new $className();
return new $className($pluginCode);
}
/**