Newwebshop/app/API/controllers/NewsletterApiController.php

464 lines
15 KiB
PHP

<?php
/**
* Copyright seit 2024 Webshop System
*
* Newsletter API Controller für das Webshop-System
*
* @author Webshop System
* @license GPL v3
*/
namespace App\API\Controllers;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Exception;
class NewsletterApiController extends ApiController
{
/**
* Newsletter abonnieren
*/
public function subscribe()
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$this->sendError('Method not allowed', 405);
}
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) {
$this->sendError('Invalid JSON input', 400);
}
if (empty($input['email'])) {
$this->sendError('Email is required', 400);
}
if (!filter_var($input['email'], FILTER_VALIDATE_EMAIL)) {
$this->sendError('Invalid email address', 400);
}
try {
// Prüfen ob bereits abonniert
$stmt = $this->conn->prepare('
SELECT id, active FROM ws_newsletter_subscriber
WHERE email = ?
');
$stmt->execute([$input['email']]);
$existing = $stmt->fetchAssociative();
if ($existing) {
if ($existing['active']) {
$this->sendError('Email is already subscribed', 409);
} else {
// Reaktivieren
$stmt = $this->conn->prepare('
UPDATE ws_newsletter_subscriber
SET active = 1, updated_at = NOW()
WHERE id = ?
');
$stmt->execute([$existing['id']]);
$this->sendResponse([
'success' => true,
'message' => 'Newsletter subscription reactivated'
]);
return;
}
}
// Neues Abonnement erstellen
$stmt = $this->conn->prepare('
INSERT INTO ws_newsletter_subscriber (email, first_name, last_name,
preferences, active, created_at)
VALUES (?, ?, ?, ?, 1, NOW())
');
$stmt->execute([
$input['email'],
$input['first_name'] ?? '',
$input['last_name'] ?? '',
json_encode($input['preferences'] ?? [])
]);
$subscriberId = $this->conn->lastInsertId();
// Willkommens-E-Mail senden
$this->sendWelcomeEmail($input['email'], $input['first_name'] ?? '');
$this->sendResponse([
'success' => true,
'data' => [
'subscriber_id' => $subscriberId
],
'message' => 'Newsletter subscription successful'
]);
} catch (Exception $e) {
$this->sendError('Failed to subscribe: ' . $e->getMessage(), 500);
}
}
/**
* Newsletter abbestellen
*/
public function unsubscribe()
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$this->sendError('Method not allowed', 405);
}
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) {
$this->sendError('Invalid JSON input', 400);
}
if (empty($input['email'])) {
$this->sendError('Email is required', 400);
}
if (!filter_var($input['email'], FILTER_VALIDATE_EMAIL)) {
$this->sendError('Invalid email address', 400);
}
try {
$stmt = $this->conn->prepare('
UPDATE ws_newsletter_subscriber
SET active = 0, unsubscribed_at = NOW()
WHERE email = ?
');
$stmt->execute([$input['email']]);
if ($stmt->rowCount() === 0) {
$this->sendError('Email not found in subscribers', 404);
}
$this->sendResponse([
'success' => true,
'message' => 'Newsletter unsubscribed successfully'
]);
} catch (Exception $e) {
$this->sendError('Failed to unsubscribe: ' . $e->getMessage(), 500);
}
}
/**
* Newsletter-Präferenzen aktualisieren
*/
public function updatePreferences($subscriberId)
{
if ($_SERVER['REQUEST_METHOD'] !== 'PUT') {
$this->sendError('Method not allowed', 405);
}
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) {
$this->sendError('Invalid JSON input', 400);
}
try {
$updateFields = [];
$params = [];
if (isset($input['first_name'])) {
$updateFields[] = 'first_name = ?';
$params[] = $input['first_name'];
}
if (isset($input['last_name'])) {
$updateFields[] = 'last_name = ?';
$params[] = $input['last_name'];
}
if (isset($input['preferences'])) {
$updateFields[] = 'preferences = ?';
$params[] = json_encode($input['preferences']);
}
if (empty($updateFields)) {
$this->sendError('No fields to update', 400);
}
$updateFields[] = 'updated_at = NOW()';
$params[] = $subscriberId;
$sql = 'UPDATE ws_newsletter_subscriber SET ' . implode(', ', $updateFields) . ' WHERE id = ?';
$stmt = $this->conn->prepare($sql);
$stmt->execute($params);
if ($stmt->rowCount() === 0) {
$this->sendError('Subscriber not found', 404);
}
$this->sendResponse([
'success' => true,
'message' => 'Preferences updated successfully'
]);
} catch (Exception $e) {
$this->sendError('Failed to update preferences: ' . $e->getMessage(), 500);
}
}
/**
* Newsletter-Templates abrufen
*/
public function getTemplates()
{
try {
$stmt = $this->conn->prepare('
SELECT id, name, subject, content, active, created_at
FROM ws_newsletter_template
WHERE active = 1
ORDER BY name ASC
');
$stmt->execute();
$templates = $stmt->fetchAllAssociative();
$this->sendResponse([
'success' => true,
'data' => $templates
]);
} catch (Exception $e) {
$this->sendError('Failed to fetch templates: ' . $e->getMessage(), 500);
}
}
/**
* Newsletter senden
*/
public function sendNewsletter()
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$this->sendError('Method not allowed', 405);
}
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) {
$this->sendError('Invalid JSON input', 400);
}
if (empty($input['template_id']) || empty($input['subject'])) {
$this->sendError('Template ID and subject are required', 400);
}
try {
// Template abrufen
$stmt = $this->conn->prepare('
SELECT * FROM ws_newsletter_template
WHERE id = ? AND active = 1
');
$stmt->execute([$input['template_id']]);
$template = $stmt->fetchAssociative();
if (!$template) {
$this->sendError('Template not found', 404);
}
// Aktive Abonnenten abrufen
$stmt = $this->conn->prepare('
SELECT id, email, first_name, last_name, preferences
FROM ws_newsletter_subscriber
WHERE active = 1
');
$stmt->execute();
$subscribers = $stmt->fetchAllAssociative();
if (empty($subscribers)) {
$this->sendError('No active subscribers found', 400);
}
$sentCount = 0;
$failedCount = 0;
foreach ($subscribers as $subscriber) {
try {
$this->sendNewsletterEmail($subscriber, $template, $input['subject']);
$sentCount++;
} catch (Exception $e) {
$failedCount++;
}
}
// Newsletter-Log erstellen
$stmt = $this->conn->prepare('
INSERT INTO ws_newsletter_log (template_id, subject, sent_count,
failed_count, created_at)
VALUES (?, ?, ?, ?, NOW())
');
$stmt->execute([
$input['template_id'],
$input['subject'],
$sentCount,
$failedCount
]);
$this->sendResponse([
'success' => true,
'data' => [
'sent_count' => $sentCount,
'failed_count' => $failedCount,
'total_subscribers' => count($subscribers)
],
'message' => 'Newsletter sent successfully'
]);
} catch (Exception $e) {
$this->sendError('Failed to send newsletter: ' . $e->getMessage(), 500);
}
}
/**
* Newsletter-Statistiken
*/
public function getStats()
{
try {
// Abonnenten-Statistiken
$stmt = $this->conn->prepare('
SELECT
COUNT(*) as total_subscribers,
COUNT(CASE WHEN active = 1 THEN 1 END) as active_subscribers,
COUNT(CASE WHEN active = 0 THEN 1 END) as inactive_subscribers
FROM ws_newsletter_subscriber
');
$stmt->execute();
$subscriberStats = $stmt->fetchAssociative();
// Newsletter-Log-Statistiken
$stmt = $this->conn->prepare('
SELECT
COUNT(*) as total_campaigns,
SUM(sent_count) as total_sent,
SUM(failed_count) as total_failed,
AVG(sent_count) as avg_sent_per_campaign
FROM ws_newsletter_log
');
$stmt->execute();
$campaignStats = $stmt->fetchAssociative();
// Template-Statistiken
$stmt = $this->conn->prepare('
SELECT COUNT(*) as total_templates
FROM ws_newsletter_template
WHERE active = 1
');
$stmt->execute();
$templateStats = $stmt->fetchAssociative();
$this->sendResponse([
'success' => true,
'data' => [
'subscribers' => $subscriberStats,
'campaigns' => $campaignStats,
'templates' => $templateStats
]
]);
} catch (Exception $e) {
$this->sendError('Failed to get newsletter stats: ' . $e->getMessage(), 500);
}
}
/**
* Willkommens-E-Mail senden
*/
private function sendWelcomeEmail($email, $firstName)
{
$subject = 'Willkommen beim Newsletter!';
$message = "
<html>
<body>
<h2>Willkommen beim Newsletter!</h2>
<p>Hallo " . htmlspecialchars($firstName ?: 'Lieber Kunde') . ",</p>
<p>Vielen Dank für Ihr Abonnement unseres Newsletters. Sie erhalten nun regelmäßig Informationen über:</p>
<ul>
<li>Neue Produkte und Angebote</li>
<li>Exklusive Rabatte und Aktionen</li>
<li>Interessante Artikel und Tipps</li>
</ul>
<p>Falls Sie den Newsletter nicht mehr erhalten möchten, können Sie sich jederzeit <a href='" . getenv('BASE_URL') . "/unsubscribe'>hier abmelden</a>.</p>
<p>Mit freundlichen Grüßen<br>Ihr Webshop-Team</p>
</body>
</html>
";
$this->sendEmail($email, $subject, $message);
}
/**
* Newsletter-E-Mail senden
*/
private function sendNewsletterEmail($subscriber, $template, $subject)
{
$preferences = json_decode($subscriber['preferences'], true) ?: [];
// Template personalisieren
$content = $template['content'];
$content = str_replace('{first_name}', $subscriber['first_name'], $content);
$content = str_replace('{last_name}', $subscriber['last_name'], $content);
$content = str_replace('{email}', $subscriber['email'], $content);
// Präferenzen-basierte Inhalte
if (!empty($preferences['categories'])) {
$categoryContent = $this->getCategoryContent($preferences['categories']);
$content = str_replace('{category_content}', $categoryContent, $content);
}
$this->sendEmail($subscriber['email'], $subject, $content);
}
/**
* Kategorie-Inhalte abrufen
*/
private function getCategoryContent($categories)
{
try {
$placeholders = str_repeat('?,', count($categories) - 1) . '?';
$stmt = $this->conn->prepare("
SELECT name, description
FROM ws_category
WHERE id IN ($placeholders) AND active = 1
LIMIT 3
");
$stmt->execute($categories);
$categoryData = $stmt->fetchAllAssociative();
$content = '<h3>Ihre bevorzugten Kategorien:</h3>';
foreach ($categoryData as $category) {
$content .= '<h4>' . htmlspecialchars($category['name']) . '</h4>';
$content .= '<p>' . htmlspecialchars($category['description']) . '</p>';
}
return $content;
} catch (Exception $e) {
return '';
}
}
/**
* E-Mail senden
*/
private function sendEmail($to, $subject, $message)
{
$headers = [
'MIME-Version: 1.0',
'Content-type: text/html; charset=UTF-8',
'From: ' . (getenv('MAIL_FROM') ?: 'noreply@webshop.local'),
'Reply-To: ' . (getenv('MAIL_REPLY_TO') ?: 'support@webshop.local'),
'X-Mailer: Webshop System'
];
$result = mail($to, $subject, $message, implode("\r\n", $headers));
if (!$result) {
throw new Exception('Failed to send email');
}
}
}