· 5 min read

FrankenPHP et Symfony : Une solution d'avenir ?

Dans cet article nous allons découvrir comment utiliser FrankenPHP avec Symfony et comment le déployer en production dans le cloud dans les conditions du réel en quelques minutes.

Dans cet article nous allons découvrir comment utiliser FrankenPHP avec Symfony et comment le déployer en production dans le cloud dans les conditions du réel en quelques minutes.

FrankenPHP et Symfony : Une solution d’avenir ?

FrankenPHP, c’est quoi ?

C’est un serveur web écrit en GO et spécialement conçu pour PHP par le génialisime Kévin Dunglas.

Il est basé sur le serveur Caddy et embarque un moteur PHP directement dans le serveur web.

Il prend en charge nativement HTTP/1.1, HTTP/2, HTTP/3, HTTPS automatique avec Let’s Encrypt et encore plein d’autres choses.

N’hesitez pas à consulter la documentation pour plus d’informations.

Notre projet : Recherche d’entreprise avec l’API gouvernementale

C’est un “vrai-faux” projet, il n’a pas de réel but, il sert juste à tester FrankenPHP avec Symfony.

Apres avoir crée un nouveau projet Symfony 7 avec la commande suivante :

symfony new FrankenSF --webapp

Nous créeons un simple controller avec une route :

<?php

namespace App\Controller;

use App\Form\SocietyType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\HttpClient\HttpClientInterface;

class SearchController extends AbstractController
{
    #[Route('/', name: 'app_search')]
    public function index(Request $request, HttpClientInterface $httpClient): Response
    {
        $results = null;

        $form = $this->createForm(SocietyType::class);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $request = $httpClient->request(
                'GET',
                'https://recherche-entreprises.api.gouv.fr/search?q='.$form->getData()['field_name'].'&activitePrincipale=62.01Z',
                [
                    'headers' => [
                        'Accept' => 'application/json',
                    ],
                ]
            );

            $results = $request->toArray()['results'];
        }

        return $this->render('search/index.html.twig', [
            'form' => $form,
            'results' => $results,
        ]);
    }
}

Créons maintenant le formulaire :

<?php

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class SocietyType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('field_name', TextType::class, [
                'label' => 'Nom de l\'entreprise',
                'attr' => [
                    'placeholder' => 'Rechercher une entreprise par nom',
                ],
            ])
            ->add('submit', SubmitType::class, [
                'label' => 'Rechercher',
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            // Configure your form options here
        ]);
    }
}

Modifions le fichier base.html.twig pour ajouter PicoCSS :

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
        <title>{% block title %}Welcome!{% endblock %}</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text></svg>">
    </head>
    <body>
        <main class="container">
            {% block body %}{% endblock %}
        </main>
    </body>
</html>

Et mettons en place le template twig pour notre route:

{% extends 'base.html.twig' %}

{% block title %}Hello SearchController!{% endblock %}

{% block body %}
<h1>Rechercher une entreprise</h1>
{{ form(form) }}

{% if results|length > 0 %}

    <h2>Résultats de la recherche</h2>
    {% for result in results %}
        <article>
            <ul>
                <li>{{ result.nom_complet }}</li>
                <li>{{ result.siren }}</li>
                <li>{{ result.siege.adresse }}</li>
            </ul>
        </article>
    {% endfor %}

{% endif %}

{% endblock %}

Tester FrankenPHP en local (avec Docker)

Pour tester FrankenPHP en local, nous allons utiliser Docker (parce que c’est plus simple).

Nous allons le tester en mode “normal” (comme n’importe quel serveur web) et en mode “Worker”.

En mode “normal”

Pour lancer FrankenPHP en mode “normal”, il suffit de lancer la commande suivante à la racine du projet :

docker run \                                       
    -v $PWD:/app \
    -p 443:443 \
    dunglas/frankenphp

Rendez-vous ensuite sur https://localhost pour voir le résultat.

Attention, il vous faudra accepter l’alerte de sécurité de votre navigateur.

En mode “Worker”

FrankenPHP peut aussi être utilisé en mode “Worker”, c’est à dire qu’il va charger en mémoire votre application PHP et la servir beaucoup plus rapidement lors des prochaines requêtes.

Pour lancer FrankenPHP en mode “Worker” il faut installer un runtime spécifique.

composer require runtime/frankenphp-symfony

Ensuite, il suffit de lancer la commande suivante à la racine du projet :

docker run \
    -e FRANKENPHP_CONFIG="worker ./public/index.php" \
    -e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \
    -v $PWD:/app \
    -p 80:80 -p 443:443 -p 443:443/udp \
    dunglas/frankenphp

Déployer FrankenPHP en production dans le cloud

Dockerisation de l’application

Première étape vers le déploiement, il faut “dockeriser” notre application.

Avec FrankenPHP, c’est très simple, il suffit de créer un fichier Dockerfile à la racine du projet avec très peu de lignes.

Attention, pour simplifier l’exemple, nous ne faisons pas de multi-stage, ni ne gérons l’installation des dépendances…

FROM dunglas/frankenphp

ENV SERVER_NAME=your-domain-name.example.com
ENV APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime
ENV APP_ENV=prod
ENV FRANKENPHP_CONFIG="worker ./public/index.php"

COPY . /app/

Build de l’image et push sur DockerHub

Pour nous simplifier la vie, mettons en place un fichier Makefile à la racine du projet qui va nous permettre d’automatiser en partie les tâches Docker.

# Makefile pour automatiser les tâches Docker

# Variables
IMAGE_NAME := johndoe/frankensf
TAG := latest

# Construire l'image Docker
build:
	@docker build -t $(IMAGE_NAME):$(TAG) .

# Pusher l'image sur Docker Hub
push:
	@docker push $(IMAGE_NAME):$(TAG)

# Puller l'image depuis Docker Hub
pull:
	@docker pull $(IMAGE_NAME):$(TAG)

# Commande par défaut
.PHONY: build push pull

Pour construire l’image Docker, il suffit de lancer la commande suivante :

make build

Pour pusher l’image sur Docker Hub, il suffit de lancer la commande suivante (a condition d’avoir un compte Docker Hub et d’être connecté) :

make push

Déploiement dans le cloud (avec Hidora)

Pour déployer notre application dans le cloud, nous allons utiliser Hidora.

Hidora est un service de cloud Suisse qui propose des solutions d’hébergement pour les applications PHP, NodeJS, Python, Java, Go, Ruby, etc… et qui permet de déployer des conteneurs Docker en quelques minutes.

Une fois connecté à votre console Hidora, cliquez sur “Créer une application” et choisissez “Docker” comme type d’application :

  • Cliquer sur “Nouvel Environnement”

  • Selectionner votre image Docker, désactiver le “SLB” et ajouter une IPV4 publique

  • Puis paramétrer la variable d’environnement SERVER_NAME avec le nom de domaine de votre application

  • Enfin, cliquer sur “Créer”

Quelques minutes plus tard, votre application est déployée et accessible depuis le nom de domaine que vous avez choisi.

Conclusion

FrankenPHP est un serveur web très prometteur, il est très simple à utiliser et permet de déployer des applications PHP très rapidement.

Il est depuis peu disponible en version 1.0.0 et “production ready”.

2024 sera trés probablement l’année ou FrankenPHP va bousculer le monde du déploiement d’applications PHP tant il est simple à utiliser et performant.

Back to Blog