Création d'un plugin Contao - développement front & backend!
Écrit le by rd
Table de matières
Aller au contenu- La structure des fichiers du plugin
- Plugin Contao: La structure de base
- La structure du Contao module Frontend "Hello World"
- Module Contao Backend: Structure et intégration de la base de données
Tous les débuts sont difficiles. Même pour des développeurs expérimentés comme nous, se lancer dans de nouvelles technologies est souvent un défi. Comprendre les concepts derrière le développement d'un plug-in Contao et les utiliser pour enrichir son propre site web Contao avec ses propres plug-ins innovants demande du temps. La documentation de Contao offre certes un assez bon aperçu, mais seulement jusqu'à un certain point. Plus les questions deviennent spécifiques, moins on y trouve ce qu'on cherche. C'est pourquoi nous avons décidé d'écrire un article sur la manière de créer soi-même un plugin Contao « Hello World ». L'article est écrit simplement et vous fournit des connaissances de base intéressantes dont vous avez besoin pour développer vos propres plugins dans Contao. Dans cet article, vous apprendrez comment mettre en place la base d'un plugin, comment afficher un texte « Hello World » sur le front-end, quelle doit être la structure des données et comment créer une connexion à une base de données. Au final, le tout devrait être un plugin « Hello World » qui affiche en plus des messages que l'on a définis dans le backend.
Le plugin est disponible sur Github à ce lien. Vous pouvez utiliser ce code comme base et à des fins de test.
La structure des fichiers du plugin
La structure de fichier du plugin Contao doit absolument être respectée pour que le Contao Manager reconnaisse le plugin Contao en tant que tel et le charge.
Plugin Contao: La structure de base
Dans la première étape, il faut construire le plugin de manière à ce que Contao le considère comme un plugin et que l'on puisse l'installer via le Contao Manager.
Pour cela, les classes suivantes doivent être créées et adaptées :
La structure de Composer
Contao utilise PHP Composer pour les modules, les extensions et les plugins. C'est pourquoi notre plugin a également besoin d'un fichier de configuration Composer, qui se trouve dans le répertoire racine du plugin. Si tu veux utiliser l'exemple JSON de Composer, tu dois absolument adapter les valeurs marquées d'un '#'.
./composer.json
{
"name": "time4digital/dylans-hello-world-bundle", # Nom du plugin
"description": "Dylan's Hello World Plugin", # Description du plugin
"license": "LGPL-3.0-or-later",
"type": "contao-bundle",
"version": "0.0.4", # Version du plugin
"authors": [
{
"name": "Ribeiro de Serra Dylan",
"homepage": "https://www.time4digital.lu" # Auteur du plugin
}
],
"homepage": "https://contao.org", # OPTIONEL: Ton propre site web
"support": {
"issues": "https://github.com/ridy01-backup/contao-plugins/issues", #OPTIONEL: Lien sur Git.
"source": "https://github.com/ridy01-backup/contao-plugins"
},
"require": {
"php": "^8.1",
"contao/core-bundle": "^4.13 || ^5.0" # Déclare tes dépendances ici
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.5",
"contao/manager-plugin": "^2.0",
"phpunit/phpunit": "^9.5",
"symfony/phpunit-bridge": "^6.1"
},
"conflict": {
"contao/manager-plugin": "<2.0 || >=3.0" # Conflits potentiels peuvent être déclarés ici
},
"autoload": {
"psr-4": {
"Time4digital\\DylansHelloWorldBundle\\": "src/" # Le chemin qui sera lié, Format: "VendorName\\BundleName\\": "CHEMIN"
}
},
"autoload-dev": {
"psr-4": {
"Time4digital\\DylansHelloWorldBundle\\Tests\\": "tests/" # Le chemin pour les tests, Format: "VendorName\\BundleName\\Tests": "CHEMIN"
}
},
"config": {
"allow-plugins": {
"bamarni/composer-bin-plugin": true,
"contao-components/installer": true,
"contao/manager-plugin": true
}
},
"extra": {
"bamarni-bin": {
"bin-links": false,
"target-directory": "tools"
},
"contao-manager-plugin": "Time4digital\\DylansHelloWorldBundle\\ContaoManager\\Plugin" # Lien du plugin, Format:"VendorName\\BundleName\\ContaoManager\\Plugin
},
"scripts": {
"all": [
"@unit-tests",
"@ecs",
"@phpstan"
],
"ecs": "@php tools/ecs/vendor/bin/ecs check src tests --config ecs.php --fix --ansi",
"phpstan": "@php tools/phpstan/vendor/bin/phpstan analyze --ansi",
"unit-tests": "@php vendor/bin/phpunit --colors=always"
}
}
La structure de la classe Bundle
Le Contao Bundle est là pour regrouper tes ressources. Cette classe elle-même ne nécessite pas de spécifications supplémentaires ; il suffit d'étendre la classe du Symfony Bundle.
./src/DylansHelloWorldBundle.php
<?php
namespace Time4digital\DylansHelloWorldBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class DylansHelloWorldBundle extends Bundle
{
}
La structure de la classe Plugin
La classe Plugin sert à charger le bundle pour que le Contao Manager sache qu'il s'agit d'un plugin Contao.
./src/ContaoManager/Plugin.php
<?php
declare(strict_types=1);
namespace Time4digital\DylansHelloWorldBundle\ContaoManager;
use Contao\ManagerPlugin\Bundle\BundlePluginInterface;
use Contao\ManagerPlugin\Bundle\Config\BundleConfig;
use Contao\ManagerPlugin\Bundle\Parser\ParserInterface;
use Contao\CoreBundle\ContaoCoreBundle;
use Time4digital\DylansHelloWorldBundle\DylansHelloWorldBundle;
class Plugin implements BundlePluginInterface
{
/**
* {@inheritdoc}
*/
public function getBundles(ParserInterface $parser)
{
return [
BundleConfig::create(DylansHelloWorldBundle::class)
->setLoadAfter([ContaoCoreBundle::class]),
];
}
}
La structure de la class Dependency
La classe Dependency sert à charger les fichiers de configuration et de services.
./src/DependencyInjection/DylansHelloWorldExtension.php
<?php
declare(strict_types=1);
namespace Time4digital\DylansHelloWorldBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
class DylansHelloWorldExtension extends Extension
{
/**
* {@inheritdoc}
*/
public function load(array $mergedConfig, ContainerBuilder $container)
{
$loader = new YamlFileLoader(
$container,
new FileLocator(__DIR__.'/../Resources/config')
);
$loader->load('services.yml');
}
}
Les fichiers Config et Services
Les fichiers Config et Services servent à lier les classes que l'on écrit au sein du bundle, afin qu'elles puissent être chargées et utilisées lors de l'installation.
./src/Resources/config/config.yml
imports:
- { resource: services.yml }
./src/Resources/config/services.yml
services:
_defaults:
autowire: true
autoconfigure: true
Et ainsi, la base du plugin est construite. On pourrait maintenant compresser le plugin, le télécharger via le Contao Manager et l'installer.
Mais cela ne suffit pas encore pour afficher 'Hello World' dans le frontend.
La structure du Contao module Frontend "Hello World"
Dans cette section, nous créons un module frontend qui doit afficher "Hello World" dans le frontend.
Le module charge en outre un fichier CSS et JS.
La structure de la classe du module Frontend
La moduleclasse sert à créer un module dans le backend, qui peut ensuite être chargé dans un article ou similaire.
./src/Module/DylanHelloWorldModule.php
<?php
namespace Time4digital\DylansHelloWorldBundle\Module;
use Contao\Module;
//Hier werden die CSS- und JS-Dateien gesetzt. Format: bundles/bundleName/dateiName.dateExtension
$GLOBALS['TL_CSS'][] = 'bundles/dylanshelloworld/styles.css';
$GLOBALS['TL_JAVASCRIPT'][] = 'bundles/dylanshelloworld/scripts.js';
class DylanHelloWorldModule extends Module
{
// On définit ici le nom du template.
// Le nom doit correspondre au modèle qui se trouve sous ./src/Resources/contao/templates.
protected $strTemplate = 'mod_helloWorld';
protected function compile()
{
// Avec $this->Template->nameVariable, tu crées des variables qui peuvent ensuite être utilisées dans le modèle.
$this->Template->message = 'Hello World!';
}
}
Porter le module Frontend dans le Backend
Le fichier Config PHP sert à apporter des modules dans le backend.
./src/Resources/contao/config/config.php
<?php
use Time4digital\DylansHelloWorldBundle\Module\DylanHelloWorldModule;
// Frontend modules
// Sous "miscellaneous", il devrait créer un nouveau onglet "Hello World Plugin" avec lequel on accède notre module Frontend
$GLOBALS['FE_MOD']['miscellaneous']['Hello World Plugin'] = DylanHelloWorldModule::class;
Fichier modèle pour le module Frontend
Le fichier modèle est en quelque sorte utilisé comme conteneur pour le module. Tu y intègres les données que tu définis dans le module et tu construis ainsi une structure HTML.
./src/Resources/contao/templates/modules/mod_helloWorld.html5
<?php $this->extend('block_searchable'); ?>
<?php $this->block('content'); ?>
<!-- Ici on utilise la valeur de la variable message. -->
<div class="dylan-hello-world-container">
<?= $this->message; ?>
</div>
<?php $this->endblock(); ?>
Intégrer CSS et JS dans le module Contao
Tu peux intégrer tes propres fichiers CSS et JS dans le module Contao, comme défini dans le module ci-dessus. Pour cela, il suffit de respecter la structure de fichier suivante (le nom du fichier n'a pas d'importance) :
./src/Resources/public/scripts.js
./src/Resources/public/styles.css
... et voilà, tu peux créer un nouveau module dans le backend sous Themes > Frontend Module et tu choisis simplement le plugin Hello World comme type de module !
Ensuite, tu vas sur un article quelconque ou quelque chose de similaire et tu y sélectionnes le module créé.
Ouf, c'était déjà beaucoup de travail... mais ce n'est pas encore suffisant! Certes, notre module frontend peut bien afficher quelque chose de beau dans le frontend, et est équipé de fonctions PHP... mais si nous voulons en plus charger des données de la base de données et les gérer via le backend Contao ?
C'est précisément ce que nous allons aborder en détail dans la section suivante.
Module Contao Backend: Structure et intégration de la base de données
Dans cette section, nous allons créer un module backend qui charge des données à partir d'une table appelée tl_messages et qui peut en outre être édité. Le tout doit être visible dans le backend Contao sous un point de menu.
De plus, nous étendons le module Frontend pour qu'il lise également les données du backend.
Création de tables de base de données avec DCA
Le fichier PHP de FDCA te permet d'indiquer à Contao que tu souhaites créer une nouvelle table de base de données.
Tu configures ainsi la structure de la table et tu définis comment les données doivent être affichées.
./src/Resources/contao/dca/tl_messages.php
<?php
use Contao\DC_Table;
// Le nom de la table ; le fichier PHP doit porter le même nom.
$GLOBALS['TL_DCA']['tl_messages'] = [
// On définit ici ce qui doit être affiché dans le backend Contao:
'palettes' => [
'default' => '{messages_legend},message;'
],
// Les champs SQL sont définis ici:
'fields' => [
// Ce champs est obligatoire.
'id' => [
'sql' => "int(10) unsigned NOT NULL auto_increment",
],
// Ce champs est obligatoire.
'tstamp' => [
'sql' => "int(10) unsigned NOT NULL default '0'",
'label' => 'TS',
],
'message' => [
'inputType' => 'text',
'eval' => ['tl_class' => 'w50', 'maxlength' => 255],
'sql' => "varchar(255) NOT NULL default ''"
]
],
// Les clés et autres attributs sont définis ici.
'config' => [
'dataContainer' => DC_Table::class,
'sql' => [
'keys' => [
'id' => 'primary'
]
]
],
// C'est ici que l'on définit comment l'ensemble sera représenté dans le backend Contao.
'list' => [
'sorting' => [
'mode' => 1,
],
'operations' => [
'edit',
'delete',
],
'label' => [
'fields' => ['id','message'],
'showColumns' => true,
]
],
];
Traduction des champs
Le fichier XLF de la traduction sert à définir les labels et les descriptions pour les différentes langues.
./src/Resources/contao/languages/en/tl_messages.xlf
<?xml version="1.0" ?><xliff version="1.1">
<!-- Format: contao/languages/LANGUE/TABELLE.php-->
<file datatype="php" original="contao/languages/en/tl_messages.php" source-language="en">
<body>
<!-- Désignations des labels dans le backend de Contao -->
<trans-unit id="tl_messages.messages_legend">
<source>Messages</source>
</trans-unit>
<!-- Désignation du champs "Nachricht" -->
<trans-unit id="tl_messages.message.0">
<source>Message</source>
</trans-unit>
<!-- Désignation de la description du champs "Nachricht" -->
<trans-unit id="tl_messages.message.1">
<source>Your individual message.</source>
</trans-unit>
</body>
</file>
</xliff>
Porter le module Backend dans le backend de Contao
Le fichier PHP Config doit maintenant être adapté comme pour le module frontend.
./src/Resources/contao/config/config.php
<?php
use Time4digital\DylansHelloWorldBundle\Module\DylanHelloWorldModule;
// Modules Frontend
// Sous "miscellaneous", on crée un nouvel onglet nommé "Hello World Plugin", qui chargera ensuite notre module frontend.
$GLOBALS['FE_MOD']['miscellaneous']['Hello World Plugin'] = DylanHelloWorldModule::class;
// Modules Backend
// Sous la catégorie de menu « content » devrait maintenant apparaître une nouvelle entrée de menu appelée "Messages", qui gère la table tl_messages.
$GLOBALS['BE_MOD']['content']['Messages'] = [
'tables' => ['tl_messages']
];
Afficher les données du backend dans le frontend
Pour cela, le modèle et le module frontal doivent être adaptés.
./src/Module/DylanHelloWorldModule.php
<?php
namespace Time4digital\DylansHelloWorldBundle\Module;
use Contao\Module;
// Les fichiers CSS et JS sont placés ici. Format : bundles/bundleName/fileName.dateExtension
$GLOBALS['TL_CSS'][] = 'bundles/dylanshelloworld/styles.css';
$GLOBALS['TL_JAVASCRIPT'][] = 'bundles/dylanshelloworld/scripts.js';
class DylanHelloWorldModule extends Module
{
// On définit ici le nom du modèle.
// Le nom doit correspondre au modèle qui se trouve sous ./src/Resources/contao/templates.
protected $strTemplate = 'mod_helloWorld';
protected function compile()
{
// Avec $this->Template->nameVariable on peut créer des variables, qui peuvent être utilisées dans le modèle.
$this->Template->message = 'Hello World!';
// La classe Module nous donne la possibilité de charger rapidement des entrées de base de données via la classe Contao Database.
// Ici, on récupère les données via une requête SQL. Cette requête extrait les entrées de la base de données et les stocke dans un array.
try {
$objEntries = $this->Database->execute("SELECT * FROM tl_messages");
$this->Template->entries = $objEntries->fetchAllAssoc();
} catch (\Exception $e) {
// Si cela ne fonctionne pas, on retourne un tableau vide au modèle.
$this->Template->entries = [];
}
}
}
./src/Resources/contao/templates/modules/mod_helloWorld.html5
<?php $this->extend('block_searchable'); ?>
<?php $this->block('content'); ?>
<!-- Ici on utilise la valeur de la variable message -->
<div class="dylan-hello-world-container">
<?= $this->message; ?>
</div>
<!-- Nous parcourons ici le tableau entries et prenons pour chaque élément la valeur du message -->
<div class="dylans-hello-world-live-container">
<ul>
<?php foreach ($this->entries as $entry): ?>
<li><?= $entry["message"]; ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php $this->endblock(); ?>
Finalement, on y est! Après bien des hauts et des bas, nous avons atteint le sommet. Il est temps de se réjouir ! ;-)
Après la réinstallation du plugin, il devrait y avoir un nouvel élément de menu appelé « Messages », qui permet de créer de nouveaux messages. Ensuite, notre module frontal devrait afficher tous ces messages.
Nous espérons que cet article de blog vous a permis d'en apprendre davantage sur le développement de plugins Contao.
Il est important de noter qu'il existe plusieurs façons de mettre en œuvre ce plugin et que cet article ne constitue qu'un exemple. Vous êtes entièrement libre de développer votre plugin Hello World comme vous le souhaitez, tant que la base est correcte et que le Contao Manager le reconnaît comme un plugin et l'installe.
Tu trouveras encore plus d'informations ici.
En outre, tu peux aussi télécharger directement le plugin via ce lien et bien sûr continuer à le développer.
Merci d'avoir lu cet article de blog! J'espère que tu t'es bien amusé et que tu as pu apprendre quelque chose. Continuez à vous amuser en développant !