Colas Mérand
25/05/2025
Symfony
Développement web
UX/UI
5 minutes
Dans un monde numérique où l'attention des utilisateurs est une ressource précieuse, les fonctionnalités d'engagement sont devenues essentielles pour toute application web performante. Parmi ces fonctionnalités, les systèmes de notifications, de partage et de favoris jouent un rôle crucial pour fidéliser les utilisateurs et enrichir leur expérience. Chez Platane, nous avons développé une expertise pointue dans l'implémentation de ces systèmes, particulièrement dans l'écosystème Symfony.
L'intégration d'un système complet de notifications, partage et favoris présente de nombreux avantages :
Un système de notifications efficace doit fonctionner aussi bien pour les utilisateurs connectés que pour les visiteurs anonymes. Voici comment nous l'implémentons généralement :
// NotificationController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Service\NotificationService;
class NotificationController extends AbstractController
{
#[Route('/subscribe', name: 'notification_subscribe', methods: ['POST'])]
public function subscribe(Request $request, NotificationService $notificationService): Response
{
$email = $request->request->get('email');
$sections = $request->request->get('sections', []);
// Validation et traitement
$result = $notificationService->subscribeAnonymous($email, $sections);
return $this->json($result);
}
}
// Dans le même contrôleur
#[Route('/notifications/manage', name: 'notifications_manage')]
public function manageNotifications(): Response
{
$user = $this->getUser();
// Récupération des préférences de notification de l'utilisateur
return $this->render('notifications/manage.html.twig', [
'user' => $user,
'preferences' => $user->getNotificationPreferences(),
]);
}
// Command/SendNotificationsCommand.php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use App\Service\NotificationService;
class SendNotificationsCommand extends Command
{
protected static $defaultName = 'app:send-notifications';
private $notificationService;
public function __construct(NotificationService $notificationService)
{
$this->notificationService = $notificationService;
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln('Sending notifications...');
$this->notificationService->processAndSendNotifications();
$output->writeln('Notifications sent successfully!');
return Command::SUCCESS;
}
}
Le partage social est un excellent moyen d'étendre la portée de votre contenu. Voici comment nous l'implémentons :
// assets/js/share.js
const initShareButtons = () => {
document.querySelectorAll('.share-button').forEach(button => {
button.addEventListener('click', (e) => {
e.preventDefault();
const type = button.dataset.shareType;
const url = encodeURIComponent(window.location.href);
const title = encodeURIComponent(document.title);
let shareUrl;
switch(type) {
case 'facebook':
shareUrl = `https://www.facebook.com/sharer/sharer.php?u=${url}`;
break;
case 'twitter':
shareUrl = `https://twitter.com/intent/tweet?url=${url}&text=${title}`;
break;
case 'linkedin':
shareUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${url}`;
break;
case 'email':
shareUrl = `mailto:?subject=${title}&body=Check out this link: ${url}`;
break;
// Autres plateformes...
}
if (shareUrl) {
window.open(shareUrl, '_blank', 'width=600,height=400');
}
});
});
};
document.addEventListener('DOMContentLoaded', initShareButtons);
La gestion des favoris nécessite une architecture robuste pour stocker et récupérer efficacement les éléments sauvegardés :
// Entity/Favorite.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: FavoriteRepository::class)]
class Favorite
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'favorites')]
#[ORM\JoinColumn(nullable: false)]
private $user;
#[ORM\Column(type: 'string', length: 255)]
private $entityType;
#[ORM\Column(type: 'integer')]
private $entityId;
#[ORM\Column(type: 'datetime')]
private $createdAt;
// Getters and setters...
}
// FavoriteController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Service\FavoriteService;
class FavoriteController extends AbstractController
{
#[Route('/favorite/toggle', name: 'favorite_toggle', methods: ['POST'])]
public function toggleFavorite(Request $request, FavoriteService $favoriteService): Response
{
$this->denyAccessUnlessGranted('ROLE_USER');
$entityType = $request->request->get('entityType');
$entityId = $request->request->get('entityId');
$result = $favoriteService->toggleFavorite($this->getUser(), $entityType, $entityId);
return $this->json($result);
}
#[Route('/favorites', name: 'favorites_list')]
public function listFavorites(FavoriteService $favoriteService): Response
{
$this->denyAccessUnlessGranted('ROLE_USER');
$favorites = $favoriteService->getUserFavorites($this->getUser());
return $this->render('favorites/list.html.twig', [
'favorites' => $favorites,
]);
}
}
Fort de notre expérience sur des projets comme Astory (plateforme de location d'œuvres d'art) et Epictory (génération de posters personnalisés), nous avons identifié plusieurs bonnes pratiques pour l'implémentation de ces systèmes :
// Service/NotificationService.php
public function subscribeAnonymous(string $email, array $sections): array
{
// Génération d'un token unique pour la confirmation
$token = bin2hex(random_bytes(32));
// Stockage temporaire de la demande d'inscription
$this->storeSubscriptionRequest($email, $sections, $token);
// Envoi d'un email de confirmation (double opt-in)
$this->mailer->send(
$email,
'Confirmation de votre inscription aux notifications',
'emails/subscription_confirmation.html.twig',
['token' => $token, 'sections' => $sections]
);
return ['success' => true, 'message' => 'Veuillez confirmer votre inscription en cliquant sur le lien envoyé par email.'];
}
Pour éviter de surcharger votre serveur, utilisez des tâches planifiées pour l'envoi des notifications :
# config/packages/messenger.yaml
framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
'App\Message\NotificationMessage': async
// Security/FavoriteVoter.php
namespace App\Security;
use App\Entity\Favorite;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class FavoriteVoter extends Voter
{
protected function supports(string $attribute, $subject): bool
{
return $attribute === 'MANAGE' && $subject instanceof Favorite;
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof User) {
return false;
}
/** @var Favorite $favorite */
$favorite = $subject;
return $favorite->getUser() === $user;
}
}
L'expérience utilisateur est primordiale. Lors du développement du site du Festival Ouaille Note, nous avons mis l'accent sur une interface simple et intuitive pour la gestion des notifications et des favoris :
{# templates/notifications/manage.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
<div class="container my-5">
<h1>Gérer vos notifications</h1>
<form method="post" action="{{ path('notifications_update') }}">
<div class="card mb-4">
<div class="card-header">Préférences de notification</div>
<div class="card-body">
{% for section in available_sections %}
<div class="form-check mb-3">
<input
type="checkbox"
class="form-check-input"
id="section_{{ section.id }}"
name="sections[]"
value="{{ section.id }}"
{% if section.id in user_preferences %}checked{% endif %}
>
<label class="form-check-label" for="section_{{ section.id }}">
{{ section.name }}
</label>
<small class="text-muted d-block">{{ section.description }}</small>
</div>
{% endfor %}
</div>
</div>
<button type="submit" class="btn btn-primary">Enregistrer les préférences</button>
</form>
</div>
{% endblock %}
Chez Platane, nous avons implémenté ces systèmes dans divers contextes :
Pour Astory, nous avons développé un système de notifications permettant aux collectionneurs d'être alertés lorsque de nouvelles œuvres correspondant à leurs critères sont disponibles à la location. Cette fonctionnalité a contribué à augmenter le taux de conversion de 23%.
Sur Epictory, le système de partage social a permis aux utilisateurs de diffuser leurs posters personnalisés sur les réseaux sociaux, générant un trafic organique significatif et réduisant le coût d'acquisition client.
Pour notre propre plateforme de gestion de contenu, nous avons intégré un système de favoris qui permet aux utilisateurs de sauvegarder des articles pour une lecture ultérieure, augmentant ainsi le temps passé sur la plateforme de 35%.
L'implémentation d'un système de notifications, partage et favoris dans une application Symfony 6.4 représente un investissement stratégique pour améliorer l'engagement utilisateur et la rétention. Bien que techniquement complexe, cette fonctionnalité offre un retour sur investissement significatif en termes d'expérience utilisateur et de croissance de votre plateforme.
Chez Platane, nous combinons expertise technique et vision stratégique pour développer des solutions sur mesure qui répondent précisément aux besoins de nos clients. Notre approche intègre les dernières technologies, comme l'intelligence artificielle générative, pour créer des expériences utilisateur innovantes et performantes.
Vous avez un projet similaire ou souhaitez améliorer l'engagement sur votre plateforme existante ? N'hésitez pas à prendre rendez-vous via notre formulaire de contact. Notre équipe sera ravie d'échanger avec vous sur votre projet et de vous montrer comment notre expertise peut vous aider à atteindre vos objectifs. Collaborer avec Platane, c'est choisir un partenaire qui comprend les enjeux techniques et business de votre projet, pour des résultats concrets et mesurables.