247 lines
6.6 KiB
PHP
247 lines
6.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
class Autoloader
|
|
{
|
|
private const PATH_CLASSES = 'backend/classes';
|
|
private const PATH_CONTROLLERS = self::PATH_CLASSES . '/controller';
|
|
private const PATH_CACHE = 'backend/cache/';
|
|
|
|
public function __construct(string $cachePath = self::PATH_CACHE)
|
|
{
|
|
if ($cachePath !== self::PATH_CACHE) {
|
|
$cachePath = substr($cachePath, -1) === '/' ? $cachePath : $cachePath . '/';
|
|
}
|
|
|
|
$routesFound = @include($cachePath . 'routes.php');
|
|
$classesFound = @include($cachePath . 'classes.php');
|
|
|
|
if (!$routesFound || !$classesFound) {
|
|
throw new Exception(
|
|
sprintf(
|
|
'Autoloader cache not found! Please generate it with %s::BuildCache() at first!',
|
|
self::class
|
|
)
|
|
);
|
|
}
|
|
|
|
spl_autoload_register(
|
|
function (string $className) {
|
|
if (!$this->loadClass($className)) {
|
|
throw new Exception(sprintf('Class %s couldn\'t be loaded!', $className));
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
public static function BuildCache(): void
|
|
{
|
|
self::BuildClassCache();
|
|
self::BuildRouteCache();
|
|
}
|
|
|
|
public static function BuildClassCache(): void
|
|
{
|
|
$classesResult = self::scanForClasses();
|
|
|
|
$cacheContent = '';
|
|
|
|
foreach ($classesResult as $className => $path) {
|
|
$cacheContent .= sprintf("\t\t'%s' => '%s',\n", $className, $path);
|
|
}
|
|
|
|
$cacheContent .= "\t]\n);";
|
|
|
|
self::buildCacheFile($cacheContent, 'classes');
|
|
}
|
|
|
|
private function loadClass(string $className): bool
|
|
{
|
|
if (!isset(CLASSES[$className]) || !@include(CLASSES[$className])) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static function BuildRouteCache(): void
|
|
{
|
|
$controllersResult = self::scanForControllers();
|
|
$controllerMethods = [
|
|
'GET' => [],
|
|
'POST' => [],
|
|
'PUT' => [],
|
|
'DELETE' => [],
|
|
];
|
|
|
|
foreach ($controllersResult as $className => $path) {
|
|
$file = fopen($path, 'r');
|
|
$content = fread($file, filesize($path));
|
|
fclose($file);
|
|
|
|
preg_match_all('/(?<=private )\w+ \$\w+(?=;)/', $content, $matches);
|
|
|
|
$params = [];
|
|
|
|
foreach ($matches[0] as $match) {
|
|
$parts = explode(' ', $match);
|
|
$params[] = [
|
|
'type' => $parts[0],
|
|
'name' => $parts[1],
|
|
];
|
|
}
|
|
|
|
preg_match('/(?<=protected string \$route = \').*(?=\';)/', $content, $matches);
|
|
$route = $matches[0];
|
|
|
|
preg_match('/[A-Z][a-z]+(?=Controller)/', $className, $matches);
|
|
$method = strtoupper($matches[0]);
|
|
|
|
$controllerMethods[$method][$route] = [
|
|
'name' => $className,
|
|
'params' => $params,
|
|
];
|
|
}
|
|
|
|
$cacheContent = '';
|
|
|
|
foreach ($controllerMethods as $method => $controllers) {
|
|
$cacheContent .= self::createRoutesForMethod($method, $controllers);
|
|
}
|
|
|
|
$cacheContent .= "\t]\n);";
|
|
|
|
self::buildCacheFile($cacheContent, 'routes');
|
|
}
|
|
|
|
private static function createRoutesForMethod(string $method, array $routes): string
|
|
{
|
|
krsort($routes);
|
|
$stringRoutes = '';
|
|
|
|
foreach ($routes as $route => $params) {
|
|
$stringRoutes .= sprintf(
|
|
"'%s' => [
|
|
'controller' => %s::class,
|
|
'params' => [
|
|
%s
|
|
],
|
|
],
|
|
",
|
|
$route,
|
|
$params['name'],
|
|
self::createRouteParams($params['params'])
|
|
);
|
|
}
|
|
|
|
return sprintf(
|
|
"
|
|
'%s' => [
|
|
%s
|
|
],
|
|
",
|
|
$method,
|
|
$stringRoutes,
|
|
);
|
|
}
|
|
|
|
private static function createRouteParams(array $params): string
|
|
{
|
|
$string = '';
|
|
|
|
foreach ($params as $param) {
|
|
$string .= sprintf(
|
|
"
|
|
'%s' => [
|
|
'type' => '%s',
|
|
],
|
|
",
|
|
str_replace('$', '', $param['name']),
|
|
$param['type']
|
|
);
|
|
}
|
|
|
|
return $string;
|
|
}
|
|
|
|
private static function reformatCacheFileContent(string $content): string
|
|
{
|
|
$depth = 0;
|
|
$reformatted = '';
|
|
$replace = '';
|
|
|
|
// Removing indents
|
|
foreach (explode("\n", $content) as $line) {
|
|
$trim = trim($line);
|
|
|
|
if ($trim !== '') {
|
|
$replace .= $trim . "\n";
|
|
}
|
|
}
|
|
|
|
for ($i = 0; $i < strlen($replace); $i++) {
|
|
if (in_array($replace[$i], [')', ']'])) {
|
|
$depth--;
|
|
}
|
|
|
|
if ($replace[$i - 1] === "\n") {
|
|
$reformatted .= str_repeat("\t", $depth);
|
|
}
|
|
|
|
$reformatted .= $replace[$i];
|
|
|
|
if (in_array($replace[$i], ['(', '['])) {
|
|
$depth++;
|
|
}
|
|
}
|
|
|
|
return $reformatted;
|
|
}
|
|
|
|
private static function buildCacheFile(string $content, string $cacheName): void
|
|
{
|
|
$cacheContent = sprintf(
|
|
"<?php\n\n/*\n * This file was auto generated on %s\n */\n\ndefine(\n\t'%s',\n\t[\n",
|
|
(new DateTime())->format('Y-m-d H:i:s'),
|
|
strtoupper($cacheName)
|
|
);
|
|
|
|
$cacheContent .= $content;
|
|
|
|
$file = fopen(getcwd() . '/' . self::PATH_CACHE . $cacheName . '.php', 'w');
|
|
fwrite($file, self::reformatCacheFileContent($cacheContent));
|
|
fclose($file);
|
|
}
|
|
|
|
private static function scanForFiles(string $folder): array
|
|
{
|
|
$folder = substr($folder, -1) === '/' ? substr($folder, 0, -1) : $folder;
|
|
$files = [];
|
|
$handler = opendir($folder);
|
|
|
|
while ($file = readdir($handler)) {
|
|
$path = $folder . '/' . $file;
|
|
|
|
if (is_dir($path) && $file !== '.' && $file !== '..') {
|
|
$files = array_merge($files, self::scanForFiles($path));
|
|
} elseif (is_file($path) && substr($path, -4) === '.php') {
|
|
$className = substr($file, 0, -4);
|
|
$files[$className] = $path;
|
|
}
|
|
}
|
|
|
|
return $files;
|
|
}
|
|
|
|
private static function scanForClasses(): array
|
|
{
|
|
return self::scanForFiles(getcwd() . '/' . self::PATH_CLASSES);
|
|
}
|
|
|
|
private static function scanForControllers(): array
|
|
{
|
|
return self::scanForFiles(getcwd() . '/' . self::PATH_CONTROLLERS);
|
|
}
|
|
}
|