07-notifications-multi-canaux
<?php
interface Notifier {
public function send(string $recipient, string $subject, string $message): bool;
public function sendBulk(array $recipients, string $subject, string $message): array;
public function schedule(string $recipient, string $subject, string $message, DateTime $when): bool;
public function getDeliveryStatus(string $messageId): string;
public function cancelScheduled(string $messageId): bool;
}
class EmailNotifier implements Notifier {
private SMTPConnection $smtp;
public function __construct() {
$this->smtp = new SMTPConnection('smtp.example.com', 587);
$this->smtp->authenticate('user@example.com', 'password');
}
public function send(string $recipient, string $subject, string $message): bool {
return $this->smtp->sendMail($recipient, $subject, $message);
}
public function sendBulk(array $recipients, string $subject, string $message): array {
$results = [];
foreach($recipients as $recipient) {
$results[$recipient] = $this->send($recipient, $subject, $message);
}
return $results;
}
public function schedule(string $recipient, string $subject, string $message, DateTime $when): bool {
$db = new PDO('mysql:host=localhost;dbname=notifications','root','');
$stmt = $db->prepare('INSERT INTO scheduled_emails (recipient,subject,message,send_at) VALUES (?,?,?,?)');
return $stmt->execute([$recipient, $subject, $message, $when->format('Y-m-d H:i:s')]);
}
public function getDeliveryStatus(string $messageId): string {
return $this->smtp->checkStatus($messageId);
}
public function cancelScheduled(string $messageId): bool {
$db = new PDO('mysql:host=localhost;dbname=notifications','root','');
$stmt = $db->prepare('DELETE FROM scheduled_emails WHERE id = ?');
return $stmt->execute([$messageId]);
}
}
class SMSNotifier implements Notifier {
private TwilioClient $client;
public function __construct() {
$this->client = new TwilioClient('account_sid', 'auth_token');
}
public function send(string $recipient, string $subject, string $message): bool {
return $this->client->sendSMS($recipient, $message);
}
public function sendBulk(array $recipients, string $subject, string $message): array {
throw new Exception("SMS bulk sending not supported by Twilio API");
}
public function schedule(string $recipient, string $subject, string $message, DateTime $when): bool {
throw new Exception("SMS scheduling not implemented");
}
public function getDeliveryStatus(string $messageId): string {
return $this->client->getMessageStatus($messageId);
}
public function cancelScheduled(string $messageId): bool {
throw new Exception("Cannot cancel SMS");
}
}
class PushNotifier implements Notifier {
private FirebaseClient $firebase;
public function __construct() {
$this->firebase = new FirebaseClient('firebase_key');
}
public function send(string $recipient, string $subject, string $message): bool {
return $this->firebase->sendNotification($recipient, $subject, $message);
}
public function sendBulk(array $recipients, string $subject, string $message): array {
return $this->firebase->sendToMultiple($recipients, $subject, $message);
}
public function schedule(string $recipient, string $subject, string $message, DateTime $when): bool {
throw new Exception("Push notifications don't support scheduling");
}
public function getDeliveryStatus(string $messageId): string {
throw new Exception("Firebase doesn't provide delivery status");
}
public function cancelScheduled(string $messageId): bool {
throw new Exception("Cannot cancel push notifications");
}
}
class NotificationService {
public function notify(User $user, string $subject, string $message): bool {
$preference = $user->getNotificationPreference();
if($preference === 'email') {
$notifier = new EmailNotifier();
return $notifier->send($user->getEmail(), $subject, $message);
} elseif($preference === 'sms') {
$notifier = new SMSNotifier();
return $notifier->send($user->getPhone(), $subject, $message);
} elseif($preference === 'push') {
$notifier = new PushNotifier();
return $notifier->send($user->getDeviceToken(), $subject, $message);
}
return false;
}
}
class User {
public function getNotificationPreference(): string { return 'email'; }
public function getEmail(): string { return 'user@example.com'; }
public function getPhone(): string { return '+33612345678'; }
public function getDeviceToken(): string { return 'device_token_123'; }
}
class SMTPConnection {
public function __construct(string $host, int $port) { }
public function authenticate(string $user, string $pass): void { }
public function sendMail(string $to, string $subject, string $body): bool { return true; }
public function checkStatus(string $id): string { return 'delivered'; }
}
class TwilioClient {
public function __construct(string $sid, string $token) { }
public function sendSMS(string $to, string $message): bool { return true; }
public function getMessageStatus(string $id): string { return 'sent'; }
}
class FirebaseClient {
public function __construct(string $key) { }
public function sendNotification(string $token, string $title, string $body): bool { return true; }
public function sendToMultiple(array $tokens, string $title, string $body): array { return []; }
}
/*
=== USER STORIES ===
US1: En tant que product owner, je veux ajouter Slack comme canal de notification.
US2: En tant que développeur, je veux tester la logique de NotificationService
sans dépendre des vraies APIs (Twilio, Firebase, SMTP).
US3: En tant que product manager, je veux que les utilisateurs puissent choisir
plusieurs canaux de notification simultanément (email + push par exemple).
US4: En tant que développeur, je veux créer un nouveau notifier Discord sans que
toutes les méthodes de l'interface soient obligatoires.
US5: En tant que compliance officer, je veux tracer toutes les notifications
envoyées dans un système centralisé, quel que soit le canal utilisé.
*/