← Back to All Posts

Airframe Wrote All This Code

We wrote a GitHub Issue and Airframe commited to a new branch and opened a pull request in GitHub. We reviewed & merged Airframe's PR and now we have a blog!

From Issue to Production in Three Minutes

The code in this article is what we actually use to render our blog. In fact, it's what renders this post!

We used Airframe to build this feature before turning it into a tutorial. We spent 1 minute writing our issue, 1 minute letting Airframe draft the PR, and 1 minute reviewing and merging the PR.

We wrote an issue

We knew we wanted a simple way to get a blog going inside our Laravel app. We wrote an issue to track exactly what we wanted.

#127 Introduce Markdown Blog

Open kressaty opened this issue 1 hour ago

We need to be able to publish blog posts quickly and easily.

Idea is to have a directory of markdown files in resources that's /resources/markdown/blog

Then we need a route at /blog/{slug} that loads the correct markdown file based on the markdown filename for the slug

Airframe optimized the issue

Airframe then evaluated the issue, and scored it 2/5 for having a clear objective, 2/5 for describing the opportunity, and 2/5 for outlining specific requirements. We used Airframe to optimize and rewrite the issue, and it now looks like this:

#127 Introduce Markdown Blog

Open kressaty opened this issue 1 hour ago

Introduction

The goal of this issue is to implement a Markdown-based blogging system within our Laravel application. This will allow us to publish blog posts quickly and easily by utilizing Markdown files.

Requirements

  1. Directory Structure: Create a directory for Markdown files at resources/markdown/blog. This directory will store all blog posts in Markdown format.
  2. Routing: Implement a route that maps to /blog/{slug}. The {slug} parameter will correspond to the filename of the Markdown file (without the .md extension) that will be loaded and displayed.
  3. Markdown Rendering: Use a Markdown parser to convert the Markdown content into HTML for display on the blog page.
  4. Error Handling: If a requested Markdown file does not exist, return a 404 error page with a user-friendly message.

Steps to Implement

  1. Create the directory resources/markdown/blog if it does not already exist.
  2. Define a new route in routes/web.php:
    Route::get('/blog/{slug}', [BlogController::class, 'show']);
    
  3. Create a `BlogController
  4. In the BlogController, implement the show method:
    • Retrieve the slug from the route.
    • Construct the file path to the Markdown file: resources/markdown/blog/{slug}.md.
    • Check if the file exists. If it does, read the file content and parse it using a Markdown parser (e.g., Parsedown).
    • Return a view that displays the parsed HTML content.
    • If the file does not exist, return a 404 response.
  5. Create a view file (e.g., resources/views/blog/show.blade.php) to display the blog post content.

Acceptance Criteria

  • Blog posts can be added as Markdown files in the specified directory.
  • The route /blog/{slug} correctly loads and displays the corresponding Markdown file.
  • The application handles non-existent slugs gracefully by showing a 404 error page.

Out of Scope

  • This implementation does not include features such as comments, tags, or categories for blog posts. These can be considered for future enhancements.

Airframe generated a Pull Request

We then used Airframe to generate a pull request with the optimized issue. Airframe generated some great code, but used a markdown parser that we realized we didn't want, since we were already using spatie/laravel-markdown in our project.

<?php

namespace App\Http\Controllers; // Define the namespace for the BlogController

use Illuminate\Http\Request; // Import the Request class
use Illuminate\Support\Facades\Storage; // Import the Storage facade
use App\Http\Controllers\Controller; // Import the base Controller class
use Parsedown; // Import the Parsedown Markdown parser

class BlogController extends Controller // Define the BlogController class
{
// Method to show a blog post
public function show($slug) // Accepts the slug as a parameter
{
// Construct the file path for the Markdown file
$filePath = resource_path('markdown/blog/' . $slug . '.md'); // Build the path to the Markdown file

// Check if the Markdown file exists
if (file_exists($filePath)) { // If the file exists
    $markdownContent = file_get_contents($filePath); // Read the content of the Markdown file
    $parsedown = new Parsedown(); // Create a new instance of Parsedown
    $htmlContent = $parsedown->text($markdownContent); // Convert Markdown to HTML

    // Return the view with the parsed HTML content
    return view('blog.show', ['content' => $htmlContent]); // Pass the HTML content to the view
}

// If the file does not exist, return a 404 response
abort(404, 'Blog post not found.'); // Trigger a 404 error with a message
}
<!DOCTYPE html> <!-- Start of the HTML document -->
<html lang="en"> <!-- HTML language attribute set to English -->
<head> <!-- Head section of the document -->
    <meta charset="UTF-8"> <!-- Character encoding set to UTF-8 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Responsive viewport settings -->
    <title>Blog Post</title> <!-- Title of the page -->
</head>
<body> <!-- Body section of the document -->
    <div class="container"> <!-- Container for the blog post -->
        {!! $content !!} <!-- Display the parsed HTML content -->
    </div>
</body>
</html>

We reviewed the PR and requested changes

We reviewed the PR and requested changes to remove the markdown parser and use the <x-markdown> component provided by the spatie/laravel-markdown package instead. Airframe made the changes to the file as we requested, and we were ready to merge the PR!

kressaty requested changes 1 hour ago
Lets simplify a bit:
  • don't parse the markdown in the controller - just pass it as one big string to the view
  • in the view, use the existing component we already have to render the markdown

Airframe then made the requested updates to the code and committed them to the existing PR:

if (file_exists($filePath)) { // If the file exists
    $markdownContent = file_get_contents($filePath); // Read the content of the Markdown file
    $parsedown = new Parsedown(); // Create a new instance of Parsedown
    $htmlContent = $parsedown->text($markdownContent); // Convert Markdown to HTML

    // Return the view with the parsed HTML content
    return view('blog.show', ['content' => $htmlContent]); // Pass the HTML content to the view
    // Return the view with the Markdown content as a string
    return view('blog.show', ['content' => $markdownContent]); // Pass the Markdown content to the view
}
<body> <!-- Body section of the document -->
    <div class="container"> <!-- Container for the blog post -->
       {!! $content !!} <!-- Display the parsed HTML content -->
       <x-markdown>{{ $content }}</x-markdown> <!-- Use the existing x-markdown component to render the Markdown content -->
    </div>
</body>

We merged the PR

That's it! We merged the PR and now have a blog system in our Laravel app that uses Markdown files to render blog posts.

Building a Simple Markdown Blog in Laravel

In today's fast-paced development environment, creating content should be as streamlined as possible. Markdown is a popular choice among developers for writing formatted text, and integrating it into your Laravel application can greatly enhance your blogging workflow. In this blog post, we’ll walk through the steps to build a simple Markdown-based blogging system in Laravel using the spatie/laravel-markdown package.

Why Markdown?

Markdown allows you to write formatted text using an easy-to-read, easy-to-write plain text format. It’s perfect for writing blog posts because it’s both powerful and simple to use. By using Markdown, you can focus on writing content without worrying about HTML tags and other complexities.

Why not release this as a package?

Packages require maintenance, updates, and compatibility checks. By implementing this feature directly in your Laravel application, you have full control over the codebase and can easily customize it to fit your specific needs.

Step 1: Installing Laravel Markdown

To render Markdown content in Laravel, we’ll use the spatie/laravel-markdown package. This package provides a convenient way to convert Markdown to HTML using Blade components.

First, install the package via Composer:

composer require spatie/laravel-markdown

Once the package is installed, it will automatically register its service provider. You can optionally publish the configuration file if you need to customize the Markdown rendering settings:

php artisan vendor:publish --tag="markdown-config"

Step 2: Setting Up the Directory Structure

Next, we need a place to store our Markdown files. Within the Laravel project, create a directory named resources/markdown/blog. This directory will house all the Markdown files that represent your blog posts.

mkdir -p resources/markdown/blog

Step 3: Creating the Blog Route

Define a route in routes/web.php that will handle requests for blog posts. The route will map to a BlogController which we'll create shortly. The {slug} parameter in the URL corresponds to the filename of the Markdown file (excluding the .md extension).

Route::get('/blog/{slug}', [BlogController::class, 'show'])->name('blog.show');

Step 4: Building the BlogController

Create a new controller named BlogController using the Artisan command:

php artisan make:controller BlogController

In BlogController, we’ll implement a show method that handles the logic of loading and rendering a Markdown file.

Here’s the code for the BlogController:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\Controller;

class BlogController extends Controller
{
    public function show($slug)
    {
        $filePath = resource_path('markdown/blog/' . $slug . '.md');

        if (file_exists($filePath)) {
            $markdownContent = file_get_contents($filePath);
            return view('blog.show', ['content' => $markdownContent]);
        }

        abort(404, 'Blog post not found.');
    }
}

In this method:

  • We construct the file path based on the slug provided in the URL.
  • If the file exists, we read its contents and pass it to the view.
  • If the file doesn’t exist, we return a 404 error.

Step 5: Rendering the Markdown Content

Now that we have the Markdown content, we need to render it as HTML. The spatie/laravel-markdown package provides an x-markdown Blade component that makes this process incredibly simple.

Here’s the code for the view resources/views/blog/show.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Blog Post</title>
</head>
<body>
    <div class="container">
        <x-markdown>{{ $content }}</x-markdown>
    </div>
</body>
</html>

The x-markdown component automatically converts the Markdown content into HTML, allowing you to easily display it on your blog page. This component is provided by the spatie/laravel-markdown package and leverages the league/commonmark package under the hood for the actual parsing.

Conclusion

And there you have it—a simple yet powerful Markdown-based blog renderer in Laravel. By leveraging Laravel's routing, controllers, Blade templates, and the spatie/laravel-markdown package, you can quickly implement a blogging system that is both developer-friendly and scalable.