fibable/lib/ArticleParser.php

123 lines
4.2 KiB
PHP

<?php
final class ArticleParser
{
const PATTERN_DATE = "|\./data/articles/([0-9]+)/([0-9]+)/([0-9]+)/([0-9]+).txt|";
const PATTERN_TAGS = "/^\{(([a-zA-Z0-9]+,*)+)\}$/";
const PATTERN_IMG = "/^([a-zA-Z0-9\-_\.]+\.(jpg|png)) \((.*)\)$/";
const PATTERN_BOLD = "/\*([^*]*)\*/";
const PATTERN_ITALIC = "|/([^/]*)/|";
const PATTERN_UNDERLINE = "/_([^_]*)_/";
const REPLACE_DATE = "$1-$2-$3";
const REPLACE_REF = "$4";
const REPLACE_BOLD = "<strong>$1</strong>";
const REPLACE_ITALIC = "<em>$1</em>";
const REPLACE_UNDERLINE = "<u>$1</u>";
private bool $in_p = false;
private array $content = [];
private array $p = [];
public function parse(string $file_path): Article
{
$article = new Article();
$article->date = preg_replace(self::PATTERN_DATE, self::REPLACE_DATE, $file_path);
$article->ref = preg_replace(self::PATTERN_DATE, self::REPLACE_REF, $file_path);
$lines = file($file_path, FILE_IGNORE_NEW_LINES);
foreach ($lines as $line) {
if (substr($line, 0, 2) === "# ") {
$article->title = substr($line, 2);
continue;
}
if (substr($line, 0, 3) === "## ") {
$this->closeParagraph();
$this->content[] = "<h3>" . substr($line, 3) . "</h3>";
continue;
}
if (substr($line, 0, 4) === "### ") {
$this->closeParagraph();
$this->content[] = "<h4>" . substr($line, 4) . "</h4>";
continue;
}
if (substr($line, 0, 5) === "#### ") {
$this->closeParagraph();
$this->content[] = "<h5>" . substr($line, 5) . "</h5>";
continue;
}
if (preg_match(self::PATTERN_TAGS, $line, $matches)) {
$article->tags = explode(",", $matches[1]);
continue;
}
if (preg_match(self::PATTERN_IMG, $line, $matches)) {
$this->closeParagraph();
$this->content[] = "<figure>";
$this->content[] = " <img src=\"" . dirname($file_path) . "/$matches[1]\" alt=\"$matches[3]\">";
$this->content[] = " <figcaption>$matches[3]</figcaption>";
$this->content[] = "</figure>";
continue;
}
if ($line === "") {
$this->closeParagraph();
continue;
} else {
if (!$this->in_p) {
$this->content[] = "<p>";
$this->in_p = true;
}
$this->p[] = $this->parseLine($line);
}
}
$this->closeParagraph();
array_unshift($this->content,
"<header>",
" <h2>" . $article->title . "</h2>",
" <nav>" . $this->getHtmlTags($article->tags) . "</nav>",
"</header>"
);
$this->content[] = "<footer>" .
preg_replace("/([0-9]+)\-([0-9]+)-([0-9]+)/", "$3/$2/$1", $article->date) .
"</footer>";
$view_path = "./data/cache/{$article->date}_{$article->ref}.phtml";
file_put_contents($view_path, " " . implode("\n ", $this->content) . "\n");
$article->view = $view_path;
$this->content = [];
return $article;
}
private function closeParagraph()
{
if ($this->in_p) {
$this->content[] = " " . implode("<br>", $this->p);
$this->content[] = "</p>";
$this->in_p = false;
$this->p = [];
}
}
private function parseLine(string $line): string
{
$patterns = [
self::PATTERN_BOLD,
self::PATTERN_ITALIC,
self::PATTERN_UNDERLINE
];
$replacements = [
self::REPLACE_BOLD,
self::REPLACE_ITALIC,
self::REPLACE_UNDERLINE
];
return preg_replace($patterns, $replacements, htmlspecialchars($line, ENT_HTML5, UTF-8));
}
private function getHtmlTags(array $tags): string
{
$html = "";
foreach ($tags as $tag) {
$html .= "<a href=\"?view=tags&tag=$tag\" class=\"tag\">$tag</a>";
}
return $html;
}
}