devsuite/cds/DevSuite.php

269 lines
7.0 KiB
PHP
Raw Permalink Normal View History

2024-05-27 00:44:14 -04:00
<?php
namespace Crispage\DevSuite;
defined("ROOT") or die();
require_once ROOT . "/cds/IniWriter.php";
require_once ROOT . "/cds/CDSPackager.php";
use \Crispage\ApplicationConfig;
use \Crispage\Request\Route;
use \Crispage\Signaling\Receiver;
use \Crispage\Extensions\Extension;
use \Crispage\Assets\Plugin;
class DevSuite {
public const EXT_CLASS_MAP = [
"asset" => "\\Crispage\\Framework\\Asset",
"action" => "\\Crispage\\Framework\\Action",
"component" => "\\Crispage\\Framework\\Component",
"plugin" => "\\Crispage\\Framework\\PluginClass",
"modulecomponent" => "\\Crispage\\Framework\\ModuleComponent"
];
public static function nicePrint(mixed $obj): string {
if (is_object($obj))
return "{" . $obj::class . "}";
if (is_array($obj))
return "[" . count($obj) . "]";
if (is_string($obj)) return "\"$obj\"";
return @strval($obj);
}
public \Crispage $app;
public CDSPackager $packager;
private array $logs;
private string $logprefix = "";
private bool $print_enabled = true;
public function __construct(\Crispage $app) {
$this->app = $app;
@$this->app->cds = $this;
$this->packager = new CDSPackager($this);
}
public function getLogPrefix(): ?string {
return $this->logprefix;
}
public function setLogPrefix(string $prefix) {
$this->logprefix = $prefix;
}
public function clearLogPrefix(): void {
$this->logprefix = "";
}
public function disableLogPrint(): void {
$this->print_enabled = false;
}
public function log(string $msg, ?string $tag = null): float {
$time = microtime(true);
if ($tag) $this->setLogPrefix("[$tag] ");
$fmsg = $this->logprefix . preg_replace("/\\n/", "\n\t", $msg);
$this->logs[] = [$fmsg, $time];
return $time;
}
public function logEvent(...$args): float {
$event = $this->app->dispatcher->event();
$ev = $this->app->dispatcher->getValue()->current();
if ($ev) $this->app->dispatcher->pushValue($ev);
$args = array_map([$this, "nicePrint"], $args);
return $this->log("$event(" . implode(", ", $args) . "): " . self::nicePrint($ev), "Event");
}
public function printLogs(): void {
if (!$this->print_enabled) return;
$this->app->dispatcher->suppress();
@ob_end_flush();
echo "<pre class=\"cds_log\">";
foreach ($this->logs as $log)
printf("[%.6f] %s\n", $log[1] - START_TIME, $log[0]);
echo "</pre>";
}
public function init(): void {
$this->app->dispatcher->register(new Receiver(
"crispage.devsuite.log_receiver",
"", -127, [$this, "logEvent"]
));
register_shutdown_function([$this, "printLogs"]);
$this->app->router->registerHardRoute(new Route(
"cds_console", "\\Crispage\\DevSuite\\ConsoleAction",
[]
), "backend");
$this->app->router->registerHardRoute(new Route(
"cds_classmanager", "\\Crispage\\DevSuite\\ClassManagerAction",
[]
), "backend");
$this->app->router->registerHardRoute(new Route(
"cds_packager", "\\Crispage\\DevSuite\\PackagerAction",
[]
), "backend");
$this->app->page->data["styles"]["cds"] = [
"_inner" => file_get_contents(ROOT . "/cds/static/assets/cds.css")
];
$this->log("CDS Initialized");
}
public function runScript(string $script): string {
$this->log("Running script", "Console");
$output = "";
ob_start();
try {
$start = microtime(true);
$res = eval($script);
$end = microtime(true);
}
catch (\Throwable $e) {
$err = $e;
}
$output .= ob_get_clean();
if (isset($err)) {
$this->log("ERROR: $err");
$output .= "\n== Script error ==\n$err";
}
else {
$ms = sprintf("%.3f", ($end - $start) * 1000);
$rval = print_r($res ?? "[nothing returned]", true);
$this->log("Executed in $ms ms");
$this->log("Return value: $rval");
$output .= "\n== Script executed in $ms ms ==\nReturn value:\n$rval";
}
return $output;
}
public function getExtensions(): array {
$res = $this->app->database->select(
"extensions", ["id"]
);
$exts = [];
foreach ($res->fetchAll(\PDO::FETCH_COLUMN) as $id) {
$ext = $this->app->extensions->get($id);
if ($ext) $exts[] = $ext;
}
return $exts;
}
public function registerExtension(string $classname, string $type): ?Extension {
$info = ApplicationConfig::get("cds.default_info");
$this->log("Registering $classname as $type...", "Extension");
switch ($type) {
case "asset":
case "action":
case "component":
case "plugin": {
try {
$this->app->loadClass($classname, self::EXT_CLASS_MAP[$type]);
}
catch (\Exception $e) {
return null;
}
$info = $classname::getExtensionInfo();
if (is_a($classname, self::EXT_CLASS_MAP["modulecomponent"], true))
$info["is_module"] = true;
break;
}
case "template": {
foreach (Config::TEMPLATE_PATH as $tp) {
$path = ROOT . "$tp/$classname/template.ini";
if (file_exists($path)) break;
}
$ini = parse_ini_file($path, true, INI_SCANNER_TYPED);
$info = array_merge($info, $ini["ExtensionInfo"] ?? []);
break;
}
case "translation": {
foreach (Config::TRANSLATION_PATH as $tp) {
$path = ROOT . "$tp/$classname/translations.ini";
if (file_exists($path)) break;
}
$ini = parse_ini_file($path, true, INI_SCANNER_TYPED);
$info = array_merge($info, $ini["ExtensionInfo"] ?? []);
break;
}
default:
return null;
}
$id = $info["id"];
$version = $info["version"] ?? VERSION;
$package = $info["package"] ?? explode(".", $id)[0] ?? "";
$data = array_diff_key($info, ApplicationConfig::get("cds.default_info"));
$ext = new Extension($id, $version, $package, $classname, $type, $data);
$this->app->extensions->register($ext);
$this->log("Success");
return $ext;
}
public function unregisterExtensions(array $ids): int {
$count = 0;
foreach ($ids as $id) {
$this->log("Unregistering $id...", "Extension");
$ext = $this->app->extensions->get($id);
if ($ext) {
$this->app->extensions->unregister($ext);
$count++;
}
}
$this->log("Unregistered $count extensions");
return $count;
}
public function createPlugin(string $extid, int $priority = 0): ?Plugin {
$ext = $this->app->extensions->get($extid);
if (!$ext || $ext->type != "plugin") return null;
$plugin = $this->app->assets->create(
"\\Crispage\\Assets\\Plugin", [
"slug" => preg_replace("/\\./", "__", $ext->id),
"classname" => $ext->classname,
"priority" => $priority
]
);
$this->log("Created plugin $extid", "Extension");
return $plugin;
}
public function deletePlugin(string $extid): void {
$ext = $this->app->extensions->get($extid);
if (!$ext || $ext->type != "plugin") return;
$plugins = $this->app->assets->getAllFiltered(
"\\Crispage\\Assets\\Plugin",
["classname" => $ext->classname]
);
foreach ($plugins as $plugin) {
if ($plugin->slug == "devsuite") continue;
$this->app->assets->delete($plugin);
}
$this->log("Deleted plugin $extid", "Extension");
}
}
?>