mirror of
https://github.com/vrana/adminer.git
synced 2025-12-29 03:40:35 +01:00
The class Plugins don't extend Adminer anymore. Adminer is now treated like any other plugin. Hooks are now registered in the constructor and they are called dynamically. Apart from being much more pleasant to work with, it shaves 7 kB from the compiled file.
82 lines
2.8 KiB
PHP
82 lines
2.8 KiB
PHP
<?php
|
|
namespace Adminer;
|
|
|
|
class Plugins {
|
|
/** @var list<object> @visibility protected(set) */ public array $plugins;
|
|
/** @visibility protected(set) */ public string $error = ''; // HTML
|
|
public $operators; //! delete
|
|
private $hooks = array();
|
|
private $append;
|
|
|
|
/** Register plugins
|
|
* @param ?list<object> $plugins object instances or null to autoload plugins from adminer-plugins/
|
|
*/
|
|
function __construct(?array $plugins) {
|
|
if ($plugins === null) {
|
|
$plugins = array();
|
|
$basename = "adminer-plugins";
|
|
if (is_dir($basename)) {
|
|
foreach (glob("$basename/*.php") as $filename) {
|
|
$include = include_once "./$filename";
|
|
}
|
|
}
|
|
$help = " href='https://www.adminer.org/plugins/#use'" . target_blank();
|
|
if (file_exists("$basename.php")) {
|
|
$include = include_once "./$basename.php"; // example: return array(new AdminerLoginOtp($secret))
|
|
if (is_array($include)) {
|
|
foreach ($include as $plugin) {
|
|
$plugins[get_class($plugin)] = $plugin;
|
|
}
|
|
} else {
|
|
$this->error .= lang('%s must <a%s>return an array</a>.', "<b>$basename.php</b>", $help) . "<br>";
|
|
}
|
|
}
|
|
foreach (get_declared_classes() as $class) {
|
|
if (!$plugins[$class] && preg_match('~^Adminer\w~i', $class)) {
|
|
// we need to use reflection because PHP 7.1 throws ArgumentCountError for missing arguments but older versions issue a warning
|
|
$reflection = new \ReflectionClass($class);
|
|
$constructor = $reflection->getConstructor();
|
|
if ($constructor && $constructor->getNumberOfRequiredParameters()) {
|
|
$this->error .= lang('<a%s>Configure</a> %s in %s.', $help, "<b>$class</b>", "<b>$basename.php</b>") . "<br>";
|
|
} else {
|
|
$plugins[$class] = new $class;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$this->plugins = $plugins;
|
|
$this->append = array_flip(array('dumpFormat', 'dumpOutput', 'editRowPrint', 'editFunctions')); // these hooks expect the value to be appended to the result
|
|
|
|
$adminer = new Adminer;
|
|
$plugins[] = $adminer;
|
|
$reflection = new \ReflectionObject($adminer);
|
|
foreach ($reflection->getMethods() as $method) {
|
|
foreach ($plugins as $plugin) {
|
|
$name = $method->getName();
|
|
if (method_exists($plugin, $name)) {
|
|
$this->hooks[$name][] = $plugin;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function __call($name, $params) {
|
|
$args = array();
|
|
foreach ($params as $key => $val) {
|
|
// some plugins accept params by reference - we don't need to propage it outside, just to the other plugins
|
|
$args[] = &$params[$key];
|
|
}
|
|
$return = null;
|
|
foreach ($this->hooks[$name] as $plugin) {
|
|
$value = call_user_func_array(array($plugin, $name), $args);
|
|
if ($value !== null) {
|
|
if (!isset($this->append[$name])) { // non-null value from non-appending method short-circuits the other plugins
|
|
return $value;
|
|
}
|
|
$return = $value + (array) $return;
|
|
}
|
|
}
|
|
return $return;
|
|
}
|
|
}
|