Vincent Barrault

Générer des routes dynamiquement avec Symfony et Wordpress

Générer des routes dynamiquement avec Symfony et Wordpress

Table des matières

Installer Wordpress

L'idée du projet est d'utiliser Wordpress pour administrer le contenu du site, et un Symfony pour consommer l'API de Wordpress et pour afficher les pages.

Je dois donc commencer par installer un nouveau Wordpress. Pour cela, je vais à l'adresse suivante: Wordpress

Une fois le téléchargement terminé, j'extrais l'archive dans mon dossier de travail et je lance la commande suivante:

php -S localhost:9999

Ensuite, si je me rends à l'adresse suivante http://localhost:9999, je peux commencer l'installation du Wordpress.

Installation de Wordpress

Une fois l'installation terminée, Wordpress me propose de me connecter à l'interface avec le compte que j'ai renseigné lors de l'installation.

Fin de l'installation

Activer la réécriture des liens

Pour activer l'API de Wordpress, il suffit d'activer la réécriture des liens à la page suivante: http://localhost:9999/wp-admin/options-permalink.php

Permalinks wordpress

Ensuite, l'API devient accessible à l'url suivante: http://localhost:9999/wp-json/. Cette url est une sorte de documentation de l'API du Wordpress.

Nous pouvons voir la liste des endpoints disponibles et les paramètres qu'ils acceptent.

Api de Wordpress

Créer un nouveau projet Symfony

Dans un autre dossier, je vais créer un nouveau projet Symfony. C'est ce dernier qui lira l'API de Wordpress et qui affichera les pages aux clients.

Je commence par exécuter les commandes suivantes:

symfony new --full my-blog-symfony
cd my-blog-symfony

Et si je vérifie, je n'ai pour le moment aucune route configurée.

bin/console debug:router
 -------------------------- -------- -------- ------ -----------------------------------
  Name                       Method   Scheme   Host   Path
 -------------------------- -------- -------- ------ -----------------------------------
  _preview_error             ANY      ANY      ANY    /_error/{code}.{_format}
  _wdt                       ANY      ANY      ANY    /_wdt/{token}
  _profiler_home             ANY      ANY      ANY    /_profiler/  
  _profiler_search           ANY      ANY      ANY    /_profiler/search
  _profiler_search_bar       ANY      ANY      ANY    /_profiler/search_bar  
  _profiler_phpinfo          ANY      ANY      ANY    /_profiler/phpinfo
  _profiler_search_results   ANY      ANY      ANY    /_profiler/{token}/search/results
  _profiler_open_file        ANY      ANY      ANY    /_profiler/open
  _profiler                  ANY      ANY      ANY    /_profiler/{token}
  _profiler_router           ANY      ANY      ANY    /_profiler/{token}/router  
  _profiler_exception        ANY      ANY      ANY    /_profiler/{token}/exception
  _profiler_exception_css    ANY      ANY      ANY    /_profiler/{token}/exception.css
 -------------------------- -------- -------- ------ -----------------------------------

Faire un RouteLoader qui chargera les routes

Je vais donc commencer par déclarer un RouteLoader dans mon fichier de routing.

./config/route.yml
my_blog_pages:
    resource: 'App\Routing\RouteLoader::loadPages'
    type: service

Ce service a besoin d'implémenter RouteLoaderInterface et la méthode loadPages déclarée dans le fichier de routing doit retourner une RouteCollection.

./src/Routing/RouteLoader.php
<?php

declare(strict_types=1);

namespace App\Routing;

use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Component\Routing\Route;
use Symfony\Bundle\FrameworkBundle\Routing\RouteLoaderInterface;
use Symfony\Component\Routing\RouteCollection;

class RouteLoader implements RouteLoaderInterface
{
    private $client;

    public function __construct(HttpClientInterface $client)
    {
        $this->client = $client;
    }

    public function loadPages(): RouteCollection
    {
        $routes = new RouteCollection();
        foreach ($this->fetch() as $routeConfiguration) {
            $routeIdentifier = $routeConfiguration['id'];
            $routes->add("page_$routeIdentifier", new Route($routeConfiguration['slug'], [
                '_controller' => 'App\Controller\PageController::show',
                'pageData' => $routeConfiguration
            ]));
        }

        return $routes;
    }

    private function fetch(): array
    {
        $response = $this->client->request('GET','http://localhost:9999/wp-json/wp/v2/pages');

        return json_decode($response->getContent(), true);
    }
}

Si je relance une détection des routes, j'ai bien mes deux nouvelles pages dynamiquement créees.

bin/console debug:router
 -------------------------- -------- -------- ------ ----------------------------------- 
  Name                       Method   Scheme   Host   Path                               
 -------------------------- -------- -------- ------ -----------------------------------
  _preview_error             ANY      ANY      ANY    /_error/{code}.{_format}
  _wdt                       ANY      ANY      ANY    /_wdt/{token}
  _profiler_home             ANY      ANY      ANY    /_profiler/
  _profiler_search           ANY      ANY      ANY    /_profiler/search
  _profiler_search_bar       ANY      ANY      ANY    /_profiler/search_bar
  _profiler_phpinfo          ANY      ANY      ANY    /_profiler/phpinfo
  _profiler_search_results   ANY      ANY      ANY    /_profiler/{token}/search/results
  _profiler_open_file        ANY      ANY      ANY    /_profiler/open
  _profiler                  ANY      ANY      ANY    /_profiler/{token}
  _profiler_router           ANY      ANY      ANY    /_profiler/{token}/router
  _profiler_exception        ANY      ANY      ANY    /_profiler/{token}/exception
  _profiler_exception_css    ANY      ANY      ANY    /_profiler/{token}/exception.css
  page_3                     ANY      ANY      ANY    /privacy-policy
  page_2                     ANY      ANY      ANY    /sample-page
 -------------------------- -------- -------- ------ -----------------------------------

Faire un Controller qui affichera les pages

Il ne me reste plus qu'à créer le Controller, qui se chargera simplement de transférer les données de l'aAPI à la vue.

./src/Controller/PageController.php
<?php

declare(strict_types=1);

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class PageController extends AbstractController
{
    public function show(Request $request): Response
    {
        return $this->render('page.html.twig', $request->get('pageData'));
    }
}

Le template de la vue se chargera juste d'afficher le titre de la page et le contenu des pages dans des sections dédiées

./templates/page.html.twig
{% extends 'base.html.twig' %}

{% block body %}
    <h1>{{ title.rendered }}</h1>
    <p>{{ content.rendered | raw }}</p>
{% endblock %}

Le résultat

Ensuite, lorsque je vais sur http://localhost:8000/sample-page, j'ai une erreur doctrine, parce que ma base de données n'est pas correctement configurée.

Rien de grave, je modifie le fichier .env (ou je crée une copie .env.local et modifie cette dernière) pour me connecter à une base de données.

J'exécute ensuite la commande suivante et tout revient dans l'ordre.

bin/console doctrine:database:create

Affichage de la page

Une fois la page chargée, le système de cache de sSymfony enregistrera l'url et le contenu dans app/cache.