PHP 插件监听器

问题描述 投票:0回答:1

所以我尝试使用侦听器在 PHP 中编写一个插件系统,就像我的世界对优先级和操作所做的那样,但我真的不知道如何做。因为如果我尝试使用事件侦听器,我必须将其赋予一个名为 $event 的值,但我无法与其他类共享该值,因为它们会告诉我可以使用 index.php 文件外部的变量.

我的项目结构就像一个 lavarel 结构,一个 public/index.php ,其余的只是 app/

这是插件事件:

<?php

namespace MythicalSystemsFramework\Plugins;

/**
 * This class is used to handle plugin events.
 *
 * @since 1.0.0
 *
 * @version 1.0.0
 *
 * @category Plugins
 *
 * This class is inspired by Evenement.
 *
 * @see https://github.com/igorw/even  ement
 *
 * @license MIT
 *
 *  */
class PluginEvent
{
    protected array $listeners = [];

    protected array $onceListeners = [];

    /**
     * Adds a listener for the specified event.
     *
     * @param string $event the name of the event
     * @param callable $listener the listener function to be added
     *
     * @return static returns the current instance of the PluginEvent class
     */
    public function on(string $event, callable $listener): static
    {
        if (!isset($this->listeners[$event])) {
            $this->listeners[$event] = [];
        }

        $this->listeners[$event][] = $listener;

        return $this;
    }

    /**
     * Adds a listener for the specified event that will be triggered only once.
     *
     * @param string $event the name of the event
     * @param callable $listener the listener function to be added
     *
     * @return static returns the current instance of the PluginEvent class
     */
    public function once(string $event, callable $listener): static
    {
        if (!isset($this->onceListeners[$event])) {
            $this->onceListeners[$event] = [];
        }

        $this->onceListeners[$event][] = $listener;

        return $this;
    }

    /**
     * Removes a listener for the specified event.
     *
     * @param string $event the name of the event
     * @param callable $listener the listener function to be removed
     */
    public function removeListener(string $event, callable $listener): void
    {
        if (isset($this->listeners[$event])) {
            $index = array_search($listener, $this->listeners[$event], true);

            if ($index !== false) {
                unset($this->listeners[$event][$index]);

                if (count($this->listeners[$event]) === 0) {
                    unset($this->listeners[$event]);
                }
            }
        }

        if (isset($this->onceListeners[$event])) {
            $index = array_search($listener, $this->onceListeners[$event], true);

            if ($index !== false) {
                unset($this->onceListeners[$event][$index]);

                if (count($this->onceListeners[$event]) === 0) {
                    unset($this->onceListeners[$event]);
                }
            }
        }
    }

    /**
     * Removes all listeners for the specified event or all events if no event is specified.
     *
     * @param string|null $event the name of the event (optional)
     */
    public function removeAllListeners(?string $event = null): void
    {
        if ($event !== null) {
            unset($this->listeners[$event], $this->onceListeners[$event]);
        } else {
            $this->listeners = [];
            $this->onceListeners = [];
        }
    }

    /**
     * Removes all listeners for the specified event or all events if no event is specified.
     *
     * @param string|null $event the name of the event (optional)
     *
     * @return void
     */
    public function listeners(?string $event = null): array
    {
        if ($event === null) {
            $events = [];
            $eventNames = array_unique(
                array_merge(
                    array_keys($this->listeners),
                    array_keys($this->onceListeners)
                )
            );

            foreach ($eventNames as $eventName) {
                $events[$eventName] = array_merge(
                    $this->listeners[$eventName] ?? [],
                    $this->onceListeners[$eventName] ?? []
                );
            }

            return $events;
        }

        return array_merge(
            $this->listeners[$event] ?? [],
            $this->onceListeners[$event] ?? []
        );
    }

    /**
     * Emits the specified event and triggers all associated listeners.
     *
     * @param string $event the name of the event
     * @param array $arguments the arguments to be passed to the listeners (optional)
     */
    public function emit(string $event, array $arguments = []): void
    {
        $listeners = [];
        if (isset($this->listeners[$event])) {
            $listeners = array_values($this->listeners[$event]);
        }

        $onceListeners = [];
        if (isset($this->onceListeners[$event])) {
            $onceListeners = array_values($this->onceListeners[$event]);
        }

        if ($listeners !== []) {
            foreach ($listeners as $listener) {
                $listener(...$arguments);
            }
        }

        if ($onceListeners !== []) {
            unset($this->onceListeners[$event]);

            foreach ($onceListeners as $listener) {
                $listener(...$arguments);
            }
        }
    }

    /**
     * Get an instance of the PluginEvent class.
     */
    public static function getInstance(): PluginEvent
    {
        return new PluginEvent();
    }
}

这是加载插件事件的内容:

<?php

namespace MythicalSystemsFramework\Plugins;

use MythicalSystemsFramework\Kernel\Config;
use MythicalSystemsFramework\Kernel\Logger;
use MythicalSystemsFramework\Kernel\LoggerTypes;
use MythicalSystemsFramework\Kernel\LoggerLevels;

class PluginsManager
{
    public static string $plugins_path = __DIR__ . '/../../storage/addons';

    public static function init(\Router\Router $router, \Twig\Environment $renderer, PluginEvent $eventHandler): void
    {
        if (!file_exists(self::$plugins_path)) {
            mkdir(self::$plugins_path, 0777, true);
        }

        $plugins = self::getAllPlugins();
        foreach ($plugins as $plugin) {
            $plugin_info = self::readPluginFile($plugin);
            /*
             * Are all the requirements installed?
             */
            if (isset($plugin_info['require'])) {
                $requirements = $plugin_info['require'];
                foreach ($requirements as $requirement) {
                    if ($requirement == 'MythicalSystemsFramework') {
                        continue;
                    }
                    $isInstalled = self::readPluginFile($requirement);
                    if ($isInstalled) {
                        continue;
                    } else {
                        Logger::log(LoggerLevels::CRITICAL, LoggerTypes::PLUGIN, "Plugin $plugin requires $requirement to be installed.");
                    }
                }
            }

            /*
             * Register the plugin in the database if it is not already registered.
             */
            if (!Database::doesInfoExist('name', $plugin_info['name']) == true) {
                $p = $plugin_info;

                $p_homepage = $p['homepage'] ?? null;
                $p_license = $p['license'] ?? null;
                $p_support = $p['support'] ?? null;
                $p_funding = $p['funding'] ?? null;
                $p_require = $p['require'] ?? 'MythicalSystemsFramework';
                Database::registerNewPlugin($p['name'], $p['description'], $p_homepage, $p_require, $p_license, $p['stability'], $p['authors'], $p_support, $p_funding, $p['version'], false);
                continue;
            }

            /**
             * Is plugin enabled?
             */
            $plugin_info_db = Database::getPlugin($plugin_info['name']);
            if ($plugin_info_db['enabled'] == 'true') {
                $plugin_home_dir = self::$plugins_path . '/' . $plugin_info['name'];
                $main_class = $plugin_home_dir . '/' . $plugin_info_db['name'] . '.php';
                if (file_exists($main_class)) {
                    /*
                     * Start the plugin main class.
                     */
                    try {
                        require_once $main_class;
                        $plugin_class = new $plugin_info_db['name']();
                        $plugin_class->Main();
                        try {
                            $plugin_class->Route($router, $renderer);
                        } catch (\Exception $e) {
                            Logger::log(LoggerLevels::CRITICAL, LoggerTypes::PLUGIN, 'Failed to add routes for plugin' . $plugin_info_db['name'] . '' . $e->getMessage());
                        }
                        try {
                            $plugin_class->Event($eventHandler);
                        } catch (\Exception $e) {
                            Logger::log(LoggerLevels::CRITICAL, LoggerTypes::PLUGIN, 'Failed to add events for plugin' . $plugin_info_db['name'] . '' . $e->getMessage());
                        }
                    } catch (\Exception $e) {
                        Logger::log(LoggerLevels::CRITICAL, LoggerTypes::PLUGIN, "Something failed while we tried to enable the plugin '" . $plugin_info_db['name'] . "'. " . $e->getMessage());
                    }
                } else {
                    Logger::log(LoggerLevels::CRITICAL, LoggerTypes::PLUGIN, "The main class for plugin '$plugin' does not exist.");
                }
            }
        }
    }

    /**
     * Get all plugins.
     */
    public static function getAllPlugins(): array
    {
        $plugins = [];
        foreach (scandir(self::$plugins_path) as $plugin) {
            if ($plugin == '.' || $plugin == '..') {
                continue;
            }
            $pluginPath = self::$plugins_path . '/' . $plugin;
            if (is_dir($pluginPath)) {
                $json_file = $pluginPath . '/MythicalFramework.json';
                if (file_exists($json_file)) {
                    $json = json_decode(file_get_contents($json_file), true);
                    if (isset($json['name']) && $json['name'] === $plugin) {
                        $plugins[] = $plugin;
                    }
                }
            }
        }

        return $plugins;
    }

    /**
     * Get plugin info.
     */
    public static function readPluginFile(string $plugin_name): array
    {
        if (!self::doesPluginExist($plugin_name)) {
            return [];
        }
        if (!self::isPluginConfigValid($plugin_name)) {
            return [];
        }
        $json_file = self::$plugins_path . '/' . $plugin_name . '/MythicalFramework.json';

        return json_decode(file_get_contents($json_file), true);
    }

    /**
     * Does a plugin exist?
     *
     * @param string $plugin_name The name of the plugin
     */
    public static function doesPluginExist(string $plugin_name): bool
    {
        $plugin_folder = self::$plugins_path . '/' . $plugin_name . '/MythicalFramework.json';

        return file_exists($plugin_folder);
    }

    /**
     * Is the plugin config valid?
     *
     * @param string $plugin_name The name of the plugin
     */
    public static function isPluginConfigValid(string $plugin_name): bool
    {
        if (!self::doesPluginExist($plugin_name)) {
            return false;
        }
        $json_file = self::$plugins_path . '/' . $plugin_name . '/MythicalFramework.json';
        if (file_exists($json_file)) {
            $json = json_decode(file_get_contents($json_file), true);
            if (isset($json['name']) && isset($json['description']) && isset($json['stability']) && isset($json['authors']) && isset($json['version']) && isset($json['require'])) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
}

这是 public/index.php 文件:

<?php

try {
    if (file_exists('../vendor/autoload.php')) {
        require '../vendor/autoload.php';
    } else {
        exit('Hello, it looks like you did not run: "<code>composer install --no-dev --optimize-autoloader</code>". Please run that and refresh the page');
    }
} catch (Exception $e) {
    exit('Hello, it looks like you did not run: <code>composer install --no-dev --optimize-autoloader</code> Please run that and refresh');
}

use MythicalSystemsFramework\App;
use MythicalSystemsFramework\Api\Api as api;
use MythicalSystemsFramework\Plugins\PluginEvent;
use MythicalSystemsFramework\Web\Template\Engine;
use MythicalSystemsFramework\Plugins\PluginsManager;
use MythicalSystemsFramework\Web\Installer\Installer;

$router = new Router\Router();
$event = new PluginEvent();
global $event;

define('$event', $event);

/*
 * Check if the app is installed
 */
Installer::Installed($router);
/*
 * Check if the app is healthy and all requirements are met
 */
App::checkIfAppIsHealthy();

/**
 * Get the renderer :).
 */
$renderer = Engine::getRenderer();

/*
 * Load the routes.
 */
api::registerApiRoutes($router);
App::registerRoutes($renderer);
$event->emit('app.onRoutesLoaded', [$router]);

/*
 * Initialize the plugins manager.
 */
PluginsManager::init($router, $renderer, $event);

$router->add('/(.*)', function () {
    global $renderer;
    $renderer->addGlobal('page_name', '404');
    http_response_code(404);
    exit($renderer->render('/errors/404.twig'));
});

try {
    $router->route();
} catch (Exception $e) {
    exit('Failed to start app: ' . $e->getMessage());
}

现在我尝试使用定义创建一个值,这样我就可以在全局范围内使用它,但是在执行类时我没有工作,并告诉我这是未定义的,下一个问题是 PluginManager 在应用程序文件夹之前初始化,因此基本上,由于插件在事件之前启动,因此事件将不起作用!所以在 PluginManager.init() 之后新注册的事件将不起作用!

我真的不知道如何解决这些问题!

所有的解释都在上面!

php plugins frameworks
1个回答
0
投票

全局函数是我客户的托管提供商的 PHP 配置错误!

这些事件不起作用,因为我是在之后而不是之前注册的事件!

如果有人有同样的问题,可以从我的项目中复制一些代码:

http://github.com/MythicalLTD/Framework

© www.soinside.com 2019 - 2024. All rights reserved.