mirror of
https://github.com/mivodev/mivo.git
synced 2026-01-26 05:25:42 +07:00
feat: Implement a core plugin system, integrate flag icon assets, and establish a GitHub release workflow.
This commit is contained in:
120
app/Core/Hooks.php
Normal file
120
app/Core/Hooks.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core;
|
||||
|
||||
class Hooks
|
||||
{
|
||||
/**
|
||||
* @var array Stores all registered actions
|
||||
*/
|
||||
private static $actions = [];
|
||||
|
||||
/**
|
||||
* @var array Stores all registered filters
|
||||
*/
|
||||
private static $filters = [];
|
||||
|
||||
/**
|
||||
* Register a new action
|
||||
*
|
||||
* @param string $tag The name of the action hook
|
||||
* @param callable $callback The function to call
|
||||
* @param int $priority Lower numbers correspond to earlier execution
|
||||
* @param int $accepted_args The number of arguments the function accepts
|
||||
*/
|
||||
public static function addAction($tag, $callback, $priority = 10, $accepted_args = 1)
|
||||
{
|
||||
self::$actions[$tag][$priority][] = [
|
||||
'function' => $callback,
|
||||
'accepted_args' => $accepted_args
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an action
|
||||
*
|
||||
* @param string $tag The name of the action hook
|
||||
* @param mixed ...$args Optional arguments to pass to the callback
|
||||
*/
|
||||
public static function doAction($tag, ...$args)
|
||||
{
|
||||
if (empty(self::$actions[$tag])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort by priority
|
||||
ksort(self::$actions[$tag]);
|
||||
|
||||
foreach (self::$actions[$tag] as $priority => $callbacks) {
|
||||
foreach ($callbacks as $callbackData) {
|
||||
call_user_func_array($callbackData['function'], array_slice($args, 0, $callbackData['accepted_args']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new filter
|
||||
*
|
||||
* @param string $tag The name of the filter hook
|
||||
* @param callable $callback The function to call
|
||||
* @param int $priority Lower numbers correspond to earlier execution
|
||||
* @param int $accepted_args The number of arguments the function accepts
|
||||
*/
|
||||
public static function addFilter($tag, $callback, $priority = 10, $accepted_args = 1)
|
||||
{
|
||||
self::$filters[$tag][$priority][] = [
|
||||
'function' => $callback,
|
||||
'accepted_args' => $accepted_args
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filters to a value
|
||||
*
|
||||
* @param string $tag The name of the filter hook
|
||||
* @param mixed $value The value to be filtered
|
||||
* @param mixed ...$args Optional extra arguments
|
||||
* @return mixed The filtered value
|
||||
*/
|
||||
public static function applyFilters($tag, $value, ...$args)
|
||||
{
|
||||
if (empty(self::$filters[$tag])) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Sort by priority
|
||||
ksort(self::$filters[$tag]);
|
||||
|
||||
foreach (self::$filters[$tag] as $priority => $callbacks) {
|
||||
foreach ($callbacks as $callbackData) {
|
||||
// Prepend value to args
|
||||
$params = array_merge([$value], array_slice($args, 0, $callbackData['accepted_args'] - 1));
|
||||
$value = call_user_func_array($callbackData['function'], $params);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any action has been registered for a hook.
|
||||
*
|
||||
* @param string $tag The name of the action hook.
|
||||
* @return bool True if action exists, false otherwise.
|
||||
*/
|
||||
public static function hasAction($tag)
|
||||
{
|
||||
return isset(self::$actions[$tag]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any filter has been registered for a hook.
|
||||
*
|
||||
* @param string $tag The name of the filter hook.
|
||||
* @return bool True if filter exists, false otherwise.
|
||||
*/
|
||||
public static function hasFilter($tag)
|
||||
{
|
||||
return isset(self::$filters[$tag]);
|
||||
}
|
||||
}
|
||||
78
app/Core/PluginManager.php
Normal file
78
app/Core/PluginManager.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core;
|
||||
|
||||
class PluginManager
|
||||
{
|
||||
/**
|
||||
* @var string Path to plugins directory
|
||||
*/
|
||||
private $pluginsDir;
|
||||
|
||||
/**
|
||||
* @var array List of active plugins
|
||||
*/
|
||||
private $activePlugins = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->pluginsDir = dirname(__DIR__, 2) . '/plugins'; // Root/plugins
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all active plugins
|
||||
*/
|
||||
public function loadPlugins()
|
||||
{
|
||||
// Ensure plugins directory exists
|
||||
if (!is_dir($this->pluginsDir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Get List of Active Plugins (For now, we load ALL folders as active)
|
||||
// TODO: Implement database/config check for active status
|
||||
$plugins = scandir($this->pluginsDir);
|
||||
|
||||
foreach ($plugins as $pluginName) {
|
||||
if ($pluginName === '.' || $pluginName === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pluginPath = $this->pluginsDir . '/' . $pluginName;
|
||||
|
||||
// Check if it is a directory and has specific plugin file
|
||||
if (is_dir($pluginPath) && file_exists($pluginPath . '/plugin.php')) {
|
||||
$this->loadPlugin($pluginName, $pluginPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Fire 'plugins_loaded' action after all plugins are loaded
|
||||
Hooks::doAction('plugins_loaded');
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a single plugin
|
||||
*
|
||||
* @param string $name Plugin folder name
|
||||
* @param string $path Full path to plugin directory
|
||||
*/
|
||||
private function loadPlugin($name, $path)
|
||||
{
|
||||
try {
|
||||
require_once $path . '/plugin.php';
|
||||
$this->activePlugins[] = $name;
|
||||
} catch (\Exception $e) {
|
||||
error_log("Failed to load plugin [$name]: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of loaded plugins
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getActivePlugins()
|
||||
{
|
||||
return $this->activePlugins;
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,9 @@ class Router {
|
||||
}
|
||||
|
||||
public function dispatch($uri, $method) {
|
||||
// Fire hook to allow plugins to register routes
|
||||
\App\Core\Hooks::doAction('router_init', $this);
|
||||
|
||||
$path = parse_url($uri, PHP_URL_PATH);
|
||||
|
||||
// Handle subdirectory
|
||||
|
||||
Reference in New Issue
Block a user