Developper un plugin Sylius from scratch : le guide du developpeur
L'ecosysteme de plugins est ce qui fait la puissance de Sylius. Savoir en developper un, c'est debloquer la capacite de personnaliser Sylius sans jamais toucher au core. Ce tutoriel vous guide de la creation du squelette a la publication sur Packagist.
Creer le squelette
Sylius fournit un squelette officiel :
composer create-project sylius/plugin-skeleton MonPlugin
cd MonPlugin
Structure generee :
MonPlugin/
src/
MonPluginPlugin.php # Point d'entree du bundle
DependencyInjection/
Configuration.php
MonPluginExtension.php
Entity/ # Vos entites Doctrine
Repository/ # Vos repositories
Form/ # Types de formulaires
Menu/ # Listeners de menu admin
Resources/
config/
services.xml
routes.yaml
doctrine/ # Mappings Doctrine
views/ # Templates Twig
translations/ # Traductions
tests/
Application/ # App Sylius de test
Unit/ # Tests unitaires
Functional/ # Tests fonctionnels
composer.json
phpunit.xml.dist
Exemple concret : un plugin de wishlist
Construisons un plugin qui permet aux clients de sauvegarder des produits en favoris.
1. L'entite WishlistItem
<?php
// src/Entity/WishlistItem.php
namespace MonPlugin\Entity;
use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Core\Model\CustomerInterface;
use Sylius\Component\Core\Model\ProductInterface;
#[ORM\Entity]
#[ORM\Table(name: 'mon_plugin_wishlist_item')]
#[ORM\UniqueConstraint(columns: ['customer_id', 'product_id'])]
class WishlistItem
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\ManyToOne(targetEntity: CustomerInterface::class)]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
private CustomerInterface $customer;
#[ORM\ManyToOne(targetEntity: ProductInterface::class)]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
private ProductInterface $product;
#[ORM\Column(type: 'datetime_immutable')]
private \DateTimeImmutable $createdAt;
public function __construct()
{
$this->createdAt = new \DateTimeImmutable();
}
// Getters et setters...
}
2. Le controller
<?php
// src/Controller/WishlistController.php
namespace MonPlugin\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManagerInterface;
class WishlistController extends AbstractController
{
public function toggle(
int $productId,
EntityManagerInterface $em,
Request $request
): Response {
$customer = $this->getUser()->getCustomer();
$product = $em->getRepository(ProductInterface::class)->find($productId);
$existing = $em->getRepository(WishlistItem::class)->findOneBy([
'customer' => $customer,
'product' => $product,
]);
if ($existing) {
$em->remove($existing);
$this->addFlash('success', 'Produit retire des favoris');
} else {
$item = new WishlistItem();
$item->setCustomer($customer);
$item->setProduct($product);
$em->persist($item);
$this->addFlash('success', 'Produit ajoute aux favoris');
}
$em->flush();
return $this->redirect($request->headers->get('referer', '/'));
}
}
3. Les routes
# src/Resources/config/routes.yaml
mon_plugin_wishlist_toggle:
path: /wishlist/toggle/{productId}
controller: MonPlugin\Controller\WishlistController::toggle
methods: [POST]
requirements:
productId: '\d+'
4. Enregistrer les services
<!-- src/Resources/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services">
<services>
<defaults autowire="true" autoconfigure="true" public="false" />
<prototype namespace="MonPlugin\" resource="../../*"
exclude="../../{Entity,Migrations,Tests}" />
</services>
</container>
5. Ajouter un bouton coeur via Twig Hook
# src/Resources/config/twig_hooks.yaml
sylius_twig_hooks:
hooks:
'sylius_shop.product.show.content':
wishlist_button:
template: '@MonPlugin/Shop/Product/_wishlist_button.html.twig'
priority: 80
{# src/Resources/views/Shop/Product/_wishlist_button.html.twig #}
{% if app.user %}
<form method="post" action="{{ path('mon_plugin_wishlist_toggle', {productId: product.id}) }}">
<input type="hidden" name="_token" value="{{ csrf_token('wishlist') }}">
<button type="submit" class="btn btn-outline-secondary">
{% if is_in_wishlist(product) %}Retirer des favoris{% else %}Ajouter aux favoris{% endif %}
</button>
</form>
{% endif %}
Tester le plugin
# Installer l'application de test
cd tests/Application
composer install
bin/console doctrine:database:create
bin/console doctrine:schema:update --force
bin/console sylius:fixtures:load
# Lancer les tests
cd ../..
vendor/bin/phpunit
Publier sur Packagist
Votre composer.json doit inclure :
{
"name": "monentreprise/sylius-wishlist-plugin",
"type": "sylius-plugin",
"description": "Wishlist/favorites plugin for Sylius",
"require": {
"sylius/sylius": "^2.0"
},
"autoload": {
"psr-4": {
"MonPlugin\\": "src/"
}
}
}
Poussez sur GitHub, enregistrez sur Packagist, et soumettez au Sylius Marketplace.
Besoin d'un plugin Sylius sur mesure pour votre projet ? Contactez-nous. Nous avons developpe des dizaines de plugins pour nos clients. Voir aussi notre guide complet Sylius.
