mirror of
https://github.com/openvk/chandler.git
synced 2025-03-29 12:38:12 +03:00
120 lines
4.9 KiB
PHP
120 lines
4.9 KiB
PHP
<?php declare(strict_types=1);
|
|
namespace Chandler\Extensions;
|
|
use Chandler\Eventing\EventDispatcher;
|
|
use Chandler\Patterns\TSimpleSingleton;
|
|
use Chandler\MVC\Routing\Router;
|
|
use Nette\Utils\Finder;
|
|
|
|
define("CHANDLER_EXTENSIONS", CHANDLER_ROOT . "/extensions", false);
|
|
define("CHANDLER_EXTENSIONS_AVAILABLE", CHANDLER_EXTENSIONS . "/available", false);
|
|
define("CHANDLER_EXTENSIONS_ENABLED", CHANDLER_EXTENSIONS . "/enabled", false);
|
|
|
|
class ExtensionManager
|
|
{
|
|
private $extensions = [];
|
|
private $router = NULL;
|
|
private $rootApp = NULL;
|
|
private $eventLoop = NULL;
|
|
|
|
private function __construct()
|
|
{
|
|
foreach(Finder::findDirectories("*")->in(CHANDLER_EXTENSIONS_AVAILABLE) as $directory) {
|
|
$extensionName = $directory->getFilename();
|
|
$directory = $directory->getRealPath();
|
|
$config = "$directory/manifest.yml";
|
|
|
|
if(!file_exists($config)) {
|
|
trigger_error("Skipping $extensionName for not having a valid configuration file ($config is not found)", E_USER_WARNING);
|
|
continue;
|
|
}
|
|
|
|
$this->extensions[$extensionName] = (object) chandler_parse_yaml($config);
|
|
$this->extensions[$extensionName]->id = $extensionName;
|
|
$this->extensions[$extensionName]->rawName = $directory;
|
|
$this->extensions[$extensionName]->enabled = false;
|
|
}
|
|
|
|
foreach(Finder::find("*")->in(CHANDLER_EXTENSIONS_ENABLED) as $directory) { #findDirectories doesn't work with symlinks
|
|
if(!is_dir($directory->getRealPath())) continue;
|
|
|
|
$extension = $directory->getFilename();
|
|
|
|
if(!array_key_exists($extension, $this->extensions)) {
|
|
trigger_error("Extension $extension is enabled, but not available, skipping", E_USER_WARNING);
|
|
continue;
|
|
}
|
|
|
|
$this->extensions[$extension]->enabled = true;
|
|
}
|
|
|
|
if(!array_key_exists(CHANDLER_ROOT_CONF["rootApp"], $this->extensions) || !$this->extensions[CHANDLER_ROOT_CONF["rootApp"]]->enabled) {
|
|
trigger_error("Selected root app is not available", E_USER_ERROR);
|
|
}
|
|
|
|
$this->rootApp = CHANDLER_ROOT_CONF["rootApp"];
|
|
$this->eventLoop = EventDispatcher::i();
|
|
$this->router = Router::i();
|
|
|
|
$this->init();
|
|
}
|
|
|
|
private function init(): void
|
|
{
|
|
foreach($this->getExtensions(true) as $name => $configuration) {
|
|
spl_autoload_register(@create_function("\$class", "
|
|
if(!substr(\$class, 0, " . iconv_strlen("$name\\") . ") === \"$name\\\\\") return false;
|
|
|
|
require_once CHANDLER_ROOT . \"/extensions/enabled/\" . str_replace(\"\\\\\", \"/\", \$class) . \".php\";
|
|
"));
|
|
|
|
define(mb_strtoupper($name) . "_ROOT", CHANDLER_ROOT . "/extensions/enabled/$name", false);
|
|
define(mb_strtoupper($name) . "_ROOT_CONF", chandler_parse_yaml(CHANDLER_ROOT . "/extensions/enabled/$name/$name.yml"), false);
|
|
|
|
if(isset($configuration->init))
|
|
(require(CHANDLER_ROOT . "/extensions/enabled/$name/" . $configuration->init))();
|
|
|
|
if(is_dir($hooks = CHANDLER_EXTENSIONS_ENABLED . "/$name/Hooks")) {
|
|
foreach(Finder::findFiles("*Hook.php")->in($hooks) as $hookFile) {
|
|
$hookClassName = "$name\\Hooks\\" . str_replace(".php", "", end(explode("/", $hookFile)));
|
|
$hook = new $hookClassName;
|
|
|
|
$this->eventLoop->addListener($hook);
|
|
}
|
|
}
|
|
|
|
if(is_dir($app = CHANDLER_EXTENSIONS_ENABLED . "/$name/Web")) #"app" means "web app", thus variable is called $app
|
|
$this->router->readRoutes("$app/routes.yml", $name, $this->rootApp !== $name);
|
|
}
|
|
}
|
|
|
|
function getExtensions(bool $onlyEnabled = false): array
|
|
{
|
|
return $onlyEnabled
|
|
? array_filter($this->extensions, function($e) { return $e->enabled; })
|
|
: $this->extensions;
|
|
}
|
|
|
|
function getExtension(string $name): ?object
|
|
{
|
|
return @$this->extensions[$name];
|
|
}
|
|
|
|
function disableExtension(string $name): void
|
|
{
|
|
if(!array_key_exists($name, $this->getExtensions(true))) return;
|
|
|
|
if(!unlink(CHANDLER_EXTENSIONS_ENABLED . "/$name")) throw new \Exception("Could not disable extension");
|
|
}
|
|
|
|
function enableExtension(string $name): void
|
|
{
|
|
if(array_key_exists($name, $this->getExtensions(true))) return;
|
|
|
|
$path = CHANDLER_EXTENSIONS_AVAILABLE . "/$name";
|
|
if(!is_dir($path)) throw new \Exception("Extension doesn't exist");
|
|
|
|
if(!symlink($path, str_replace("available", "enabled", $path))) throw new \Exception("Could not enable extension");
|
|
}
|
|
|
|
use TSimpleSingleton;
|
|
}
|