"\\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 "
"; foreach ($this->logs as $log) printf("[%.6f] %s\n", $log[1] - START_TIME, $log[0]); echo ""; } 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"); } } ?>