123 lines
4 KiB
PHP
123 lines
4 KiB
PHP
|
<?php
|
||
|
namespace Misuzu\Info;
|
||
|
|
||
|
use Index\Routing\IRouter;
|
||
|
use Misuzu\Template;
|
||
|
use Misuzu\Parsers\Parser;
|
||
|
|
||
|
class InfoRoutes {
|
||
|
private const DOCS_PATH = MSZ_ROOT . '/docs';
|
||
|
private const PROJECT_PATHS = [
|
||
|
'misuzu' => MSZ_ROOT,
|
||
|
'index' => MSZ_ROOT . '/vendor/flashwave/index',
|
||
|
];
|
||
|
private const PROJECT_SUFFIXES = [
|
||
|
'misuzu' => 'Misuzu Project » %s',
|
||
|
'index' => 'Index Project » %s',
|
||
|
];
|
||
|
|
||
|
public function __construct(IRouter $router) {
|
||
|
$router->get('/info', [$this, 'getIndex']);
|
||
|
$router->get('/info/:name', [$this, 'getDocsPage']);
|
||
|
$router->get('/info/:project/:name', [$this, 'getProjectPage']);
|
||
|
|
||
|
$router->get('/info.php', function($response) {
|
||
|
$response->redirect(url('info'), true);
|
||
|
});
|
||
|
$router->get('/info.php/:name', function($response, $request, string $name) {
|
||
|
$response->redirect(url('info', ['title' => $name]), true);
|
||
|
});
|
||
|
$router->get('/info.php/:project/:name', function($response, $request, string $project, string $name) {
|
||
|
$response->redirect(url('info', ['title' => $project . '/' . $name]), true);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
private static function checkName(string $name): bool {
|
||
|
return preg_match('#^([A-Za-z0-9_]+)$#', $name) === 1;
|
||
|
}
|
||
|
|
||
|
public function getIndex() {
|
||
|
return Template::renderRaw('info.index');
|
||
|
}
|
||
|
|
||
|
public function getDocsPage($response, $request, string $name) {
|
||
|
if(!self::checkName($name))
|
||
|
return 404;
|
||
|
|
||
|
return $this->serveMarkdownDocument(
|
||
|
sprintf('%s/%s.md', self::DOCS_PATH, $name)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public function getProjectPage($response, $request, string $project, string $name) {
|
||
|
if(!array_key_exists($project, self::PROJECT_PATHS))
|
||
|
return 404;
|
||
|
if(!self::checkName($name))
|
||
|
return 404;
|
||
|
|
||
|
$projectPath = self::PROJECT_PATHS[$project];
|
||
|
$titleSuffix = array_key_exists($project, self::PROJECT_SUFFIXES) ? self::PROJECT_SUFFIXES[$project] : '';
|
||
|
|
||
|
$attempts = 0;
|
||
|
$licenceHack = false;
|
||
|
for(;;) {
|
||
|
$path = match(++$attempts) {
|
||
|
1 => sprintf('%s/%s', $projectPath, $name),
|
||
|
2 => sprintf('%s/%s.md', $projectPath, $name),
|
||
|
3 => sprintf('%s/%s', $projectPath, strtoupper($name)),
|
||
|
4 => sprintf('%s/%s.md', $projectPath, strtoupper($name)),
|
||
|
5 => sprintf('%s/%s', $projectPath, strtolower($name)),
|
||
|
6 => sprintf('%s/%s.md', $projectPath, strtolower($name)),
|
||
|
default => '',
|
||
|
};
|
||
|
|
||
|
if($path === '') {
|
||
|
if(!$licenceHack) {
|
||
|
$isBritish = strtolower($name) === 'licence';
|
||
|
$isAmerican = strtolower($name) === 'license';
|
||
|
|
||
|
if($isBritish || $isAmerican) {
|
||
|
$attempts = 0;
|
||
|
$licenceHack = true;
|
||
|
$name = $isAmerican ? 'licence' : 'license';
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 404;
|
||
|
}
|
||
|
|
||
|
if(is_file($path))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return $this->serveMarkdownDocument($path, $titleSuffix);
|
||
|
}
|
||
|
|
||
|
private function serveMarkdownDocument(string $path, string $titleFormat = '') {
|
||
|
if(!is_file($path))
|
||
|
return 404;
|
||
|
|
||
|
$body = file_get_contents($path);
|
||
|
|
||
|
if(str_starts_with($body, '#')) {
|
||
|
$offset = strpos($body, "\n");
|
||
|
$title = trim(substr($body, 1, $offset));
|
||
|
$body = substr($body, $offset);
|
||
|
} else
|
||
|
$title = ucfirst(basename($path));
|
||
|
|
||
|
if($titleFormat !== '')
|
||
|
$title = sprintf($titleFormat, $title);
|
||
|
|
||
|
$body = Parser::instance(Parser::MARKDOWN)->parseText($body);
|
||
|
|
||
|
return Template::renderRaw('info.view', [
|
||
|
'document' => [
|
||
|
'title' => $title,
|
||
|
'content' => $body,
|
||
|
],
|
||
|
]);
|
||
|
}
|
||
|
}
|