add new guide service
This commit is contained in:
109
src/Controller/Admin/GuideController.php
Normal file
109
src/Controller/Admin/GuideController.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Service\MarkdownRenderer;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
|
||||
#[Route('/admin/guides')]
|
||||
final class GuideController extends AbstractController
|
||||
{
|
||||
private string $guidePath;
|
||||
|
||||
public function __construct(ParameterBagInterface $params)
|
||||
{
|
||||
$this->guidePath = rtrim(
|
||||
$params->get('kernel.project_dir'),
|
||||
'/'
|
||||
);
|
||||
}
|
||||
|
||||
#[Route('', name: 'admin_guides_index')]
|
||||
public function index(): Response
|
||||
{
|
||||
if (!is_dir($this->guidePath)) {
|
||||
return $this->render('admin/guides/index.html.twig', [
|
||||
'guides' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
$files = glob($this->guidePath . '/*.md') ?: [];
|
||||
|
||||
$guides = [];
|
||||
|
||||
foreach ($files as $file) {
|
||||
$slug = basename($file, '.md');
|
||||
|
||||
if (!$this->isValidSlug($slug)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = file_get_contents($file) ?: '';
|
||||
|
||||
$title = $this->extractTitleFromMarkdown($content)
|
||||
?? $this->humanizeSlug($slug);
|
||||
|
||||
$guides[] = [
|
||||
'slug' => $slug,
|
||||
'title' => $title,
|
||||
];
|
||||
}
|
||||
|
||||
usort($guides, fn ($a, $b) => strcasecmp($a['title'], $b['title']));
|
||||
|
||||
return $this->render('admin/guides/index.html.twig', [
|
||||
'guides' => $guides,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/{slug}', name: 'admin_guides_view')]
|
||||
public function view(string $slug, MarkdownRenderer $renderer): Response
|
||||
{
|
||||
if (!$this->isValidSlug($slug)) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
$file = $this->guidePath . '/' . $slug . '.md';
|
||||
|
||||
if (!is_file($file)) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
$content = file_get_contents($file) ?: '';
|
||||
|
||||
return $this->render('admin/guides/view.html.twig', [
|
||||
'slug' => $slug,
|
||||
'title' => $this->extractTitleFromMarkdown($content)
|
||||
?? $this->humanizeSlug($slug),
|
||||
'html' => $renderer->render($content),
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Helper
|
||||
// =========================================================
|
||||
|
||||
private function extractTitleFromMarkdown(string $content): ?string
|
||||
{
|
||||
if (preg_match('/^#\s+(.+)$/m', $content, $matches)) {
|
||||
return trim($matches[1]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function humanizeSlug(string $slug): string
|
||||
{
|
||||
return ucfirst(str_replace('-', ' ', $slug));
|
||||
}
|
||||
|
||||
private function isValidSlug(string $slug): bool
|
||||
{
|
||||
return (bool) preg_match('/^[a-zA-Z0-9\-_]+$/', $slug);
|
||||
}
|
||||
}
|
||||
38
src/Service/MarkdownRenderer.php
Normal file
38
src/Service/MarkdownRenderer.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use League\CommonMark\MarkdownConverter;
|
||||
use League\CommonMark\Environment\Environment;
|
||||
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
|
||||
use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
|
||||
|
||||
final class MarkdownRenderer
|
||||
{
|
||||
private MarkdownConverter $converter;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$config = [
|
||||
'html_input' => 'strip',
|
||||
'allow_unsafe_links' => false,
|
||||
];
|
||||
|
||||
$environment = new Environment($config);
|
||||
|
||||
// Core Markdown
|
||||
$environment->addExtension(new CommonMarkCoreExtension());
|
||||
|
||||
// GitHub Flavored Markdown (Tables, Strikethrough, Autolinks, Task Lists)
|
||||
$environment->addExtension(new GithubFlavoredMarkdownExtension());
|
||||
|
||||
$this->converter = new MarkdownConverter($environment);
|
||||
}
|
||||
|
||||
public function render(string $markdown): string
|
||||
{
|
||||
return (string) $this->converter->convert($markdown);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user