[ Mini Kiebo ]
Server: Windows NT DESKTOP-5B8S0D4 6.2 build 9200 (Windows 8 Professional Edition) i586
Path:
D:
/
Backup
/
Data Shendy
/
Back up Shendy
/
DATA
/
amd64
/
httpd
/
htdocs
/
bulian
/
lib
/
[
Home
]
File: Plugins.php
<?php /** * @Created by : Waris Agung Widodo (ido.alit@gmail.com) * @Date : 05/11/20 13.53 * @File name : Plugins.php */ namespace SLiMS; use SLiMS\SearchEngine\Engine; use stdClass; class Plugins { const DATABASE_VERSION = 'db_version'; private static $instance; /** * Store plugins location, so plugins can stored in multiple location * @var array */ protected array $locations = []; /** * Plugin scanned will store here * @var array */ protected array $plugins = []; protected array $active_plugins = []; protected array $hooks = []; protected array $menus = []; private int $deep = 2; private string $hook_handler = ''; private string $current_location = ''; private ?string $group_name = null; /** * Plugins constructor. * @param null $location */ public function __construct($location = null) { $this->addLocation($location); } public static function getInstance(): Plugins { if (is_null(self::$instance)) self::$instance = new static; return self::$instance; } /** * @param array|string $location * @return Plugins */ public function addLocation($location): Plugins { if (is_array($location)) { $this->locations = array_unique(array_merge($this->locations, $location)); } elseif (!is_null($location)) { $this->locations[] = $location; } else { // setup default location $this->locations[] = realpath(__DIR__ . '/../plugins'); } return $this; } private function getPluginInfo($path): stdClass { $file_open = fopen($path, 'r'); $raw_data = fread($file_open, 8192); fclose($file_open); // store plugin info as object $plugin = new stdClass; // parsing plugin data preg_match('|Plugin Name:(.*)$|mi', $raw_data, $plugin->name); preg_match('|Plugin URI:(.*)$|mi', $raw_data, $plugin->uri); preg_match('|Version:(.*)|i', $raw_data, $plugin->version); preg_match('|Description:(.*)$|mi', $raw_data, $plugin->description); preg_match('|Author:(.*)$|mi', $raw_data, $plugin->author); preg_match('|Author URI:(.*)$|mi', $raw_data, $plugin->author_uri); foreach (get_object_vars($plugin) as $key => $val) { $plugin->$key = isset($val[1]) && trim($val[1]) !== '' ? trim($val[1]) : null; } $plugin->id = md5($path); $plugin->path = $path; return $plugin; } private function getPluginsInfo($location) { // open location if ($dir = opendir($location)) { while ($file = readdir($dir)) { $path = $location . DS . $file; // if location is file if (is_file($path)) { // just get file with suffix plugin.php if (strpos($path, 'plugin.php')) { $plugin = $this->getPluginInfo($path); // get migration info $this->plugins[$plugin->id] = $plugin; $this->plugins[$plugin->id]->migration = $this->getMigrationInfo($plugin); } } elseif (is_dir($path) && (substr($file, 0, 1) != '.')) { // get plugins from sub folder location // deep level directory that will be scanned if ($this->isDeep($location)) $this->getPluginsInfo($path); } } closedir($dir); } } private function getMigrationInfo($plugin): stdClass { $migration = new stdClass; $migration->is_exist = false; $migration_directory = dirname($plugin->path) . DIRECTORY_SEPARATOR . 'migration'; if (is_dir($migration_directory)) { $migration->is_exist = true; $migration->{self::DATABASE_VERSION} = $this->getDBVersion($plugin->id); } return $migration; } private function getOptions($id): void { if (isset($this->active_plugins[$id])) { try { $this->plugins[$id]->options = json_decode($this->active_plugins[$id]->options??''); } catch (\Exception $exception) { $this->plugins[$id]->options = new stdClass; } } else { $stmt = DB::getInstance()->prepare('SELECT options FROM plugins WHERE id = :id'); $stmt->execute(['id' => $id]); if ($stmt->rowCount() < 1) $this->plugins[$id]->options = new stdClass; $plugin = $stmt->fetch(\PDO::FETCH_OBJ); try { $this->plugins[$id]->options = json_decode($plugin->options ?? '{}'); } catch (\Exception $exception) { $this->plugins[$id]->options = new stdClass; } } } private function getDBVersion($id): int { $this->getOptions($id); return $this->plugins[$id]->options->{self::DATABASE_VERSION} ?? 0; } function isDeep($location): bool { $sub_dir = str_replace($this->current_location, '', $location); $arr_sub_dir = explode(DIRECTORY_SEPARATOR, $sub_dir); return count($arr_sub_dir) <= $this->deep; } /** * @return array */ public function getPlugins(): array { foreach ($this->locations as $location) { $this->current_location = $location; $this->getPluginsInfo($location); } return $this->plugins; } /** * Get active plugins from database */ public function getActive(): array { $query = DB::getInstance()->query("SELECT * FROM plugins WHERE deleted_at IS NULL"); while ($data = $query->fetchObject()) $this->active_plugins[$data->id] = $data; return $this->active_plugins; } public function isActive($id): bool { $query = DB::getInstance()->prepare("SELECT * FROM plugins WHERE ID = :id"); $query->bindValue(':id', $id); $query->execute(); return $query->rowCount() > 0; } public function loadPlugins() { foreach ($this->getActive() as $item) { if (file_exists($item->path)) require_once $item->path; } } public function register($hook, $callback) { $this->hooks[$hook][] = [$callback, $this->hook_handler]; } public function registerHook($hook, $callback) { $this->register($hook, $callback); } public function registerMenu($module_name, $label, $path, $description = null) { $hash = md5(realpath($path)); if ($module_name === 'opac') { $name = strtolower(implode('_', explode(' ', $label))); $this->menus[$module_name][$name] = [$label, SWB . 'index.php?p=' . $name, $description, realpath($path)]; } else { $this->menus[$module_name][$hash] = [$label, AWB . 'plugin_container.php?mod=' . $module_name . '&id=' . $hash, $description, realpath($path)]; } $group_instance = GroupMenu::getInstance()->bind($hash); if (!is_null($this->group_name)) $group_instance->group($this->group_name); return $group_instance; } public function registerSearchEngine($class_name) { Engine::init()->set($class_name); } public static function group($group_name, $callback): GroupMenuOrder { self::getInstance()->setGroupName($group_name); $callback(); self::getInstance()->setGroupName(null); return GroupMenuOrder::getInstance()->bind($group_name); } public static function menu($module_name, $label, $path, $description = null) { return self::getInstance()->registerMenu($module_name, $label, $path, $description = null); } public static function hook($hook, $callback) { self::getInstance()->registerHook($hook, $callback); } public function setGroupName($group_name) { $this->group_name = $group_name; } public function execute($hook, $params = []) { foreach ($this->hooks[$hook] ?? [] as $hook) { list($callback, $handler) = $hook; if (is_callable($callback)) call_user_func_array($callback, array_values($params)); if (!empty($handler) && is_string($callback) && method_exists(($handlerInstance = new $handler), $callback)) {call_user_func_array([$handlerInstance, $callback], array_values($params));} } } public static function use($handler_class) { self::getInstance()->hook_handler = $handler_class; return self::getInstance(); } public function for($hooks) { if (empty($this->hook_handler)) return; if (is_callable($hooks)) call_user_func_array($hooks, [$this]); } /** * @param null $module * @return array */ public function getMenus($module = null): array { if (is_null($module)) return $this->menus; return $this->menus[$module] ?? []; } }