You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

297 lines
8.4 KiB
PHP

<?php
namespace Eater;
use DateTime;
use League\CommonMark\CommonMarkConverter;
use Slim\Factory\AppFactory;
use Slim\Psr7\Request;
use Slim\Psr7\Response;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Yosymfony\Toml\Toml;
class Blog
{
private $app;
private $twig;
private $debug = false;
private $posts = [];
private $tags = [];
private $pages = [];
private $config = [];
private $games = [];
public function __construct()
{
$this->app = AppFactory::create();
$this->twig = new Environment(
new FilesystemLoader([__DIR__."/../views"]), [
'cache' => __DIR__."/../var/cache/twig",
'debug' => $this->debug,
]
);
$this->routes();
$this->makeListing();
}
public function run()
{
$this->app->run();
}
public function routes()
{
$app = $this->app;
$app->get(
'/',
function (Request $request, Response $response, $args) {
$response->getBody()->write(
$this->twig->render(
"main.html.twig",
$this->context()
)
);
return $response;
}
);
$app->get(
'/tag/{tag}',
function (Request $request, Response $response, $args) {
$tag = $args['tag'];
$posts = array_filter(
$this->posts,
function ($post) use ($tag) {
return in_array($tag, $post['meta']['tags'] ?: []);
}
);
$response->getBody()->write(
$this->twig->render(
"tag.html.twig",
$this->context(
[
'tag' => $tag,
'posts' => $posts,
]
)
)
);
return $response;
}
);
$app->get(
'/game/{game}',
function (Request $request, Response $response, $args) {
$game = $this->games[$args['game']] ?? false;
if ( ! $game) {
return $response->withStatus(404);
}
$posts = array_filter(
$this->posts,
function ($post) use ($game) {
return in_array($game['slug'], $post['meta']['games'] ?: []);
}
);
$response->getBody()->write(
$this->twig->render(
"game.html.twig",
$this->context(
[
'posts' => $posts,
'game' => $game,
'game_body' => $this->parseMarkdown($game['markdown']),
]
)
)
);
return $response;
}
);
$app->get(
'/post/{post}',
function (Request $request, Response $response, $args) {
$post = $this->posts[$args['post']] ?? false;
if ( ! $post) {
return $response->withStatus(404);
}
$response->getBody()->write(
$this->twig->render(
"post.html.twig",
$this->context(
[
'post' => $post,
'post_body' => $this->parseMarkdown($post['markdown']),
]
)
)
);
return $response;
}
);
$app->get(
'/rss.xml',
function (Request $request, Response $response) {
$response->getBody()->write(
$this->twig->render(
"rss.xml.twig",
$this->context()
)
);
return $response->withHeader("Content-Type", "application/rss+xml");
}
);
$app->get(
'/games',
function (Request $request, Response $response) {
$response->getBody()->write(
$this->twig->render(
"games.html.twig",
$this->context()
)
);
return $response;
}
);
$app->get(
'/{page}',
function (Request $request, Response $response, $args) {
$page = $this->pages[$args['page']] ?? false;
if ( ! $page) {
return $response->withStatus(404);
}
$response->getBody()->write(
$this->twig->render(
"page.html.twig",
$this->context(
[
'page' => $page,
'page_body' => $this->parseMarkdown($page['markdown']),
]
)
)
);
return $response;
}
);
}
private function context($context = [])
{
return array_merge(
[
'pages' => $this->pages,
'posts' => $this->posts,
'config' => $this->config,
'games' => $this->games,
'tags' => $this->tags,
],
$context
);
}
private function parseObjects($path, $registerTags = false)
{
$objectBase = realpath($path);
$objects = glob($objectBase."/*.md");
$objectsColl = [];
foreach ($objects as $object) {
$objectSource = file_get_contents($object);
$parts = explode('---', $objectSource, 2);
if (count($parts) !== 2) {
continue;
}
$meta = Toml::parse($parts[0]);
$md = $parts[1];
$slug = ltrim(substr($object, strlen($objectBase)), '/');
$objectsColl[$slug] = [
"markdown" => $md,
"meta" => $meta,
"slug" => $slug,
];
if ($registerTags) {
$this->tags = array_merge($meta['tags'] ?: [], $this->tags);
}
}
return $objectsColl;
}
private function makeListing()
{
$cacheFile = __DIR__."/../var/cache/listing.json";
if (file_exists($cacheFile) && ! $this->debug) {
$data = json_decode(file_get_contents($cacheFile), true);
$this->posts = $data['posts'];
$this->pages = $data['pages'];
$this->tags = $data['tags'];
$this->config = $data['config'];
$this->games = $data['games'];
foreach ($this->posts as &$post) {
if (isset($post['meta']['date'])) {
$post['meta']['date'] = new DateTime($post['meta']['date']['date']);
}
}
return;
}
$this->posts = $this->parseObjects(__DIR__."/../data/posts", true);
$this->pages = $this->parseObjects(__DIR__."/../data/pages");
$this->games = $this->parseObjects(__DIR__."/../data/games");
$this->config = Toml::parse(file_get_contents(__DIR__."/../data/config.toml"));
$this->tags = array_unique($this->tags);
$cacheDir = __DIR__."/../var/cache/";
if ( ! is_dir($cacheDir)) {
mkdir($cacheDir, 0777, true);
}
file_put_contents(
__DIR__."/../var/cache/listing.json",
json_encode(
[
"pages" => $this->pages,
"posts" => $this->posts,
"tags" => $this->tags,
"games" => $this->games,
"config" => $this->config,
]
)
);
}
private function parseMarkdown($markdown)
{
$converter = new CommonMarkConverter();
return $converter->convertToHtml($markdown);
}
}