adrianbaez/markdown-bundle
Symfony 4 bundle that adds a Markdown parsing service and Twig filter. Uses Parsedown by default but can be configured to use any Markdown library, making it easy to render Markdown content in templates and services.
Installation
composer require adrianbaez/markdown-bundle
Add to config/bundles.php (Symfony 4+ auto-discovers, but explicit inclusion ensures clarity):
return [
// ...
Adrianbaez\MarkdownBundle\MarkdownBundle::class => ['all' => true],
];
First Use Case
Inject the MarkdownParser service into a controller or Twig template:
// In a controller
use Adrianbaez\MarkdownBundle\Parser\MarkdownParserInterface;
public function showMarkdown(MarkdownParserInterface $parser) {
$markdown = "# Hello, **Markdown**!";
$html = $parser->parse($markdown);
return new Response($html);
}
Or in Twig:
{{ markdown_content|markdown }}
Key Files to Review
config/packages/adrianbaez_markdown.yaml (default config)src/Resources/doc/index.md (documentation)src/Parser/MarkdownParserInterface.php (core interface)Parsing Markdown in Controllers
public function renderBlogPost(MarkdownParserInterface $parser, string $markdownContent) {
$html = $parser->parse($markdownContent);
return $this->render('post/show.html.twig', ['content' => $html]);
}
Twig Integration
markdown filter for inline parsing:
{{ post.content|markdown }}
markdown_block function for dedicated blocks:
{% markdown_block post.content %}
Custom Markdown Libraries
Override the default Parsedown by configuring a custom parser:
# config/packages/adrianbaez_markdown.yaml
adrianbaez_markdown:
parser: App\Custom\MarkdownParser
Caching Parsed Output Extend the parser to cache results (e.g., using Symfony Cache component):
class CachedMarkdownParser implements MarkdownParserInterface {
private $decorated;
private $cache;
public function __construct(MarkdownParserInterface $parser, CacheInterface $cache) {
$this->decorated = $parser;
$this->cache = $cache;
}
public function parse(string $markdown): string {
$cacheKey = md5($markdown);
return $this->cache->get($cacheKey, function() use ($markdown) {
return $this->decorated->parse($markdown);
});
}
}
Dynamic Markdown Sources Fetch Markdown from APIs or databases:
public function getMarkdownFromApi(MarkdownParserInterface $parser, string $apiUrl) {
$markdown = file_get_contents($apiUrl);
return $parser->parse($markdown);
}
Deprecated Symfony Version
Parsedown Limitations
Parsedown lacks support for tables, definition lists, or footnotes. Extend it or switch to League\CommonMark:
adrianbaez_markdown:
parser: League\CommonMark\MarkdownConverter
Twig Filter Scope
markdown filter is global by default. Override it in a custom Twig extension if you need per-environment behavior:
class CustomTwigExtension extends \Twig\Extension\AbstractExtension {
public function getFilters() {
return [
new \Twig\TwigFilter('markdown', [$this->parser, 'parse'], ['is_safe' => ['html']]),
];
}
}
HTML Sanitization
use Symfony\Component\DomCrawler\Crawler;
$cleanHtml = (new Crawler($html))->html();
Configuration Overrides
Parsedown options via config. Override the parser class directly:
services:
adrianbaez_markdown.parser:
class: ParsedownExtra\ParsedownExtra
arguments: ['--extra']
Check Parser Output Log raw Markdown and parsed HTML to debug issues:
file_put_contents(
'debug/markdown.log',
"Markdown: {$markdown}\nHTML: {$html}\n\n",
FILE_APPEND
);
Verify Autowiring
Ensure the MarkdownParserInterface is correctly autowired. If not, explicitly bind it:
services:
Adrianbaez\MarkdownBundle\Parser\MarkdownParserInterface: '@adrianbaez_markdown.parser'
Twig Filter Testing
Test Twig filters in isolation using twig:render:
php bin/console twig:render --env=dev --debug blog/post.html.twig
Custom Parsers
Implement MarkdownParserInterface for full control:
class MyMarkdownParser implements MarkdownParserInterface {
public function parse(string $markdown): string {
// Custom logic (e.g., pre-process Markdown)
return (new Parsedown)->text($markdown);
}
}
Post-Processing Hooks Decorate the parser to add logic after parsing:
class AnalyticsMarkdownParser implements MarkdownParserInterface {
private $parser;
public function __construct(MarkdownParserInterface $parser) {
$this->parser = $parser;
}
public function parse(string $markdown): string {
$html = $this->parser->parse($markdown);
// Inject analytics scripts
return str_replace('</body>', '<script>...</script></body>', $html);
}
}
Markdown Syntax Highlighting
Combine with a library like Fidry\AliceDataBundle to generate Markdown with syntax highlighting:
{% markdown_block post.code_with_highlighting %}
```php
<?php
echo "Hello, world!";
{% endmarkdown_block %}
How can I help you explore Laravel packages today?