feat: unify kernel entry
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
99
bin/console
99
bin/console
@@ -3,21 +3,12 @@
|
||||
|
||||
/**
|
||||
* Console Entry Point
|
||||
*
|
||||
* Bootstraps the application container and registers console commands
|
||||
* from core and modules using lazy loading via Symfony Console.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use KTXC\Application;
|
||||
use KTXC\Kernel;
|
||||
use KTXC\Module\ModuleManager;
|
||||
use KTXF\Module\ModuleConsoleInterface;
|
||||
use Symfony\Component\Console\Application as ConsoleApplication;
|
||||
use Symfony\Component\Console\Command\LazyCommand;
|
||||
use KTXC\Server;
|
||||
|
||||
// Check dependencies
|
||||
if (!is_dir(dirname(__DIR__).'/vendor')) {
|
||||
fwrite(STDERR, "Dependencies are missing. Run 'composer install' first.\n");
|
||||
exit(1);
|
||||
@@ -26,91 +17,11 @@ if (!is_dir(dirname(__DIR__).'/vendor')) {
|
||||
require_once dirname(__DIR__).'/vendor/autoload.php';
|
||||
|
||||
try {
|
||||
// Bootstrap the application
|
||||
$projectRoot = dirname(__DIR__);
|
||||
$app = new Application($projectRoot);
|
||||
|
||||
// Boot kernel to initialize container and modules
|
||||
$app->kernel()->boot();
|
||||
|
||||
// Get the container
|
||||
$container = $app->container();
|
||||
|
||||
// Create Symfony Console Application
|
||||
$console = new ConsoleApplication('Ktrix Console', Kernel::VERSION);
|
||||
|
||||
// Collect all command classes
|
||||
$commandClasses = [];
|
||||
|
||||
// Collect commands from modules
|
||||
/** @var ModuleManager $moduleManager */
|
||||
$moduleManager = $container->get(ModuleManager::class);
|
||||
|
||||
foreach ($moduleManager->list() as $module) {
|
||||
$moduleInstance = $module->instance();
|
||||
|
||||
// Skip if module instance is not available
|
||||
if ($moduleInstance === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if module implements console command provider
|
||||
if ($moduleInstance instanceof ModuleConsoleInterface) {
|
||||
try {
|
||||
$commands = $moduleInstance->registerCI();
|
||||
|
||||
foreach ($commands as $commandClass) {
|
||||
if (!class_exists($commandClass)) {
|
||||
fwrite(STDERR, "Warning: Command class not found: {$commandClass}\n");
|
||||
continue;
|
||||
}
|
||||
$commandClasses[] = $commandClass;
|
||||
}
|
||||
$server = new Server(dirname(__DIR__));
|
||||
exit($server->runConsole());
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, "Warning: Failed to load commands from module {$module->handle()}: {$e->getMessage()}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register commands using lazy loading
|
||||
foreach ($commandClasses as $commandClass) {
|
||||
try {
|
||||
// Use reflection to read #[AsCommand] attribute without instantiation
|
||||
$reflection = new \ReflectionClass($commandClass);
|
||||
$attributes = $reflection->getAttributes(\Symfony\Component\Console\Attribute\AsCommand::class);
|
||||
|
||||
if (empty($attributes)) {
|
||||
fwrite(STDERR, "Warning: Command {$commandClass} missing #[AsCommand] attribute\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get attribute instance
|
||||
/** @var \Symfony\Component\Console\Attribute\AsCommand $commandAttr */
|
||||
$commandAttr = $attributes[0]->newInstance();
|
||||
|
||||
// Create lazy command wrapper that defers instantiation
|
||||
$lazyCommand = new LazyCommand(
|
||||
$commandAttr->name,
|
||||
[],
|
||||
$commandAttr->description ?? '',
|
||||
$commandAttr->hidden ?? false,
|
||||
fn() => $container->get($commandClass) // Only instantiate when executed
|
||||
);
|
||||
|
||||
$console->add($lazyCommand);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, "Warning: Failed to register command {$commandClass}: {$e->getMessage()}\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Run the console application
|
||||
$exitCode = $console->run();
|
||||
exit($exitCode);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, "Fatal error: " . $e->getMessage() . "\n");
|
||||
if (isset($app) && $app->debug()) {
|
||||
fwrite(STDERR, "Fatal error: {$e->getMessage()}\n");
|
||||
if (isset($server) && $server->debug()) {
|
||||
fwrite(STDERR, $e->getTraceAsString()."\n");
|
||||
}
|
||||
exit(1);
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC;
|
||||
|
||||
use KTXC\Http\Request\Request;
|
||||
use KTXC\Http\Response\Response;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Application class - entry point for the framework
|
||||
* Handles configuration loading and kernel lifecycle
|
||||
*/
|
||||
class Application
|
||||
{
|
||||
private static $composerLoader = null;
|
||||
|
||||
private Kernel $kernel;
|
||||
private array $config;
|
||||
private string $rootDir;
|
||||
|
||||
public function __construct(string $rootDir, ?string $environment = null, ?bool $debug = null)
|
||||
{
|
||||
$this->rootDir = $this->resolveProjectRoot($rootDir);
|
||||
|
||||
// Load configuration
|
||||
$this->config = $this->loadConfig();
|
||||
|
||||
// Determine environment and debug mode
|
||||
$environment = $environment ?? $this->config['environment'] ?? 'prod';
|
||||
$debug = $debug ?? $this->config['debug'] ?? false;
|
||||
|
||||
// Create kernel with configuration
|
||||
$this->kernel = new Kernel($environment, $debug, $this->config, $rootDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the application - handle incoming request and send response
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
try {
|
||||
$request = Request::createFromGlobals();
|
||||
$response = $this->handle($request);
|
||||
$response->send();
|
||||
$this->terminate();
|
||||
} catch (\Throwable $e) {
|
||||
// Last resort error handling for kernel initialization failures
|
||||
error_log('Application error: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
|
||||
$content = $this->kernel->debug()
|
||||
? '<pre>' . htmlspecialchars((string) $e) . '</pre>'
|
||||
: 'An error occurred. Please try again later.';
|
||||
$response = new Response($content, Response::HTTP_INTERNAL_SERVER_ERROR, [
|
||||
'Content-Type' => 'text/html; charset=UTF-8',
|
||||
]);
|
||||
$response->send();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
return $this->kernel->handle($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate the application - process deferred events
|
||||
*/
|
||||
public function terminate(): void
|
||||
{
|
||||
$this->kernel->processEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the kernel instance
|
||||
*/
|
||||
public function kernel(): Kernel
|
||||
{
|
||||
return $this->kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the container instance
|
||||
*/
|
||||
public function container(): ContainerInterface
|
||||
{
|
||||
return $this->kernel->container();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the application root directory
|
||||
*/
|
||||
public function rootDir(): string
|
||||
{
|
||||
return $this->rootDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the modules directory
|
||||
*/
|
||||
public function moduleDir(): string
|
||||
{
|
||||
return $this->rootDir . '/modules';
|
||||
}
|
||||
|
||||
public function varDir(): string
|
||||
{
|
||||
return $this->rootDir . '/var';
|
||||
}
|
||||
|
||||
public function logDir(): string
|
||||
{
|
||||
return $this->varDir() . '/logs';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get configuration value
|
||||
*/
|
||||
public function config(?string $key = null, mixed $default = null): mixed
|
||||
{
|
||||
if ($key === null) {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
// Support dot notation: 'database.uri'
|
||||
$keys = explode('.', $key);
|
||||
$value = $this->config;
|
||||
|
||||
foreach ($keys as $k) {
|
||||
if (!is_array($value) || !array_key_exists($k, $value)) {
|
||||
return $default;
|
||||
}
|
||||
$value = $value[$k];
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get environment
|
||||
*/
|
||||
public function environment(): string
|
||||
{
|
||||
return $this->kernel->environment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if debug mode is enabled
|
||||
*/
|
||||
public function debug(): bool
|
||||
{
|
||||
return $this->kernel->debug();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load configuration from config directory
|
||||
*/
|
||||
protected function loadConfig(): array
|
||||
{
|
||||
$configFile = $this->rootDir . '/config/system.php';
|
||||
|
||||
if (!file_exists($configFile)) {
|
||||
error_log('Configuration file not found: ' . $configFile);
|
||||
return [];
|
||||
}
|
||||
|
||||
$config = include $configFile;
|
||||
|
||||
if (!is_array($config)) {
|
||||
throw new \RuntimeException('Configuration file must return an array');
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the project root directory.
|
||||
*
|
||||
* Some entrypoints may pass the public/ directory or another subdirectory.
|
||||
* We walk up the directory tree until we find composer.json.
|
||||
*/
|
||||
private function resolveProjectRoot(string $startDir): string
|
||||
{
|
||||
$dir = rtrim($startDir, '/');
|
||||
if ($dir === '') {
|
||||
return $startDir;
|
||||
}
|
||||
|
||||
// If startDir is a file path, use its directory.
|
||||
if (is_file($dir)) {
|
||||
$dir = dirname($dir);
|
||||
}
|
||||
|
||||
$current = $dir;
|
||||
while (true) {
|
||||
if (is_file($current . '/composer.json')) {
|
||||
return $current;
|
||||
}
|
||||
|
||||
$parent = dirname($current);
|
||||
if ($parent === $current) {
|
||||
// Reached filesystem root
|
||||
return $dir;
|
||||
}
|
||||
$current = $parent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Composer ClassLoader instance
|
||||
*/
|
||||
public static function setComposerLoader($loader): void
|
||||
{
|
||||
self::$composerLoader = $loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Composer ClassLoader instance
|
||||
*/
|
||||
public static function getComposerLoader()
|
||||
{
|
||||
return self::$composerLoader;
|
||||
}
|
||||
}
|
||||
@@ -2,91 +2,310 @@
|
||||
|
||||
namespace KTXC;
|
||||
|
||||
use KTXC\Injection\Container;
|
||||
use KTXC\Http\Request\Request;
|
||||
use KTXC\Http\Response\Response;
|
||||
use KTXC\Module\ModuleAutoloader;
|
||||
use KTXC\Module\ModuleManager;
|
||||
use KTXF\Module\ModuleConsoleInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\Console\Application as ConsoleApplication;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\LazyCommand;
|
||||
|
||||
/**
|
||||
* Legacy Server class - now a facade to Application
|
||||
* @deprecated Use Application class directly
|
||||
* Server class - entry point for the framework
|
||||
* Handles configuration loading and kernel lifecycle
|
||||
*/
|
||||
class Server
|
||||
{
|
||||
public const ENVIRONMENT_DEV = 'dev';
|
||||
public const ENVIRONMENT_PROD = 'prod';
|
||||
private static $composerLoader = null;
|
||||
private static ?self $instance = null;
|
||||
|
||||
/**
|
||||
* @deprecated Use Application instead
|
||||
*/
|
||||
public static function run(): void {
|
||||
trigger_error('Server::run() is deprecated. Use Application class instead.', E_USER_DEPRECATED);
|
||||
private Kernel $kernel;
|
||||
private array $config;
|
||||
private string $rootDir;
|
||||
|
||||
$projectRoot = dirname(dirname(__DIR__));
|
||||
$app = new Application($projectRoot);
|
||||
$app->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Application::getInstance()->environment()
|
||||
*/
|
||||
public static function environment(): string {
|
||||
return self::app()->environment();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Application::getInstance()->debug()
|
||||
*/
|
||||
public static function debug(): bool {
|
||||
return self::app()->debug();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Application::getInstance()->kernel()
|
||||
*/
|
||||
public static function runtimeKernel(): Kernel {
|
||||
return self::app()->kernel();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Application::getInstance()->container()
|
||||
*/
|
||||
public static function runtimeContainer(): Container {
|
||||
return self::app()->container();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Application::getInstance()->rootDir()
|
||||
*/
|
||||
public static function runtimeRootLocation(): string {
|
||||
return self::app()->rootDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Application::getInstance()->moduleDir()
|
||||
*/
|
||||
public static function runtimeModuleLocation(): string {
|
||||
return self::app()->moduleDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Application::setComposerLoader()
|
||||
*/
|
||||
public static function setComposerLoader($loader): void {
|
||||
Application::setComposerLoader($loader);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Application::getComposerLoader()
|
||||
*/
|
||||
public static function getComposerLoader() {
|
||||
return Application::getComposerLoader();
|
||||
}
|
||||
|
||||
private static function app(): Application
|
||||
public function __construct(string $rootDir, ?string $environment = null, ?bool $debug = null)
|
||||
{
|
||||
throw new \RuntimeException(
|
||||
'Server class is deprecated and no longer functional. ' .
|
||||
'Update your code to use Application class with proper dependency injection. ' .
|
||||
'See the migration guide for details.'
|
||||
);
|
||||
self::$instance = $this;
|
||||
|
||||
$this->rootDir = $this->resolveProjectRoot($rootDir);
|
||||
|
||||
// Load configuration
|
||||
$this->config = $this->loadConfig();
|
||||
|
||||
// Determine environment and debug mode
|
||||
$environment = $environment ?? $this->config['environment'] ?? 'prod';
|
||||
$debug = $debug ?? $this->config['debug'] ?? false;
|
||||
|
||||
// Create kernel with configuration
|
||||
$this->kernel = new Kernel($environment, $debug, $this->config, $rootDir);
|
||||
|
||||
// Register module autoloader for both HTTP and CLI contexts
|
||||
$moduleAutoloader = new ModuleAutoloader($this->moduleDir());
|
||||
$moduleAutoloader->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the application - handle incoming request and send response
|
||||
*/
|
||||
public function runHttp(): void
|
||||
{
|
||||
try {
|
||||
$request = Request::createFromGlobals();
|
||||
$response = $this->handle($request);
|
||||
$response->send();
|
||||
$this->terminate();
|
||||
} catch (\Throwable $e) {
|
||||
// Last resort error handling for kernel initialization failures
|
||||
error_log('Application error: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
|
||||
$content = $this->kernel->debug()
|
||||
? '<pre>' . htmlspecialchars((string) $e) . '</pre>'
|
||||
: 'An error occurred. Please try again later.';
|
||||
$response = new Response($content, Response::HTTP_INTERNAL_SERVER_ERROR, [
|
||||
'Content-Type' => 'text/html; charset=UTF-8',
|
||||
]);
|
||||
$response->send();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run as a console application (CLI runtime).
|
||||
*/
|
||||
public function runConsole(): int
|
||||
{
|
||||
$this->kernel()->boot();
|
||||
$container = $this->container();
|
||||
|
||||
$console = new ConsoleApplication('Ktrix Console', Kernel::VERSION);
|
||||
|
||||
/** @var ModuleManager $moduleManager */
|
||||
$moduleManager = $container->get(ModuleManager::class);
|
||||
|
||||
foreach ($moduleManager->list() as $module) {
|
||||
$instance = $module->instance();
|
||||
if (!$instance instanceof ModuleConsoleInterface) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
foreach ($instance->registerCI() as $commandClass) {
|
||||
if (!class_exists($commandClass)) {
|
||||
fwrite(STDERR, "Warning: Command class not found: {$commandClass}\n");
|
||||
continue;
|
||||
}
|
||||
$this->registerLazyCommand($console, $container, $commandClass);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, "Warning: Failed to load commands from module {$module->handle()}: {$e->getMessage()}\n");
|
||||
}
|
||||
}
|
||||
|
||||
return $console->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
return $this->kernel->handle($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate the application - process deferred events
|
||||
*/
|
||||
public function terminate(): void
|
||||
{
|
||||
$this->kernel->processEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the kernel instance
|
||||
*/
|
||||
public function kernel(): Kernel
|
||||
{
|
||||
return $this->kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the container instance
|
||||
*/
|
||||
public function container(): ContainerInterface
|
||||
{
|
||||
return $this->kernel->container();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the application root directory
|
||||
*/
|
||||
public function rootDir(): string
|
||||
{
|
||||
return $this->rootDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the modules directory
|
||||
*/
|
||||
public function moduleDir(): string
|
||||
{
|
||||
return $this->rootDir . '/modules';
|
||||
}
|
||||
|
||||
public function varDir(): string
|
||||
{
|
||||
return $this->rootDir . '/var';
|
||||
}
|
||||
|
||||
public function logDir(): string
|
||||
{
|
||||
return $this->varDir() . '/logs';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get configuration value
|
||||
*/
|
||||
public function config(?string $key = null, mixed $default = null): mixed
|
||||
{
|
||||
if ($key === null) {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
// Support dot notation: 'database.uri'
|
||||
$keys = explode('.', $key);
|
||||
$value = $this->config;
|
||||
|
||||
foreach ($keys as $k) {
|
||||
if (!is_array($value) || !array_key_exists($k, $value)) {
|
||||
return $default;
|
||||
}
|
||||
$value = $value[$k];
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get environment
|
||||
*/
|
||||
public function environment(): string
|
||||
{
|
||||
return $this->kernel->environment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if debug mode is enabled
|
||||
*/
|
||||
public function debug(): bool
|
||||
{
|
||||
return $this->kernel->debug();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load configuration from config directory
|
||||
*/
|
||||
protected function loadConfig(): array
|
||||
{
|
||||
$configFile = $this->rootDir . '/config/system.php';
|
||||
|
||||
if (!file_exists($configFile)) {
|
||||
error_log('Configuration file not found: ' . $configFile);
|
||||
return [];
|
||||
}
|
||||
|
||||
$config = include $configFile;
|
||||
|
||||
if (!is_array($config)) {
|
||||
throw new \RuntimeException('Configuration file must return an array');
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the project root directory.
|
||||
*
|
||||
* Some entrypoints may pass the public/ directory or another subdirectory.
|
||||
* We walk up the directory tree until we find composer.json.
|
||||
*/
|
||||
private function resolveProjectRoot(string $startDir): string
|
||||
{
|
||||
$dir = rtrim($startDir, '/');
|
||||
if ($dir === '') {
|
||||
return $startDir;
|
||||
}
|
||||
|
||||
// If startDir is a file path, use its directory.
|
||||
if (is_file($dir)) {
|
||||
$dir = dirname($dir);
|
||||
}
|
||||
|
||||
$current = $dir;
|
||||
while (true) {
|
||||
if (is_file($current . '/composer.json')) {
|
||||
return $current;
|
||||
}
|
||||
|
||||
$parent = dirname($current);
|
||||
if ($parent === $current) {
|
||||
// Reached filesystem root
|
||||
return $dir;
|
||||
}
|
||||
$current = $parent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Composer ClassLoader instance
|
||||
*/
|
||||
public static function setComposerLoader($loader): void
|
||||
{
|
||||
self::$composerLoader = $loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Composer ClassLoader instance
|
||||
*/
|
||||
public static function getComposerLoader()
|
||||
{
|
||||
return self::$composerLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Application instance
|
||||
*/
|
||||
public static function getInstance(): ?self
|
||||
{
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a single command via lazy loading using its #[AsCommand] attribute.
|
||||
*/
|
||||
private function registerLazyCommand(
|
||||
ConsoleApplication $console,
|
||||
ContainerInterface $container,
|
||||
string $commandClass
|
||||
): void {
|
||||
try {
|
||||
$ref = new \ReflectionClass($commandClass);
|
||||
$attrs = $ref->getAttributes(AsCommand::class);
|
||||
|
||||
if (empty($attrs)) {
|
||||
fwrite(STDERR, "Warning: Command {$commandClass} missing #[AsCommand] attribute\n");
|
||||
return;
|
||||
}
|
||||
|
||||
$attr = $attrs[0]->newInstance();
|
||||
$console->add(new LazyCommand(
|
||||
$attr->name,
|
||||
[],
|
||||
$attr->description ?? '',
|
||||
$attr->hidden ?? false,
|
||||
fn() => $container->get($commandClass)
|
||||
));
|
||||
} catch (\Throwable $e) {
|
||||
fwrite(STDERR, "Warning: Failed to register command {$commandClass}: {$e->getMessage()}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,11 @@
|
||||
<?php
|
||||
|
||||
use KTXC\Application;
|
||||
use KTXC\Module\ModuleAutoloader;
|
||||
use KTXC\Server;
|
||||
|
||||
// Capture Composer ClassLoader instance
|
||||
// Capture Composer ClassLoader instance for compatibility
|
||||
$composerLoader = require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// Determine project root (one level up from this file)
|
||||
$projectRoot = dirname(__DIR__);
|
||||
$server = new Server(dirname(__DIR__));
|
||||
Server::setComposerLoader($composerLoader);
|
||||
|
||||
// Create and run application
|
||||
$app = new Application($projectRoot);
|
||||
|
||||
// Store composer loader for compatibility
|
||||
Application::setComposerLoader($composerLoader);
|
||||
|
||||
// Register custom module autoloader for lazy loading
|
||||
$moduleAutoloader = new ModuleAutoloader($app->moduleDir());
|
||||
$moduleAutoloader->register();
|
||||
|
||||
$app->run();
|
||||
$server->runHttp();
|
||||
Reference in New Issue
Block a user