Files
dockerfluxodecaixapro/kernel/ModuleLoader.php
T
2026-09-01 10:46:29 -03:00

202 lines
5.6 KiB
PHP
Executable File

<?php
namespace Kernel;
use Exception;
class ModuleLoader
{
protected string $modulesPath;
protected array $modules = [];
protected array $loaded = [];
public function __construct(string $modulesPath)
{
$this->modulesPath = rtrim($modulesPath, '/');
}
/**
* Registers the autoloader for module classes
* Pattern: Modules\{Module}\{Class} -> modules/{module}/classes/{Class}.php
*/
public function registerAutoload(): void
{
spl_autoload_register(function ($class) {
// Base prefix
$prefix = 'Modules\\';
// Checks if the class uses the prefix
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
}
// Gets the relative class name without the prefix
$relativeClass = substr($class, $len);
// Separates the module name (first part of the namespace)
$parts = explode('\\', $relativeClass);
$moduleName = array_shift($parts);
if (empty($moduleName)) {
return;
}
// Converts the module name to lowercase to match the folder
$moduleDir = strtolower($moduleName);
// Rebuilds the class path
$classPath = implode('/', $parts);
// File path
$file = $this->modulesPath . '/' . $moduleDir . '/classes/' . $classPath . '.php';
// If the file exists, load it
if (file_exists($file)) {
require $file;
}
});
}
/**
* Loads all modules
*/
public function loadAll(): void
{
$dirs = glob($this->modulesPath . '/*', GLOB_ONLYDIR);
foreach ($dirs as $dir) {
$moduleName = basename($dir);
$this->load($moduleName);
}
}
/**
* Loads a specific module
*/
public function load(string $moduleName): void
{
if (isset($this->loaded[$moduleName])) {
return; // already loaded
}
$modulePath = $this->modulesPath . '/' . $moduleName;
// Checks if it exists
if (!is_dir($modulePath)) {
throw new Exception("Módulo '{$moduleName}' não encontrado.");
}
// Checks module.json
$jsonFile = $modulePath . '/module.json';
if (!file_exists($jsonFile)) {
throw new Exception("O módulo '{$moduleName}' não possui um module.json válido.");
}
$config = json_decode(file_get_contents($jsonFile), true);
if (!is_array($config)) {
throw new Exception("module.json inválido no módulo '{$moduleName}'.");
}
$this->modules[$moduleName] = $config;
// Load Service Providers
$this->registerProviders($config);
// Load Routes
$this->registerRoutes($moduleName, $modulePath, $config);
// Register Views and Locales
$this->registerResources($moduleName, $modulePath, $config);
$this->loaded[$moduleName] = true;
}
/**
* Registers Service Providers
*/
protected function registerProviders(array $config): void
{
if (!isset($config['providers'])) {
return;
}
foreach ($config['providers'] as $class) {
if (class_exists($class)) {
$provider = new $class();
if (method_exists($provider, 'register')) {
$provider->register();
}
if (method_exists($provider, 'boot')) {
$provider->boot();
}
}
}
}
/**
* Loads route files
*/
protected function registerRoutes(string $module, string $path, array $config): void
{
if (!isset($config['routes'])) {
return;
}
// Get the application instance to register routes
$app = \Kernel\Application::getInstance();
if (isset($config['routes']['web'])) {
$file = $path . '/' . $config['routes']['web'];
if (file_exists($file)) {
$routeLoader = require $file;
if (is_callable($routeLoader) && $app) {
$routeLoader($app);
}
}
}
if (isset($config['routes']['api'])) {
$file = $path . '/' . $config['routes']['api'];
if (file_exists($file)) {
$routeLoader = require $file;
if (is_callable($routeLoader) && $app) {
$routeLoader($app);
}
}
}
}
/**
* Registers views and translations
*/
protected function registerResources(string $module, string $path, array $config): void
{
// Views
if (isset($config['views'])) {
$viewsPath = $path . '/' . $config['views'];
if (is_dir($viewsPath)) {
View::addPath($module, $viewsPath);
}
}
// Locales
if (isset($config['locales'])) {
$localesPath = $path . '/' . $config['locales'];
if (is_dir($localesPath)) {
Translator::addNamespace($module, $localesPath);
}
}
}
/**
* Returns the list of loaded modules
*/
public function getModules(): array
{
return $this->modules;
}
}