feat(Deployment): Integrate Ansible deployment via PHP deployment pipeline
- Create AnsibleDeployStage using framework's Process module for secure command execution - Integrate AnsibleDeployStage into DeploymentPipelineCommands for production deployments - Add force_deploy flag support in Ansible playbook to override stale locks - Use PHP deployment module as orchestrator (php console.php deploy:production) - Fix ErrorAggregationInitializer to use Environment class instead of $_ENV superglobal Architecture: - BuildStage → AnsibleDeployStage → HealthCheckStage for production - Process module provides timeout, error handling, and output capture - Ansible playbook supports rollback via rollback-git-based.yml - Zero-downtime deployments with health checks
This commit is contained in:
219
examples/notification-multi-channel-example.php
Normal file
219
examples/notification-multi-channel-example.php
Normal file
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use App\Framework\Notification\Notification;
|
||||
use App\Framework\Notification\NotificationDispatcher;
|
||||
use App\Framework\Notification\Dispatcher\DispatchStrategy;
|
||||
use App\Framework\Notification\ValueObjects\NotificationChannel;
|
||||
use App\Framework\Notification\ValueObjects\NotificationPriority;
|
||||
use App\Framework\Notification\ValueObjects\SystemNotificationType;
|
||||
|
||||
/**
|
||||
* Multi-Channel Notification Dispatch Example
|
||||
*
|
||||
* Demonstrates the four dispatch strategies:
|
||||
* - ALL: Send to all channels regardless of failures
|
||||
* - FIRST_SUCCESS: Stop after first successful delivery
|
||||
* - FALLBACK: Try next only if previous failed
|
||||
* - ALL_OR_NONE: All must succeed or entire dispatch fails
|
||||
*/
|
||||
|
||||
echo "=== Multi-Channel Notification Dispatch Examples ===\n\n";
|
||||
|
||||
// Setup (in real app, get from DI container)
|
||||
$dispatcher = $container->get(NotificationDispatcher::class);
|
||||
|
||||
// Example 1: ALL Strategy - Send to all channels
|
||||
echo "1. ALL Strategy - Send to all channels\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
$notification = Notification::create(
|
||||
recipientId: 'user_123',
|
||||
type: new SystemNotificationType('system.update'),
|
||||
title: 'System Update Available',
|
||||
body: 'A new system update is available. Please review and install.',
|
||||
NotificationChannel::TELEGRAM,
|
||||
NotificationChannel::EMAIL,
|
||||
NotificationChannel::SMS
|
||||
)->withPriority(NotificationPriority::NORMAL);
|
||||
|
||||
$result = $dispatcher->sendNow($notification, DispatchStrategy::ALL);
|
||||
|
||||
echo "Status: " . ($result->isSuccess() ? "✅ SUCCESS" : "❌ FAILURE") . "\n";
|
||||
echo "Successful channels: " . count($result->getSuccessful()) . "\n";
|
||||
echo "Failed channels: " . count($result->getFailed()) . "\n";
|
||||
|
||||
foreach ($result->getSuccessful() as $channelResult) {
|
||||
echo " ✅ {$channelResult->channel->value}: " . json_encode($channelResult->metadata) . "\n";
|
||||
}
|
||||
|
||||
foreach ($result->getFailed() as $channelResult) {
|
||||
echo " ❌ {$channelResult->channel->value}: {$channelResult->errorMessage}\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 2: FIRST_SUCCESS Strategy - Stop after first success
|
||||
echo "2. FIRST_SUCCESS Strategy - Quick delivery\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
$notification = Notification::create(
|
||||
recipientId: 'user_456',
|
||||
type: new SystemNotificationType('order.shipped'),
|
||||
title: 'Your Order Has Shipped',
|
||||
body: 'Your order #12345 has been shipped and is on its way!',
|
||||
NotificationChannel::TELEGRAM, // Try Telegram first
|
||||
NotificationChannel::EMAIL, // Then Email if Telegram fails
|
||||
NotificationChannel::SMS // Then SMS if Email fails
|
||||
)->withPriority(NotificationPriority::HIGH);
|
||||
|
||||
$result = $dispatcher->sendNow($notification, DispatchStrategy::FIRST_SUCCESS);
|
||||
|
||||
echo "Status: " . ($result->isSuccess() ? "✅ SUCCESS" : "❌ FAILURE") . "\n";
|
||||
echo "Delivery stopped after first success\n";
|
||||
echo "Channels attempted: " . (count($result->getSuccessful()) + count($result->getFailed())) . "\n";
|
||||
|
||||
foreach ($result->getSuccessful() as $channelResult) {
|
||||
echo " ✅ {$channelResult->channel->value}: Delivered successfully\n";
|
||||
}
|
||||
|
||||
foreach ($result->getFailed() as $channelResult) {
|
||||
echo " ❌ {$channelResult->channel->value}: {$channelResult->errorMessage}\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 3: FALLBACK Strategy - Telegram -> Email -> SMS chain
|
||||
echo "3. FALLBACK Strategy - Graceful degradation\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
$notification = Notification::create(
|
||||
recipientId: 'user_789',
|
||||
type: new SystemNotificationType('security.alert'),
|
||||
title: 'Security Alert',
|
||||
body: 'Unusual login activity detected on your account.',
|
||||
NotificationChannel::TELEGRAM, // Primary: Telegram (instant)
|
||||
NotificationChannel::EMAIL, // Fallback 1: Email (reliable)
|
||||
NotificationChannel::SMS // Fallback 2: SMS (last resort)
|
||||
)->withPriority(NotificationPriority::URGENT);
|
||||
|
||||
$result = $dispatcher->sendNow($notification, DispatchStrategy::FALLBACK);
|
||||
|
||||
echo "Status: " . ($result->isSuccess() ? "✅ SUCCESS" : "❌ FAILURE") . "\n";
|
||||
echo "Fallback chain executed\n";
|
||||
|
||||
foreach ($result->getSuccessful() as $channelResult) {
|
||||
echo " ✅ {$channelResult->channel->value}: Delivered (fallback stopped here)\n";
|
||||
}
|
||||
|
||||
foreach ($result->getFailed() as $channelResult) {
|
||||
echo " ❌ {$channelResult->channel->value}: Failed, tried next channel\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 4: ALL_OR_NONE Strategy - Critical notifications
|
||||
echo "4. ALL_OR_NONE Strategy - All must succeed\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
$notification = Notification::create(
|
||||
recipientId: 'user_101',
|
||||
type: new SystemNotificationType('account.deleted'),
|
||||
title: 'Account Deletion Confirmation',
|
||||
body: 'Your account has been permanently deleted as requested.',
|
||||
NotificationChannel::EMAIL,
|
||||
NotificationChannel::SMS
|
||||
)->withPriority(NotificationPriority::URGENT);
|
||||
|
||||
$result = $dispatcher->sendNow($notification, DispatchStrategy::ALL_OR_NONE);
|
||||
|
||||
echo "Status: " . ($result->isSuccess() ? "✅ ALL SUCCEEDED" : "❌ STOPPED ON FIRST FAILURE") . "\n";
|
||||
echo "Successful channels: " . count($result->getSuccessful()) . "\n";
|
||||
echo "Failed channels: " . count($result->getFailed()) . "\n";
|
||||
|
||||
if ($result->isFailure()) {
|
||||
echo "⚠️ Critical notification failed - some channels did not receive the message\n";
|
||||
}
|
||||
|
||||
foreach ($result->getSuccessful() as $channelResult) {
|
||||
echo " ✅ {$channelResult->channel->value}: Delivered\n";
|
||||
}
|
||||
|
||||
foreach ($result->getFailed() as $channelResult) {
|
||||
echo " ❌ {$channelResult->channel->value}: {$channelResult->errorMessage}\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 5: Async Multi-Channel with Strategy
|
||||
echo "5. Async Multi-Channel Dispatch\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
$notification = Notification::create(
|
||||
recipientId: 'user_202',
|
||||
type: new SystemNotificationType('newsletter.weekly'),
|
||||
title: 'Your Weekly Newsletter',
|
||||
body: 'Check out this week\'s highlights and updates.',
|
||||
NotificationChannel::EMAIL,
|
||||
NotificationChannel::TELEGRAM
|
||||
)->withPriority(NotificationPriority::LOW);
|
||||
|
||||
// Async dispatch - queued with priority mapping
|
||||
$dispatcher->send($notification, async: true, strategy: DispatchStrategy::ALL);
|
||||
|
||||
echo "✅ Notification queued for async dispatch\n";
|
||||
echo "Strategy: ALL (will attempt all channels in background)\n";
|
||||
echo "Priority: LOW (mapped to queue priority)\n";
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 6: Strategy Selection Based on Priority
|
||||
echo "6. Dynamic Strategy Selection\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
function selectStrategy(NotificationPriority $priority): DispatchStrategy
|
||||
{
|
||||
return match ($priority) {
|
||||
NotificationPriority::URGENT => DispatchStrategy::ALL_OR_NONE, // Critical: all must succeed
|
||||
NotificationPriority::HIGH => DispatchStrategy::FIRST_SUCCESS, // Quick delivery
|
||||
NotificationPriority::NORMAL => DispatchStrategy::FALLBACK, // Graceful degradation
|
||||
NotificationPriority::LOW => DispatchStrategy::ALL, // Best effort
|
||||
};
|
||||
}
|
||||
|
||||
$urgentNotification = Notification::create(
|
||||
recipientId: 'user_303',
|
||||
type: new SystemNotificationType('payment.failed'),
|
||||
title: 'Payment Failed',
|
||||
body: 'Your payment could not be processed.',
|
||||
NotificationChannel::EMAIL,
|
||||
NotificationChannel::SMS
|
||||
)->withPriority(NotificationPriority::URGENT);
|
||||
|
||||
$strategy = selectStrategy($urgentNotification->priority);
|
||||
echo "Priority: {$urgentNotification->priority->value}\n";
|
||||
echo "Selected Strategy: {$strategy->value}\n";
|
||||
|
||||
$result = $dispatcher->sendNow($urgentNotification, $strategy);
|
||||
echo "Result: " . ($result->isSuccess() ? "✅ SUCCESS" : "❌ FAILURE") . "\n";
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Summary
|
||||
echo "=== Strategy Summary ===\n";
|
||||
echo "ALL: Send to all channels, continue even if some fail\n";
|
||||
echo " Use case: Non-critical updates, newsletters, marketing\n\n";
|
||||
|
||||
echo "FIRST_SUCCESS: Stop after first successful delivery\n";
|
||||
echo " Use case: Time-sensitive notifications, quick delivery needed\n\n";
|
||||
|
||||
echo "FALLBACK: Try next only if previous failed\n";
|
||||
echo " Use case: Graceful degradation, Telegram -> Email -> SMS chain\n\n";
|
||||
|
||||
echo "ALL_OR_NONE: All must succeed or entire dispatch fails\n";
|
||||
echo " Use case: Critical notifications, legal compliance, account actions\n\n";
|
||||
|
||||
echo "✅ Multi-channel dispatch examples completed\n";
|
||||
283
examples/notification-rich-media-example.php
Normal file
283
examples/notification-rich-media-example.php
Normal file
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use App\Framework\Core\AppBootstrapper;
|
||||
use App\Framework\Notification\Channels\TelegramChannel;
|
||||
use App\Framework\Notification\Media\MediaManager;
|
||||
use App\Framework\Notification\ValueObjects\NotificationChannel;
|
||||
use App\Framework\Notification\Notification;
|
||||
|
||||
/**
|
||||
* Rich Media Notification Example
|
||||
*
|
||||
* Demonstrates the MediaManager system for sending notifications with:
|
||||
* - Photos
|
||||
* - Videos
|
||||
* - Audio files
|
||||
* - Documents
|
||||
* - Location data
|
||||
*/
|
||||
|
||||
echo "🎨 Rich Media Notification System Example\n";
|
||||
echo "==========================================\n\n";
|
||||
|
||||
// Bootstrap application
|
||||
$app = AppBootstrapper::bootstrap();
|
||||
$container = $app->getContainer();
|
||||
|
||||
// Get TelegramChannel with injected MediaManager
|
||||
$telegramChannel = $container->get(TelegramChannel::class);
|
||||
$mediaManager = $telegramChannel->mediaManager;
|
||||
|
||||
// Create sample notification
|
||||
$notification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Rich Media Test',
|
||||
body: 'Testing media capabilities',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'media_test'
|
||||
);
|
||||
|
||||
echo "📋 Testing MediaManager Capabilities\n";
|
||||
echo "------------------------------------\n\n";
|
||||
|
||||
// 1. Check Telegram capabilities
|
||||
echo "1️⃣ Checking Telegram channel capabilities...\n";
|
||||
|
||||
$capabilities = $mediaManager->getCapabilities(NotificationChannel::TELEGRAM);
|
||||
|
||||
echo " Supported media types:\n";
|
||||
echo " - Photos: " . ($capabilities->supportsPhoto ? '✅' : '❌') . "\n";
|
||||
echo " - Videos: " . ($capabilities->supportsVideo ? '✅' : '❌') . "\n";
|
||||
echo " - Audio: " . ($capabilities->supportsAudio ? '✅' : '❌') . "\n";
|
||||
echo " - Documents: " . ($capabilities->supportsDocument ? '✅' : '❌') . "\n";
|
||||
echo " - Location: " . ($capabilities->supportsLocation ? '✅' : '❌') . "\n";
|
||||
echo " - Voice: " . ($capabilities->supportsVoice ? '✅' : '❌') . "\n\n";
|
||||
|
||||
// 2. Test photo support
|
||||
echo "2️⃣ Testing photo support...\n";
|
||||
|
||||
if ($mediaManager->supportsPhoto(NotificationChannel::TELEGRAM)) {
|
||||
echo " ✅ Telegram supports photos\n";
|
||||
|
||||
// Example: Send photo with caption
|
||||
try {
|
||||
$photoNotification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Photo Notification',
|
||||
body: 'Check out this image!',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'photo_test'
|
||||
);
|
||||
|
||||
// Note: In real usage, you would provide a valid file path or Telegram file_id
|
||||
// $mediaManager->sendPhoto(
|
||||
// NotificationChannel::TELEGRAM,
|
||||
// $photoNotification,
|
||||
// photoPath: '/path/to/image.jpg',
|
||||
// caption: 'Beautiful landscape photo'
|
||||
// );
|
||||
|
||||
echo " 📸 Photo sending method available\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ Photo test skipped: {$e->getMessage()}\n";
|
||||
}
|
||||
} else {
|
||||
echo " ❌ Telegram does not support photos\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// 3. Test video support
|
||||
echo "3️⃣ Testing video support...\n";
|
||||
|
||||
if ($mediaManager->supportsVideo(NotificationChannel::TELEGRAM)) {
|
||||
echo " ✅ Telegram supports videos\n";
|
||||
|
||||
// Example: Send video with thumbnail
|
||||
try {
|
||||
$videoNotification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Video Notification',
|
||||
body: 'Watch this video!',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'video_test'
|
||||
);
|
||||
|
||||
// Note: In real usage, you would provide valid file paths
|
||||
// $mediaManager->sendVideo(
|
||||
// NotificationChannel::TELEGRAM,
|
||||
// $videoNotification,
|
||||
// videoPath: '/path/to/video.mp4',
|
||||
// caption: 'Tutorial video',
|
||||
// thumbnailPath: '/path/to/thumbnail.jpg'
|
||||
// );
|
||||
|
||||
echo " 🎥 Video sending method available\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ Video test skipped: {$e->getMessage()}\n";
|
||||
}
|
||||
} else {
|
||||
echo " ❌ Telegram does not support videos\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// 4. Test audio support
|
||||
echo "4️⃣ Testing audio support...\n";
|
||||
|
||||
if ($mediaManager->supportsAudio(NotificationChannel::TELEGRAM)) {
|
||||
echo " ✅ Telegram supports audio\n";
|
||||
|
||||
// Example: Send audio file
|
||||
try {
|
||||
$audioNotification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Audio Notification',
|
||||
body: 'Listen to this audio!',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'audio_test'
|
||||
);
|
||||
|
||||
// Note: In real usage, you would provide a valid audio file
|
||||
// $mediaManager->sendAudio(
|
||||
// NotificationChannel::TELEGRAM,
|
||||
// $audioNotification,
|
||||
// audioPath: '/path/to/audio.mp3',
|
||||
// caption: 'Podcast episode',
|
||||
// duration: 300 // 5 minutes
|
||||
// );
|
||||
|
||||
echo " 🎵 Audio sending method available\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ Audio test skipped: {$e->getMessage()}\n";
|
||||
}
|
||||
} else {
|
||||
echo " ❌ Telegram does not support audio\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// 5. Test document support
|
||||
echo "5️⃣ Testing document support...\n";
|
||||
|
||||
if ($mediaManager->supportsDocument(NotificationChannel::TELEGRAM)) {
|
||||
echo " ✅ Telegram supports documents\n";
|
||||
|
||||
// Example: Send document
|
||||
try {
|
||||
$documentNotification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Document Notification',
|
||||
body: 'Here is your document!',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'document_test'
|
||||
);
|
||||
|
||||
// Note: In real usage, you would provide a valid document
|
||||
// $mediaManager->sendDocument(
|
||||
// NotificationChannel::TELEGRAM,
|
||||
// $documentNotification,
|
||||
// documentPath: '/path/to/document.pdf',
|
||||
// caption: 'Monthly report',
|
||||
// filename: 'Report_2024.pdf'
|
||||
// );
|
||||
|
||||
echo " 📄 Document sending method available\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ Document test skipped: {$e->getMessage()}\n";
|
||||
}
|
||||
} else {
|
||||
echo " ❌ Telegram does not support documents\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// 6. Test location support
|
||||
echo "6️⃣ Testing location support...\n";
|
||||
|
||||
if ($mediaManager->supportsLocation(NotificationChannel::TELEGRAM)) {
|
||||
echo " ✅ Telegram supports location sharing\n";
|
||||
|
||||
// Example: Send location
|
||||
try {
|
||||
$locationNotification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Location Notification',
|
||||
body: 'Meet me here!',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'location_test'
|
||||
);
|
||||
|
||||
// Note: In real usage, you would provide actual coordinates
|
||||
// $mediaManager->sendLocation(
|
||||
// NotificationChannel::TELEGRAM,
|
||||
// $locationNotification,
|
||||
// latitude: 52.5200, // Berlin
|
||||
// longitude: 13.4050,
|
||||
// title: 'Meeting Point',
|
||||
// address: 'Brandenburger Tor, Berlin'
|
||||
// );
|
||||
|
||||
echo " 📍 Location sending method available\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ Location test skipped: {$e->getMessage()}\n";
|
||||
}
|
||||
} else {
|
||||
echo " ❌ Telegram does not support location sharing\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// 7. Test error handling for unsupported channel
|
||||
echo "7️⃣ Testing error handling for unsupported channel...\n";
|
||||
|
||||
try {
|
||||
// Try to check capabilities for a channel without registered driver
|
||||
$emailCapabilities = $mediaManager->getCapabilities(NotificationChannel::EMAIL);
|
||||
|
||||
if (!$emailCapabilities->hasAnyMediaSupport()) {
|
||||
echo " ✅ Email channel has no media support (as expected)\n";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ Expected behavior: {$e->getMessage()}\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// 8. Demonstrate runtime capability checking
|
||||
echo "8️⃣ Runtime capability checking pattern...\n";
|
||||
|
||||
$testChannel = NotificationChannel::TELEGRAM;
|
||||
|
||||
echo " Example: Sending media with runtime checks\n";
|
||||
echo " \n";
|
||||
echo " if (\$mediaManager->supportsPhoto(\$channel)) {\n";
|
||||
echo " \$mediaManager->sendPhoto(\$channel, \$notification, \$photoPath);\n";
|
||||
echo " } else {\n";
|
||||
echo " // Fallback to text-only notification\n";
|
||||
echo " \$channel->send(\$notification);\n";
|
||||
echo " }\n";
|
||||
echo "\n";
|
||||
|
||||
// Summary
|
||||
echo "✅ Rich Media System Summary\n";
|
||||
echo "============================\n\n";
|
||||
|
||||
echo "Architecture:\n";
|
||||
echo "- MediaManager: Central management with driver registration\n";
|
||||
echo "- MediaDriver: Marker interface with atomic capability interfaces\n";
|
||||
echo "- Atomic Interfaces: SupportsPhotoAttachments, SupportsVideoAttachments, etc.\n";
|
||||
echo "- TelegramMediaDriver: Full media support implementation\n\n";
|
||||
|
||||
echo "Key Features:\n";
|
||||
echo "- ✅ Runtime capability detection via instanceof\n";
|
||||
echo "- ✅ Type-safe media sending with validation\n";
|
||||
echo "- ✅ Optional media support per channel\n";
|
||||
echo "- ✅ Public MediaManager property on channels\n";
|
||||
echo "- ✅ Graceful degradation for unsupported features\n\n";
|
||||
|
||||
echo "Usage:\n";
|
||||
echo "1. Access MediaManager via channel: \$channel->mediaManager\n";
|
||||
echo "2. Check capabilities before sending: \$mediaManager->supportsPhoto(\$channel)\n";
|
||||
echo "3. Send media with validation: \$mediaManager->sendPhoto(...)\n";
|
||||
echo "4. Handle unsupported media gracefully with fallbacks\n\n";
|
||||
|
||||
echo "✨ Example completed successfully!\n";
|
||||
309
examples/notification-template-example.php
Normal file
309
examples/notification-template-example.php
Normal file
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use App\Framework\Notification\Templates\NotificationTemplate;
|
||||
use App\Framework\Notification\Templates\TemplateRenderer;
|
||||
use App\Framework\Notification\Templates\ChannelTemplate;
|
||||
use App\Framework\Notification\Templates\InMemoryTemplateRegistry;
|
||||
use App\Framework\Notification\ValueObjects\NotificationChannel;
|
||||
use App\Framework\Notification\ValueObjects\NotificationPriority;
|
||||
use App\Framework\Notification\ValueObjects\SystemNotificationType;
|
||||
|
||||
/**
|
||||
* Notification Template System Example
|
||||
*
|
||||
* Demonstrates:
|
||||
* - Template creation with placeholders
|
||||
* - Variable substitution
|
||||
* - Per-channel customization
|
||||
* - Template registry
|
||||
* - Required and default variables
|
||||
*/
|
||||
|
||||
echo "=== Notification Template System Examples ===\n\n";
|
||||
|
||||
// Setup
|
||||
$registry = new InMemoryTemplateRegistry();
|
||||
$renderer = new TemplateRenderer();
|
||||
|
||||
// Example 1: Basic Template with Simple Placeholders
|
||||
echo "1. Basic Template - Order Shipped\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
$orderShippedTemplate = NotificationTemplate::create(
|
||||
name: 'order.shipped',
|
||||
titleTemplate: 'Order {{order_id}} Shipped',
|
||||
bodyTemplate: 'Your order {{order_id}} has been shipped and will arrive by {{delivery_date}}. Track your package: {{tracking_url}}'
|
||||
)->withPriority(NotificationPriority::HIGH)
|
||||
->withRequiredVariables('order_id', 'delivery_date', 'tracking_url');
|
||||
|
||||
$registry->register($orderShippedTemplate);
|
||||
|
||||
// Render notification
|
||||
$notification = $renderer->render(
|
||||
template: $orderShippedTemplate,
|
||||
recipientId: 'user_123',
|
||||
variables: [
|
||||
'order_id' => '#12345',
|
||||
'delivery_date' => 'December 25, 2024',
|
||||
'tracking_url' => 'https://example.com/track/ABC123',
|
||||
],
|
||||
channels: [NotificationChannel::EMAIL, NotificationChannel::TELEGRAM],
|
||||
type: new SystemNotificationType('order.shipped')
|
||||
);
|
||||
|
||||
echo "Title: {$notification->title}\n";
|
||||
echo "Body: {$notification->body}\n";
|
||||
echo "Priority: {$notification->priority->value}\n";
|
||||
echo "Template Data: " . json_encode($notification->data, JSON_PRETTY_PRINT) . "\n";
|
||||
echo "\n";
|
||||
|
||||
// Example 2: Template with Nested Variables
|
||||
echo "2. Nested Variables - User Welcome\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
$welcomeTemplate = NotificationTemplate::create(
|
||||
name: 'user.welcome',
|
||||
titleTemplate: 'Welcome to {{app.name}}, {{user.name}}!',
|
||||
bodyTemplate: 'Hi {{user.name}}, welcome to {{app.name}}! Your account has been created successfully. Get started here: {{app.url}}'
|
||||
)->withRequiredVariables('user.name')
|
||||
->withDefaultVariables([
|
||||
'app' => [
|
||||
'name' => 'My Application',
|
||||
'url' => 'https://example.com/start',
|
||||
],
|
||||
]);
|
||||
|
||||
$registry->register($welcomeTemplate);
|
||||
|
||||
$notification = $renderer->render(
|
||||
template: $welcomeTemplate,
|
||||
recipientId: 'user_456',
|
||||
variables: [
|
||||
'user' => [
|
||||
'name' => 'John Doe',
|
||||
'email' => 'john@example.com',
|
||||
],
|
||||
],
|
||||
channels: [NotificationChannel::EMAIL],
|
||||
type: new SystemNotificationType('user.welcome')
|
||||
);
|
||||
|
||||
echo "Title: {$notification->title}\n";
|
||||
echo "Body: {$notification->body}\n";
|
||||
echo "\n";
|
||||
|
||||
// Example 3: Per-Channel Customization
|
||||
echo "3. Per-Channel Templates - Different Formats\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
$securityAlertTemplate = NotificationTemplate::create(
|
||||
name: 'security.alert',
|
||||
titleTemplate: 'Security Alert',
|
||||
bodyTemplate: 'Unusual login activity detected from {{ip_address}} at {{time}}.'
|
||||
)->withPriority(NotificationPriority::URGENT);
|
||||
|
||||
// Telegram: Use Markdown formatting
|
||||
$telegramTemplate = ChannelTemplate::create(
|
||||
titleTemplate: '🔒 *Security Alert*',
|
||||
bodyTemplate: '⚠️ Unusual login activity detected:\n\n📍 IP: `{{ip_address}}`\n⏰ Time: {{time}}\n\nIf this wasn\'t you, secure your account immediately!'
|
||||
)->withMetadata(['parse_mode' => 'Markdown']);
|
||||
|
||||
// Email: Use HTML formatting
|
||||
$emailTemplate = ChannelTemplate::create(
|
||||
titleTemplate: '🔒 Security Alert',
|
||||
bodyTemplate: '<h2>Unusual Login Activity</h2><p>We detected a login from <strong>{{ip_address}}</strong> at {{time}}.</p><p>If this wasn\'t you, please secure your account immediately.</p>'
|
||||
)->withMetadata(['content_type' => 'text/html']);
|
||||
|
||||
// SMS: Keep it short and plain
|
||||
$smsTemplate = ChannelTemplate::create(
|
||||
bodyTemplate: 'SECURITY ALERT: Login from {{ip_address}} at {{time}}. If not you, secure account now.'
|
||||
);
|
||||
|
||||
$securityAlertTemplate = $securityAlertTemplate
|
||||
->withChannelTemplate(NotificationChannel::TELEGRAM, $telegramTemplate)
|
||||
->withChannelTemplate(NotificationChannel::EMAIL, $emailTemplate)
|
||||
->withChannelTemplate(NotificationChannel::SMS, $smsTemplate);
|
||||
|
||||
$registry->register($securityAlertTemplate);
|
||||
|
||||
// Render for each channel
|
||||
$variables = [
|
||||
'ip_address' => '203.0.113.42',
|
||||
'time' => '2024-12-19 15:30:00 UTC',
|
||||
];
|
||||
|
||||
echo "TELEGRAM VERSION:\n";
|
||||
$telegramContent = $renderer->renderForChannel(
|
||||
$securityAlertTemplate,
|
||||
NotificationChannel::TELEGRAM,
|
||||
$variables
|
||||
);
|
||||
echo "Title: {$telegramContent->title}\n";
|
||||
echo "Body:\n{$telegramContent->body}\n";
|
||||
echo "Metadata: " . json_encode($telegramContent->metadata) . "\n\n";
|
||||
|
||||
echo "EMAIL VERSION:\n";
|
||||
$emailContent = $renderer->renderForChannel(
|
||||
$securityAlertTemplate,
|
||||
NotificationChannel::EMAIL,
|
||||
$variables
|
||||
);
|
||||
echo "Title: {$emailContent->title}\n";
|
||||
echo "Body:\n{$emailContent->body}\n";
|
||||
echo "Metadata: " . json_encode($emailContent->metadata) . "\n\n";
|
||||
|
||||
echo "SMS VERSION:\n";
|
||||
$smsContent = $renderer->renderForChannel(
|
||||
$securityAlertTemplate,
|
||||
NotificationChannel::SMS,
|
||||
$variables
|
||||
);
|
||||
echo "Body: {$smsContent->body}\n";
|
||||
echo "\n";
|
||||
|
||||
// Example 4: Template with Default Variables
|
||||
echo "4. Default Variables - Newsletter Template\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
$newsletterTemplate = NotificationTemplate::create(
|
||||
name: 'newsletter.weekly',
|
||||
titleTemplate: '{{newsletter.title}} - Week {{week_number}}',
|
||||
bodyTemplate: 'Hi {{user.name}}, here\'s your weekly {{newsletter.title}}! This week\'s highlights: {{highlights}}. Read more: {{newsletter.url}}'
|
||||
)->withDefaultVariables([
|
||||
'newsletter' => [
|
||||
'title' => 'Weekly Update',
|
||||
'url' => 'https://example.com/newsletter',
|
||||
],
|
||||
'highlights' => 'New features, bug fixes, and improvements',
|
||||
])->withRequiredVariables('user.name', 'week_number');
|
||||
|
||||
$registry->register($newsletterTemplate);
|
||||
|
||||
$notification = $renderer->render(
|
||||
template: $newsletterTemplate,
|
||||
recipientId: 'user_789',
|
||||
variables: [
|
||||
'user' => ['name' => 'Jane Smith'],
|
||||
'week_number' => '51',
|
||||
// Using default values for newsletter and highlights
|
||||
],
|
||||
channels: [NotificationChannel::EMAIL],
|
||||
type: new SystemNotificationType('newsletter.weekly')
|
||||
);
|
||||
|
||||
echo "Title: {$notification->title}\n";
|
||||
echo "Body: {$notification->body}\n";
|
||||
echo "\n";
|
||||
|
||||
// Example 5: Template Registry Usage
|
||||
echo "5. Template Registry - Lookup and Reuse\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
echo "Registered templates:\n";
|
||||
foreach ($registry->all() as $name => $template) {
|
||||
echo " - {$name} (Priority: {$template->defaultPriority->value})\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Reuse template from registry
|
||||
$template = $registry->get('order.shipped');
|
||||
if ($template !== null) {
|
||||
echo "Retrieved template: {$template->name}\n";
|
||||
echo "Required variables: " . implode(', ', $template->requiredVariables) . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Example 6: Error Handling - Missing Required Variable
|
||||
echo "6. Error Handling - Validation\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
try {
|
||||
$renderer->render(
|
||||
template: $orderShippedTemplate,
|
||||
recipientId: 'user_999',
|
||||
variables: [
|
||||
'order_id' => '#67890',
|
||||
// Missing 'delivery_date' and 'tracking_url'
|
||||
],
|
||||
channels: [NotificationChannel::EMAIL],
|
||||
type: new SystemNotificationType('order.shipped')
|
||||
);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
echo "❌ Validation Error: {$e->getMessage()}\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Example 7: Complex Object in Variables
|
||||
echo "7. Complex Objects - Value Object Support\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
$paymentTemplate = NotificationTemplate::create(
|
||||
name: 'payment.received',
|
||||
titleTemplate: 'Payment Received',
|
||||
bodyTemplate: 'We received your payment of {{amount}} on {{date}}. Transaction ID: {{transaction.id}}'
|
||||
);
|
||||
|
||||
// Create notification with object variables
|
||||
$notification = $renderer->render(
|
||||
template: $paymentTemplate,
|
||||
recipientId: 'user_101',
|
||||
variables: [
|
||||
'amount' => '$99.00',
|
||||
'date' => '2024-12-19',
|
||||
'transaction' => [
|
||||
'id' => 'TXN_123456',
|
||||
'status' => 'completed',
|
||||
],
|
||||
],
|
||||
channels: [NotificationChannel::EMAIL, NotificationChannel::TELEGRAM],
|
||||
type: new SystemNotificationType('payment.received')
|
||||
);
|
||||
|
||||
echo "Title: {$notification->title}\n";
|
||||
echo "Body: {$notification->body}\n";
|
||||
echo "\n";
|
||||
|
||||
// Example 8: Integration with NotificationDispatcher
|
||||
echo "8. Template + Dispatcher Integration\n";
|
||||
echo str_repeat("-", 50) . "\n";
|
||||
|
||||
echo "Step 1: Create template\n";
|
||||
$template = NotificationTemplate::create(
|
||||
name: 'account.deleted',
|
||||
titleTemplate: 'Account Deletion Confirmation',
|
||||
bodyTemplate: 'Your account {{username}} has been permanently deleted on {{deletion_date}}.'
|
||||
)->withPriority(NotificationPriority::URGENT);
|
||||
|
||||
echo "Step 2: Render notification from template\n";
|
||||
$notification = $renderer->render(
|
||||
template: $template,
|
||||
recipientId: 'user_202',
|
||||
variables: [
|
||||
'username' => 'johndoe',
|
||||
'deletion_date' => '2024-12-19',
|
||||
],
|
||||
channels: [NotificationChannel::EMAIL, NotificationChannel::SMS],
|
||||
type: new SystemNotificationType('account.deleted')
|
||||
);
|
||||
|
||||
echo "Step 3: Dispatch via NotificationDispatcher\n";
|
||||
echo " (In real app: \$dispatcher->sendNow(\$notification, DispatchStrategy::ALL_OR_NONE))\n";
|
||||
echo " Notification ready for dispatch:\n";
|
||||
echo " - Title: {$notification->title}\n";
|
||||
echo " - Channels: " . count($notification->channels) . "\n";
|
||||
echo " - Priority: {$notification->priority->value}\n";
|
||||
echo "\n";
|
||||
|
||||
// Summary
|
||||
echo "=== Template System Summary ===\n";
|
||||
echo "✅ Created " . count($registry->all()) . " templates\n";
|
||||
echo "✅ Demonstrated placeholder substitution ({{variable}})\n";
|
||||
echo "✅ Demonstrated nested variables ({{user.name}})\n";
|
||||
echo "✅ Demonstrated per-channel customization\n";
|
||||
echo "✅ Demonstrated default variables\n";
|
||||
echo "✅ Demonstrated validation and error handling\n";
|
||||
echo "✅ Template system ready for production use\n";
|
||||
192
examples/scheduled-job-example.php
Normal file
192
examples/scheduled-job-example.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use App\Framework\Worker\Every;
|
||||
use App\Framework\Worker\Schedule;
|
||||
|
||||
/**
|
||||
* Example: Scheduled Job that runs every 5 minutes
|
||||
*
|
||||
* The #[Schedule] attribute marks this class for automatic registration
|
||||
* with the Worker's scheduler system.
|
||||
*
|
||||
* The Worker will:
|
||||
* 1. Discover this class via ScheduleDiscoveryService on startup
|
||||
* 2. Register it with SchedulerService using an IntervalSchedule
|
||||
* 3. Execute the handle() method every 5 minutes
|
||||
*/
|
||||
#[Schedule(at: new Every(minutes: 5))]
|
||||
final class CleanupTempFilesJob
|
||||
{
|
||||
/**
|
||||
* This method is called by the scheduler when the job is due
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Running CleanupTempFilesJob\n";
|
||||
|
||||
// Your cleanup logic here
|
||||
$deletedFiles = $this->cleanupOldTempFiles();
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'deleted_files' => $deletedFiles,
|
||||
'executed_at' => time()
|
||||
];
|
||||
}
|
||||
|
||||
private function cleanupOldTempFiles(): int
|
||||
{
|
||||
// Example cleanup logic
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$deletedCount = 0;
|
||||
|
||||
// Delete files older than 1 hour
|
||||
$files = glob($tempDir . '/*.tmp');
|
||||
foreach ($files as $file) {
|
||||
if (file_exists($file) && (time() - filemtime($file)) > 3600) {
|
||||
unlink($file);
|
||||
$deletedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return $deletedCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Hourly data aggregation job
|
||||
*
|
||||
* This job runs every hour and aggregates analytics data
|
||||
*/
|
||||
#[Schedule(at: new Every(hours: 1))]
|
||||
final class AggregateAnalyticsJob
|
||||
{
|
||||
public function handle(): array
|
||||
{
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Running AggregateAnalyticsJob\n";
|
||||
|
||||
// Your aggregation logic here
|
||||
$recordsProcessed = $this->aggregateLastHourData();
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'records_processed' => $recordsProcessed,
|
||||
'executed_at' => time()
|
||||
];
|
||||
}
|
||||
|
||||
private function aggregateLastHourData(): int
|
||||
{
|
||||
// Example aggregation logic
|
||||
return rand(100, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Daily backup job
|
||||
*
|
||||
* This job runs once per day
|
||||
*/
|
||||
#[Schedule(at: new Every(days: 1))]
|
||||
final class DailyBackupJob
|
||||
{
|
||||
public function handle(): array
|
||||
{
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Running DailyBackupJob\n";
|
||||
|
||||
// Your backup logic here
|
||||
$backupSize = $this->createDatabaseBackup();
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'backup_size_mb' => $backupSize,
|
||||
'executed_at' => time()
|
||||
];
|
||||
}
|
||||
|
||||
private function createDatabaseBackup(): float
|
||||
{
|
||||
// Example backup logic
|
||||
return round(rand(50, 200) / 10, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Callable job (using __invoke)
|
||||
*
|
||||
* Jobs can also be callable instead of using handle() method
|
||||
*/
|
||||
#[Schedule(at: new Every(minutes: 10))]
|
||||
final class MonitorSystemHealthJob
|
||||
{
|
||||
public function __invoke(): string
|
||||
{
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Running MonitorSystemHealthJob\n";
|
||||
|
||||
$memoryUsage = memory_get_usage(true) / 1024 / 1024;
|
||||
$cpuLoad = sys_getloadavg()[0];
|
||||
|
||||
return "System healthy - Memory: {$memoryUsage}MB, CPU Load: {$cpuLoad}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Complex schedule with multiple time units
|
||||
*/
|
||||
#[Schedule(at: new Every(days: 1, hours: 2, minutes: 30))]
|
||||
final class WeeklyReportJob
|
||||
{
|
||||
public function handle(): array
|
||||
{
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Running WeeklyReportJob\n";
|
||||
|
||||
// This runs every 1 day, 2 hours, 30 minutes
|
||||
// Total: (1 * 86400) + (2 * 3600) + (30 * 60) = 94200 seconds
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'report_generated' => true,
|
||||
'executed_at' => time()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo <<<'INFO'
|
||||
=== Scheduled Jobs Example ===
|
||||
|
||||
This example shows how to create scheduled jobs using the #[Schedule] attribute.
|
||||
|
||||
How it works:
|
||||
1. Mark your job class with #[Schedule(at: new Every(...))]
|
||||
2. Implement either a handle() method or make your class callable (__invoke)
|
||||
3. The Worker will automatically discover and register your job on startup
|
||||
4. The job will execute at the specified interval
|
||||
|
||||
Available Every time units:
|
||||
- Every(days: 1) - Run once per day
|
||||
- Every(hours: 1) - Run once per hour
|
||||
- Every(minutes: 5) - Run every 5 minutes
|
||||
- Every(seconds: 30) - Run every 30 seconds
|
||||
- Combine multiple units: Every(days: 1, hours: 2, minutes: 30)
|
||||
|
||||
Task ID Generation:
|
||||
Job class names are automatically converted to kebab-case task IDs:
|
||||
- CleanupTempFilesJob -> cleanup-temp-files-job
|
||||
- AggregateAnalyticsJob -> aggregate-analytics-job
|
||||
- DailyBackupJob -> daily-backup-job
|
||||
|
||||
Starting the Worker:
|
||||
To run these scheduled jobs, start the Worker:
|
||||
docker exec php php console.php worker:start
|
||||
|
||||
The Worker will:
|
||||
- Discover all classes with #[Schedule] attribute
|
||||
- Register them with the SchedulerService
|
||||
- Check for due tasks every 10 seconds
|
||||
- Execute tasks and log results
|
||||
|
||||
INFO;
|
||||
212
examples/send-telegram-media-example.php
Normal file
212
examples/send-telegram-media-example.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use App\Framework\Core\AppBootstrapper;
|
||||
use App\Framework\Notification\Channels\TelegramChannel;
|
||||
use App\Framework\Notification\ValueObjects\NotificationChannel;
|
||||
use App\Framework\Notification\Notification;
|
||||
|
||||
/**
|
||||
* Practical Telegram Media Sending Example
|
||||
*
|
||||
* This script demonstrates actual media sending via Telegram
|
||||
* using the MediaManager system
|
||||
*/
|
||||
|
||||
echo "📱 Telegram Rich Media Sending Example\n";
|
||||
echo "=======================================\n\n";
|
||||
|
||||
// Bootstrap application
|
||||
$app = AppBootstrapper::bootstrap();
|
||||
$container = $app->getContainer();
|
||||
|
||||
// Get Telegram channel with MediaManager
|
||||
$telegramChannel = $container->get(TelegramChannel::class);
|
||||
$mediaManager = $telegramChannel->mediaManager;
|
||||
|
||||
// Check Telegram capabilities
|
||||
echo "📋 Telegram Media Capabilities:\n";
|
||||
$capabilities = $mediaManager->getCapabilities(NotificationChannel::TELEGRAM);
|
||||
echo " Photos: " . ($capabilities->supportsPhoto ? '✅' : '❌') . "\n";
|
||||
echo " Videos: " . ($capabilities->supportsVideo ? '✅' : '❌') . "\n";
|
||||
echo " Audio: " . ($capabilities->supportsAudio ? '✅' : '❌') . "\n";
|
||||
echo " Documents: " . ($capabilities->supportsDocument ? '✅' : '❌') . "\n";
|
||||
echo " Location: " . ($capabilities->supportsLocation ? '✅' : '❌') . "\n\n";
|
||||
|
||||
// Create notification
|
||||
$notification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Media Test',
|
||||
body: 'Testing Telegram media capabilities',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'media_demo'
|
||||
);
|
||||
|
||||
// Example 1: Send Photo
|
||||
echo "1️⃣ Sending photo...\n";
|
||||
try {
|
||||
if ($mediaManager->supportsPhoto(NotificationChannel::TELEGRAM)) {
|
||||
// Using Telegram's sample photo URL for testing
|
||||
// In production, use local file paths or previously uploaded file_id
|
||||
$photoUrl = 'https://api.telegram.org/file/bot<token>/photos/file_0.jpg';
|
||||
|
||||
$photoNotification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Photo Notification',
|
||||
body: 'This is a test photo',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'photo'
|
||||
);
|
||||
|
||||
$mediaManager->sendPhoto(
|
||||
NotificationChannel::TELEGRAM,
|
||||
$photoNotification,
|
||||
photoPath: $photoUrl, // Can be URL, file path, or file_id
|
||||
caption: '📸 Test photo from MediaManager'
|
||||
);
|
||||
|
||||
echo " ✅ Photo sent successfully\n";
|
||||
} else {
|
||||
echo " ❌ Photo not supported\n";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ Error: {$e->getMessage()}\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Example 2: Send Location
|
||||
echo "2️⃣ Sending location...\n";
|
||||
try {
|
||||
if ($mediaManager->supportsLocation(NotificationChannel::TELEGRAM)) {
|
||||
$locationNotification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Location Share',
|
||||
body: 'Meeting point',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'location'
|
||||
);
|
||||
|
||||
$mediaManager->sendLocation(
|
||||
NotificationChannel::TELEGRAM,
|
||||
$locationNotification,
|
||||
latitude: 52.5200, // Berlin
|
||||
longitude: 13.4050,
|
||||
title: 'Brandenburger Tor',
|
||||
address: '10117 Berlin, Germany'
|
||||
);
|
||||
|
||||
echo " ✅ Location sent successfully\n";
|
||||
} else {
|
||||
echo " ❌ Location not supported\n";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ Error: {$e->getMessage()}\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Example 3: Send Document
|
||||
echo "3️⃣ Sending document...\n";
|
||||
try {
|
||||
if ($mediaManager->supportsDocument(NotificationChannel::TELEGRAM)) {
|
||||
$documentNotification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Document Share',
|
||||
body: 'Important document',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'document'
|
||||
);
|
||||
|
||||
// In production, use actual file path
|
||||
// $mediaManager->sendDocument(
|
||||
// NotificationChannel::TELEGRAM,
|
||||
// $documentNotification,
|
||||
// documentPath: '/path/to/document.pdf',
|
||||
// caption: '📄 Monthly Report',
|
||||
// filename: 'report_2024.pdf'
|
||||
// );
|
||||
|
||||
echo " ℹ️ Document example (requires actual file path)\n";
|
||||
} else {
|
||||
echo " ❌ Document not supported\n";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ Error: {$e->getMessage()}\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Example 4: Graceful fallback to text-only
|
||||
echo "4️⃣ Demonstrating graceful fallback...\n";
|
||||
try {
|
||||
$fallbackNotification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Fallback Test',
|
||||
body: 'This notification tries to send media, but falls back to text if unsupported',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'fallback'
|
||||
);
|
||||
|
||||
// Try to send with photo, fallback to text
|
||||
if ($mediaManager->supportsPhoto(NotificationChannel::TELEGRAM)) {
|
||||
echo " Attempting to send with photo...\n";
|
||||
// $mediaManager->sendPhoto(...);
|
||||
echo " ✅ Would send photo if file path provided\n";
|
||||
} else {
|
||||
echo " Photo not supported, falling back to text notification...\n";
|
||||
$telegramChannel->send($fallbackNotification);
|
||||
echo " ✅ Text notification sent as fallback\n";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo " ⚠️ Error: {$e->getMessage()}\n";
|
||||
echo " Falling back to text notification...\n";
|
||||
$telegramChannel->send($fallbackNotification);
|
||||
echo " ✅ Fallback successful\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Example 5: Using MediaCapabilities for multi-media notifications
|
||||
echo "5️⃣ Smart multi-media notification...\n";
|
||||
|
||||
$multiMediaNotification = new Notification(
|
||||
userId: 'user_123',
|
||||
title: 'Order Confirmed',
|
||||
body: 'Your order #12345 has been confirmed',
|
||||
channel: NotificationChannel::TELEGRAM,
|
||||
type: 'order_confirmed'
|
||||
);
|
||||
|
||||
$capabilities = $mediaManager->getCapabilities(NotificationChannel::TELEGRAM);
|
||||
|
||||
if ($capabilities->supportsPhoto) {
|
||||
echo " 📸 Could attach product photo\n";
|
||||
}
|
||||
|
||||
if ($capabilities->supportsDocument) {
|
||||
echo " 📄 Could attach order receipt PDF\n";
|
||||
}
|
||||
|
||||
if ($capabilities->supportsLocation) {
|
||||
echo " 📍 Could share delivery location\n";
|
||||
}
|
||||
|
||||
echo " ✅ Multi-media notification planned\n\n";
|
||||
|
||||
// Summary
|
||||
echo "✨ Summary\n";
|
||||
echo "=========\n\n";
|
||||
|
||||
echo "MediaManager provides:\n";
|
||||
echo "- Runtime capability checking before sending\n";
|
||||
echo "- Type-safe media sending methods\n";
|
||||
echo "- Graceful fallback support\n";
|
||||
echo "- Unified API across all channels\n\n";
|
||||
|
||||
echo "Best Practices:\n";
|
||||
echo "1. Always check capabilities before sending media\n";
|
||||
echo "2. Provide fallback to text notifications\n";
|
||||
echo "3. Handle exceptions gracefully\n";
|
||||
echo "4. Use appropriate media types for context\n\n";
|
||||
|
||||
echo "✅ Example completed!\n";
|
||||
Reference in New Issue
Block a user