Installation:
composer require mnapoli/front-yaml
Add to composer.json if using Laravel’s autoloader:
"autoload": {
"psr-4": {
"App\\": "app/",
"Mni\\FrontYAML\\": "vendor/mnapoli/front-yaml/src/"
}
}
Run composer dump-autoload.
First Use Case:
Parse a Markdown file with front matter (e.g., resources/markdown/blog-post.md):
use Mni\FrontYAML\Parser;
$parser = new Parser();
$document = $parser->parse(file_get_contents('blog-post.md'));
$metadata = $document->getYAML(); // Array of front matter
$content = $document->getContent(); // Parsed HTML
Where to Look First:
vendor/mnapoli/front-yaml/src/Parser.php for core logic.YAMLParser and MarkdownParser in vendor/mnapoli/front-yaml/src/ for customization.vendor/mnapoli/front-yaml/src/Bridge/ for parser integrations (e.g., CommonMarkParser).Parsing Markdown Files:
AppServiceProvider to pre-process Markdown files (e.g., for a CMS or blog):
public function boot()
{
$parser = new Parser();
$posts = collect(storage_path('app/markdown/posts/*.md'))
->map(fn ($path) => $parser->parse(file_get_contents($path)))
->mapWithKeys(fn ($doc) => [$doc->getYAML()['slug'] => $doc->getContent()]);
}
Custom Parsers:
spatie/array-to-xml for XML output:
use Mni\FrontYAML\YAMLParser;
use Spatie\ArrayToXml\ArrayToXml;
$yamlParser = new class implements YAMLParser {
public function parse($yaml) {
return (new ArrayToXml)->convert(['data' => yaml_parse($yaml)]);
}
};
$parser = new Parser($yamlParser);
Markdown Processing:
$document = $parser->parse($content, false); // Returns raw Markdown
Service Container Integration:
AppServiceProvider:
$this->app->singleton(Parser::class, fn () => new Parser());
public function __construct(private Parser $parser) {}
File System Integration:
storage/app/markdown/ dynamically:
$files = Storage::files('markdown');
$documents = collect($files)->map(fn ($file) =>
$this->parser->parse(Storage::get($file))
);
Laravel Blade Directives: Create a custom Blade directive to parse front matter in views:
Blade::directive('frontmatter', function ($expression) {
$parser = app(Parser::class);
$content = $parser->parse($expression);
return "<?php echo \$content->getContent(); ?>";
});
Usage in Blade:
@frontmatter($markdownContent)
API Responses: Serve parsed content as JSON:
return response()->json([
'metadata' => $document->getYAML(),
'content' => $document->getContent(),
]);
Validation:
Validate front matter using Laravel’s Validator:
$validator = Validator::make($document->getYAML(), [
'title' => 'required|string|max:255',
'author' => 'required|string',
]);
Caching: Cache parsed documents to avoid reprocessing:
$cacheKey = 'frontmatter_'.md5($content);
$document = Cache::remember($cacheKey, now()->addHours(1), fn () =>
$parser->parse($content)
);
Testing:
Use Mockery to test custom parsers:
$mockYamlParser = Mockery::mock(YAMLParser::class);
$mockYamlParser->shouldReceive('parse')->andReturn(['key' => 'value']);
$parser = new Parser($mockYamlParser);
Line Endings:
\r\n) vs. Unix (\n) line endings may cause parsing failures. Normalize input:
$content = str_replace(["\r\n", "\r"], "\n", $content);
Empty Front Matter:
--- (no content) may throw errors. Validate:
if (empty(trim($content))) {
throw new \InvalidArgumentException('Empty content provided.');
}
Markdown Parsing Quirks:
CommonMarkParser with custom extensions:
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Environment;
$env = new Environment();
$env->addExtension(new CommonMarkCoreExtension());
$parser = new \Mni\FrontYAML\Bridge\CommonMark\CommonMarkParser($env);
YAML Syntax Errors:
try {
$yaml = $parser->parse($content)->getYAML();
} catch (\Symfony\Component\Yaml\Exception\ParseException $e) {
report($e);
$yaml = [];
}
Performance:
$document = Cache::rememberForever("frontmatter_{$fileHash}", fn () =>
$parser->parse($content)
);
Log Raw Input:
\Log::debug('Front matter input:', ['content' => $content]);
Inspect Parsed Output:
\Log::debug('Parsed YAML:', $document->getYAML());
\Log::debug('Parsed HTML:', $document->getContent());
Custom Error Handling:
Parser class to add custom error handling:
class CustomParser extends Parser {
public function parse($content, $parseMarkdown = true) {
try {
return parent::parse($content, $parseMarkdown);
} catch (\Exception $e) {
\Log::error("FrontYAML parse error: {$e->getMessage()}");
throw new \RuntimeException('Failed to parse front matter.', 0, $e);
}
}
}
Custom Separators:
--- separator (e.g., for HTML comments):
$parser = new Parser(null, null, ['separator' => '<!--', 'separatorClosing' => '-->']);
Post-Processing:
$document = $parser->parse($content);
$content = Str::of($document->getContent())->replace('old', 'new');
Event Dispatching:
event(new FrontMatterParsed($document->getYAML()));
Middleware:
public function handle($request, Closure $next) {
$request->merge(['frontmatter' => $this->parser->parse($request->input('content'))]);
return $next($request);
}
Artisan Commands:
public function handle() {
foreach (Storage::files('markdown') as $file) {
$content = Storage::get($file);
$this->parser->parse($content); // Throws on error
$this->info("Valid: {$file}");
}
}
How can I help you explore Laravel packages today?