connection->execute(SqlQuery::create($sql, [ $feedback->detectionId, $feedback->feedbackType->value, $feedback->userId, $feedback->comment, $feedback->timestamp->toSqlString(), $feedback->category->value, $feedback->severity->value, json_encode($feedback->context), ])); } /** * {@inheritdoc} */ public function getFeedbackForDetection(string $detectionId): array { $sql = ' SELECT detection_id, feedback_type, user_id, comment, timestamp, category, severity, context FROM waf_feedback WHERE detection_id = ? ORDER BY timestamp DESC '; $result = $this->connection->query(SqlQuery::create($sql, [$detectionId])); return $this->hydrateMultipleResults($result); } /** * {@inheritdoc} */ public function getFeedbackByCategory(DetectionCategory $category, ?Timestamp $since = null): array { $sql = ' SELECT detection_id, feedback_type, user_id, comment, timestamp, category, severity, context FROM waf_feedback WHERE category = ? '; $params = [$category->value]; if ($since !== null) { $sql .= ' AND timestamp >= ?'; $params[] = $since->toSqlString(); } $sql .= ' ORDER BY timestamp DESC'; $result = $this->connection->query(SqlQuery::create($sql, $params)); return $this->hydrateMultipleResults($result); } /** * {@inheritdoc} */ public function getFeedbackByFeedbackType(FeedbackType $feedbackType, ?Timestamp $since = null): array { $sql = ' SELECT detection_id, feedback_type, user_id, comment, timestamp, category, severity, context FROM waf_feedback WHERE feedback_type = ? '; $params = [$feedbackType->value]; if ($since !== null) { $sql .= ' AND timestamp >= ?'; $params[] = $since->toSqlString(); } $sql .= ' ORDER BY timestamp DESC'; $result = $this->connection->query(SqlQuery::create($sql, $params)); return $this->hydrateMultipleResults($result); } /** * {@inheritdoc} */ public function getFeedbackStats(): array { // Get total count $totalResult = $this->connection->query(SqlQuery::create('SELECT COUNT(*) FROM waf_feedback')); $totalCount = (int)$totalResult->fetchColumn(); // Get counts by feedback type $typeResult = $this->connection->query(SqlQuery::create(' SELECT feedback_type, COUNT(*) as count FROM waf_feedback GROUP BY feedback_type ')); $typeStats = []; foreach ($typeResult->fetchAll() as $row) { $typeStats[$row['feedback_type']] = (int)$row['count']; } // Get counts by category $categoryResult = $this->connection->query(SqlQuery::create(' SELECT category, COUNT(*) as count FROM waf_feedback GROUP BY category ')); $categoryStats = []; foreach ($categoryResult->fetchAll() as $row) { $categoryStats[$row['category']] = (int)$row['count']; } // Get counts by severity $severityResult = $this->connection->query(SqlQuery::create(' SELECT severity, COUNT(*) as count FROM waf_feedback GROUP BY severity ')); $severityStats = []; foreach ($severityResult->fetchAll() as $row) { $severityStats[$row['severity']] = (int)$row['count']; } // Get trend data (last 30 days) $trendResult = $this->connection->query(SqlQuery::create(' SELECT DATE(timestamp) as date, feedback_type, COUNT(*) as count FROM waf_feedback WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY DATE(timestamp), feedback_type ORDER BY date ')); $trendData = []; foreach ($trendResult->fetchAll() as $row) { if (! isset($trendData[$row['date']])) { $trendData[$row['date']] = []; } $trendData[$row['date']][$row['feedback_type']] = (int)$row['count']; } return [ 'total_count' => $totalCount, 'by_feedback_type' => $typeStats, 'by_category' => $categoryStats, 'by_severity' => $severityStats, 'trend_data' => $trendData, ]; } /** * {@inheritdoc} */ public function getRecentFeedback(int $limit = 10): array { $sql = ' SELECT detection_id, feedback_type, user_id, comment, timestamp, category, severity, context FROM waf_feedback ORDER BY timestamp DESC LIMIT ? '; $result = $this->connection->query(SqlQuery::create($sql, [$limit])); return $this->hydrateMultipleResults($result); } /** * Hydrates multiple DetectionFeedback objects from a PDO statement * * @param \PDOStatement $stmt The executed PDO statement * @return DetectionFeedback[] Array of DetectionFeedback objects */ private function hydrateMultipleResults($result): array { $results = []; foreach ($result->fetchAll() as $row) { $results[] = $this->hydrateFromRow($row); } return $results; } /** * Hydrates a DetectionFeedback object from a database row * * @param array $row Database row * @return DetectionFeedback */ private function hydrateFromRow(array $row): DetectionFeedback { return new DetectionFeedback( detectionId: $row['detection_id'], feedbackType: FeedbackType::from($row['feedback_type']), userId: $row['user_id'], comment: $row['comment'], timestamp: Timestamp::fromString($row['timestamp']), category: DetectionCategory::from($row['category']), severity: DetectionSeverity::from($row['severity']), context: json_decode($row['context'] ?? '{}', true) ?: [] ); } }