Lädt...


🔧 Using Twig for rendering Markdown with PHP


Nachrichtenbereich: 🔧 Programmierung
🔗 Quelle: dev.to

Twig is a go-to templating engine for rendering HTML when developing web applications with Symfony.
However, Twig’s flexibility extends beyond generating just HTML pages. It can be a powerful tool for delivering content across multiple channels, such as generating Markdown files, JSON outputs, and even plain text, all from the same set of content.

This adaptability allows you to create content for different channels.

You can use Twig for generating HTML, Markdown, JSON, Text etc

Use case: fetching and rendering a recipe as Markdown with Symfony

In this example, we use Symfony's HTTP Client to fetch a recipe from an external API (https://dummyjson.com/recipes/1) and render it as a Markdown document using Twig.
This approach shows how you can combine Symfony's powerful packages, like the Symfony HTTP client for external data retrieval and Twig for rendering views, to deliver content across multiple channels, such as Markdown reports in a command-line tool.

The command/script we are going to build fetches the recipe data (title, description, ingredients, and instructions) from the API, processes it, and then uses Twig to output the content in a structured Markdown format. This practical use case illustrates how to use Twig beyond web templates, making it versatile for generating content in various formats.

So, we are going to use:

Installing necessary Symfony components

Ensure that you have the required components installed for HTTP requests and creating commands:

composer require symfony/http-client symfony/console twig/twig

Create a Symfony command

First, let's create a new Symfony command.

If you want to read more about how to create a command line tool using the Symfony Command component, I wrote a specific article about this: https://dev.to/robertobutti/building-a-command-line-tool-with-php-and-symfony-console-4n6g

Commands classes, typically go into the src/Commands directory.

# create a new empty directory
mkdir -p src/Commands
# create a new empty file
touch src/Commands/FetchRecipeCommand.php

Command Class (e.g., src/Commands/FetchRecipeCommand.php):

<?php

namespace MyExample\Commands;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpClient\HttpClient;


class FetchRecipeCommand extends Command
{

    private $twig;

    public function __construct()
    {
        $this
            ->setName('recipe')
            ->setDescription('Prints a recipe in Markdown')
            ->setHelp('This command prints a simple recipe in Markdown.');
        // Step 1: loading the Twig environment
        $loader = new \Twig\Loader\FilesystemLoader(__DIR__ . '/../resources/views');
        $twig = new \Twig\Environment(
            $loader,
            // Optional: Enable caching for better performance
            /*[
                'cache' => __DIR__ . '/../../cache',
            ]*/
        );

        $this->twig = $twig;
        parent::__construct();
    }

    protected function configure()
    {
        $this->setDescription('Fetches a recipe from an API and renders it as Markdown');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // Step 2: Initialize the HTTP client and fetch the recipe
        $client = HttpClient::create();
        $response = $client->request('GET', 'https://dummyjson.com/recipes/1');

        // Step 3: obtain the array of info
        $recipeData = $response->toArray();

        // Step 4: Render the template using Twig, returning a string
        $markdownOutput = $this->twig->render('recipe.md.twig', $recipeData);

        // Step 5: Output the generated Markdown
        $output->writeln($markdownOutput);

        return Command::SUCCESS;
    }
}

Here’s a detailed explanation of each step in the FetchRecipeCommand example.

Step-by-step breakdown

Step 1: Loading the twig environment

To use Twig outside its typical web context, such as in a PHP command-line tool, you first need to initialize it manually via the Twig\Environment class. Here's an example setup for Twig in a console command:

$loader = new \Twig\Loader\FilesystemLoader(__DIR__ . '/../resources/views');
$twig = new \Twig\Environment(
    $loader,
    // Optional: Enable caching for better performance
    /*[
        'cache' => __DIR__ . '/../../cache',
    ]*/
);
$this->twig = $twig;

Explanation:

  • The twig environment is initialized by creating a FilesystemLoader that tells Twig where to find the templates. This case points to the src/resources/views folder where your Twig templates are stored.
  • Then, the $twig environment is instantiated and responsible for rendering the templates. Optional caching can be enabled to improve performance by storing precompiled templates.
  • Finally, the initialized $twig environment is assigned to $this->twig for later use (in the execute() method).

Step 2: initializing the HTTP Client and fetch the recipe

$client = HttpClient::create();
$response = $client->request('GET', 'https://dummyjson.com/recipes/1');

Explanation:

  • The Symfony HTTP client is created using the HttpClient::create() method, which allows the command to perform HTTP requests.
  • To fetch a recipe, the request() method performs a GET request to the specified URL (https://dummyjson.com/recipes/1).
  • The API returns a JSON response stored in the $response variable.

Step 3: obtaining the array of information

$recipeData = $response->toArray();

Explanation:

  • The toArray() method converts the JSON response from the API into a PHP array. This array contains the recipe’s data (e.g., name, ingredients, instructions), which will be used to populate the Twig template in the next step.

Step 4: rendering the template using Twig

$markdownOutput = $this->twig->render('recipe.md.twig', $recipeData);

Explanation:

  • The Twig environment's render() method generates the Markdown output. It loads the template (recipe.md.twig) from the src/resources/views folder.
  • The recipe data fetched from the API ($recipeData) is passed into the template, where it will replace placeholders such as the recipe name, ingredients, and instructions, creating a fully formatted Markdown file.
  • The rendered Markdown content (the string returned by the render() method) is stored in the $markdownOutput variable.

Step 5: generating output for the generated Markdown

$output->writeln($markdownOutput);

Explanation:

  • The final Markdown content is printed to the console using the $output->writeln() method. This method outputs the string to the console, allowing users to see the formatted recipe in Markdown format (eventually, you can redirect the output into a file in the shell).

Creating the starter file

You have to create a starter file to allow the user to launch your Symfony command directly from the shell. (In this article, we are not creating a Symfony application; we are building a PHP script using the Symfony packages.)
In the project directory, where you have the composer.json file and where you have the src directory, you can create a my-app file.

#!/usr/bin/env php
<?php

use MyExample\Commands\FetchRecipeCommand;
use Symfony\Component\Console\Application;

if (file_exists(__DIR__ . '/../../autoload.php')) {
    require __DIR__ . '/../../autoload.php';
} else {
    require __DIR__ . '/vendor/autoload.php';
}

/**
 * Start the console application.
 */
$app = new Application('Recipe to Markdown', '1.0.0');
$app->setDefaultCommand("recipe");

$app->add(new FetchRecipeCommand());


$app->run();

To use correctly the namespaces and the classes be sure to set the autoload section in the composer.json file:

{
    "require": {
        "symfony/http-client": "^7.1",
        "symfony/console": "^7.1",
        "twig/twig": "^3.14"
    },
    "autoload": {
        "psr-4": {
            "MyExample\\": "src/"
        }
    }
}

If you change the autoload section I suggest to dump the autoload file:

composer dump-autoload

Now, you have to create the Twig template/view to render the data retrieved by the API.

Create a Twig template/view for the recipe

Next, create a Twig template/view to render the recipe in Markdown format.
This template should go in the views directory (e.g., src/resources/view/recipe.md.twig).

# Recipe: {{ name }}

- Preparation time: {{ prepTimeMinutes }} minutes
- Cooking time {{ cookTimeMinutes }} minutes
- Difficulty level: {{ difficulty }}
- Cuisine: {{ cuisine }}
- Servings {{ servings }} people, with {{ caloriesPerServing }} calories per person

## Ingredients:

{% for ingredient in ingredients %}
- {{ ingredient }}
{% endfor %}

## Instructions:

{% for instruction in instructions %}
- {{ instruction }}
{% endfor %}

Enjoy!

This Twig view file will render the recipe in Markdown format, with sections for the recipe's name, ingredients, and instructions.

Running the command

To execute the command, run the following in the terminal:

php my-app

In the case you have more than one command, you can launch:

php m-app recipe

To see all the available commands:

php my-app list

Conclusion

With this approach, you can easily retrieve data from an external API using Symfony's HTTP client, process the response, and render the output in a structured format using Twig. In this case, the command outputs a recipe as Markdown, but this technique can be adapted to any other content or data type you need to process.
Enjoy your recipe!

...

🔧 Using Twig for rendering Markdown with PHP


📈 52.61 Punkte
🔧 Programmierung

🕵️ perl-XML-Twig XML::Twig privilege escalation


📈 40.84 Punkte
🕵️ Sicherheitslücken

🕵️ perl-XML-Twig XML::Twig erweiterte Rechte


📈 40.84 Punkte
🕵️ Sicherheitslücken

🕵️ perl-XML-Twig XML::Twig erweiterte Rechte


📈 40.84 Punkte
🕵️ Sicherheitslücken

🔧 Server-Side Rendering (SSR) vs. Client-Side Rendering (CSR): The Fascinating World of Page Rendering


📈 36.55 Punkte
🔧 Programmierung

🔧 Rendering Twig templates in Storybook


📈 32.61 Punkte
🔧 Programmierung

🕵️ CVE-2024-7738 | yzane vscode-markdown-pdf 1.5.0 Markdown File pathname traversal


📈 25.94 Punkte
🕵️ Sicherheitslücken

🕵️ CVE-2019-19619 | Documize up to 3.5.0 Markdown markdown.go cross site scripting


📈 25.94 Punkte
🕵️ Sicherheitslücken

🕵️ CVE-2019-25102 | simple-markdown 0.6.0 simple-markdown.js redos (ID 73)


📈 25.94 Punkte
🕵️ Sicherheitslücken

🕵️ CVE-2019-25103 | simple-markdown 0.5.1 simple-markdown.js redos


📈 25.94 Punkte
🕵️ Sicherheitslücken

🕵️ transformers up to 0.32.x Markdown Qiita::Markdown cross site scripting


📈 25.94 Punkte
🕵️ Sicherheitslücken

🐧 markdown-slides: modern slides with markdown


📈 25.94 Punkte
🐧 Linux Tipps

🕵️ Discount 2.2.3a markdown.c quoteblock Markdown memory corruption


📈 25.94 Punkte
🕵️ Sicherheitslücken

🕵️ Discount 2.2.3a markdown.c isfootnote Markdown memory corruption


📈 25.94 Punkte
🕵️ Sicherheitslücken

🕵️ Discount 2.2.3a markdown.c islist Markdown memory corruption


📈 25.94 Punkte
🕵️ Sicherheitslücken

🕵️ Discount 2.2.3a markdown.c quoteblock Markdown Pufferüberlauf


📈 25.94 Punkte
🕵️ Sicherheitslücken

🕵️ Discount 2.2.3a markdown.c islist Markdown Pufferüberlauf


📈 25.94 Punkte
🕵️ Sicherheitslücken

🕵️ Discount 2.2.3a markdown.c isfootnote Markdown Pufferüberlauf


📈 25.94 Punkte
🕵️ Sicherheitslücken

🔧 Beyond boring 🙄 markdown rendering with LLMs ✨ and React ⚛️


📈 25.15 Punkte
🔧 Programmierung

🔧 Server-Side Rendering (SSR) vs. Client-Side Rendering (CSR) in Web Applications: A Complete Guide


📈 24.37 Punkte
🔧 Programmierung

🕵️ CVE-2023-37908 | XWiki Rendering XHTML Rendering cross site scripting (GHSA-663w-2xp3-5739)


📈 24.37 Punkte
🕵️ Sicherheitslücken

🔧 Client-side Rendering & Server-side Rendering


📈 24.37 Punkte
🔧 Programmierung

🔧 Concurrent Rendering in React: How React’s Concurrent Rendering Makes Everything Smoother


📈 24.37 Punkte
🔧 Programmierung

🔧 CSR, SSR, pre-rendering: Which rendering technique to choose?


📈 24.37 Punkte
🔧 Programmierung

🔧 Understanding Server-Side Rendering (SSR) and Client-Side Rendering (CSR): How Websites Show You Content


📈 24.37 Punkte
🔧 Programmierung

🔧 Client Side Rendering (CSR) vs Server Side Rendering (SSR): Simplified Story


📈 24.37 Punkte
🔧 Programmierung

🔧 Mastering Advanced React: Strategies for Efficient Rendering and Re-Rendering


📈 24.37 Punkte
🔧 Programmierung

🔧 Client Side Rendering vs Server side rendering vs Server Components


📈 24.37 Punkte
🔧 Programmierung

🔧 🚀 Day 5: Exploring List Rendering and Conditional Rendering in React🚀


📈 24.37 Punkte
🔧 Programmierung

🔧 Server-Side Rendering vs Client-Side Rendering


📈 24.37 Punkte
🔧 Programmierung

🔧 Server Side Rendering Vs Client Side Rendering Waterfall


📈 24.37 Punkte
🔧 Programmierung

🔧 Exploring Next.js: Unraveling the Dynamics of Client-Side Rendering vs. Server-Side Rendering


📈 24.37 Punkte
🔧 Programmierung

🔧 Client-Side Rendering (CSR) Vs Server-Side Rendering (SSR)


📈 24.37 Punkte
🔧 Programmierung

matomo