-
Notifications
You must be signed in to change notification settings - Fork 0
Rendering Markdown
In this tutorial you'll learn how to set up an async Markdown rendering service and pair it up with a simple Empress app.
Apart from a working Empress setup we'll need commonmark.
$ composer require empress-php/empress league/commonmarkWe'll use the code layout shown below. We'll go through every file in the following sections.
bin/
├─ app.php
Controller/
├─ HelloMarkdownController.php
Markdown/
├─ MarkdownRenderer.php
Resources/
├─ hello_markdown.md
Empress doesn't have any kind of builtin support for template renderers or in fact any renderers for that matter. This doesn't mean you can't use them. The implemention though is left for the user to take care of. We'll create a simple class that will allow us to open files and convert their contents to Markdown.
<?php
// Markdown/MarkdownRenderer.php
namespace Empress\Example\Markdown;
use Amp\File\File;
use Amp\Promise;
use League\CommonMark\MarkdownConverterInterface;
use function Amp\ByteStream\buffer;
use function Amp\call;
use function Amp\File\open;
class MarkdownRenderer
{
public function __construct(private MarkdownConverterInterface $converter)
{
}
/**
* @return Promise<string>
*/
public function render(string $fileName): Promise
{
return call(function () use ($fileName) {
/** @var File $file */
$file = yield open($fileName, 'rb');
$contents = yield buffer($file);
return $this->converter->convertToHtml($contents);
});
}
}Next we'll create a controller where we'll be able to use it:
<?php
// Controller/HelloMarkdownController.php
namespace Empress\Example\Controller;
use Empress\Context;
use Empress\Example\Markdown\MarkdownRenderer;
use Empress\Routing\RouteCollector\AnnotatedRouteCollectorTrait;
use Empress\Routing\RouteCollector\Attribute\Route;
class HelloMarkdownController
{
use AnnotatedRouteCollectorTrait;
public function __construct(private MarkdownRenderer $renderer)
{
}
#[Route('GET', '/hello-markdown')]
public function index(Context $ctx)
{
$ctx->html(yield $this->renderer->render(__DIR__ . '/../Resources/hello_markdown.md'));
}
}Our markdown file (Resources/hello_markdown.md):
# Hello World
# This is an h1 tag
## This is an h2 tag
###### This is an h6 tag
*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__
_You **can** combine them_
* Item 1
* Item 2
* Item 2a
* Item 2b
1. Item 1
1. Item 2
1. Item 3
1. Item 3a
1. Item 3bIn our bootstrap file we'll glue all of the pieces together:
// bin/app.php
<?php
use Amp\Loop;
use Empress\Application;
use Empress\Empress;
use Empress\Example\Controller\HelloMarkdownController;
use Empress\Example\Markdown\MarkdownRenderer;
use League\CommonMark\CommonMarkConverter;
require_once __DIR__ . '/../vendor/autoload.php';
$app = Application::create(9000);
$converter = new CommonMarkConverter();
$renderer = new MarkdownRenderer($converter);
$app->routes(new HelloMarkdownController($renderer));
return $app;Run the app with vendor/bin/empress bin/app.php and open http://localhost:9000/hello-markdown in your browser. You'll see a page that looks like this:
Our renderer has one obvious flaw - it doesn't cache the parsed contents. In practice, you'd like to cache data e.g. based on file path. Also, you might want to provide another component that will take care of matching file paths to template names.
