Skip to content
Snippets Groups Projects
Commit 2fa32f08 authored by Gábor Szántó's avatar Gábor Szántó
Browse files

Create csv export

parent e00ed142
Branches 8.x-2.x
Tags 8.x-2.x-alpha1
No related merge requests found
......@@ -16,3 +16,13 @@
text-align: center;
margin-top: 40px;
}
.sendgrid-export-links {
display: flex;
justify-content: center;
margin: 20px 0;
}
.sendgrid-export-links a.button {
margin: 0 5px;
}
......@@ -13,6 +13,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\sendgrid_integration_reports\Api;
use Drupal\sendgrid_integration_simplenews_reports\Service\SendGridSimplenewsReportsService;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
/**
* Displays SendGrid email statistics for Simplenews newsletters.
......@@ -108,30 +109,36 @@ class SendGridSimplenewsReportsController extends ControllerBase {
}
/**
* Displays email reports for a newsletter node.
* Displays email reports for a newsletter node or exports as CSV.
*
* @param \Drupal\node\NodeInterface $node
* The newsletter node.
*
* @return array
* Render array for the report page.
* @return array|Response
* Render array for the report page or CSV response.
*/
public function getNodeReports(NodeInterface $node) {
$date_range = $this->reportsService->getDateRangeFromRequest($node);
$start_date = $date_range['start_date'];
$end_date = $date_range['end_date'];
// Get the date range form.
$date_range_form = $this->formBuilder()->getForm(
DateRangeForm::class,
$node,
// Get email statistics data from the service.
$statistics = $this->reportsService->getNewsletterStatistics(
$node->id(),
$start_date,
$end_date
);
// Get email statistics data from the service.
$statistics = $this->reportsService->getNewsletterStatistics(
$node->id(),
// Check if CSV export is requested
$request = $this->requestStack->getCurrentRequest();
if ($request->query->get('format') === 'csv') {
return $this->exportAsCsv($statistics, $node);
}
// Get the date range form.
$date_range_form = $this->formBuilder()->getForm(
DateRangeForm::class,
$node,
$start_date,
$end_date
);
......@@ -151,11 +158,139 @@ class SendGridSimplenewsReportsController extends ControllerBase {
'form' => $date_range_form,
];
// Add CSV export link.
$csv_url = Url::fromRoute('sendgrid_integration_simplenews_reports.node_statistics', [
'node' => $node->id(),
], [
'query' => [
'start_date' => $start_date,
'end_date' => $end_date,
'format' => 'csv',
],
]);
$render['export_links'] = [
'#type' => 'container',
'#weight' => 100,
'#attributes' => ['class' => ['sendgrid-export-links']],
'csv' => [
'#type' => 'link',
'#title' => $this->t('Export as CSV'),
'#url' => $csv_url,
'#attributes' => [
'class' => ['button', 'button--small'],
],
],
];
$render['#prefix'] = '<div class="sendgrid-integration-simplenews-reports-container">';
$render['#suffix'] = '</div>';
return $render;
}
/**
* Exports statistics as CSV.
*
* @param array $statistics
* The statistics data.
* @param \Drupal\node\NodeInterface $node
* The newsletter node.
*
* @return \Symfony\Component\HttpFoundation\Response
* CSV response.
*/
protected function exportAsCsv(array $statistics, NodeInterface $node) {
// Generate CSV content.
$csv_content = $this->generateCsvContent($statistics, $node->getTitle());
// Create response with CSV content.
$response = new Response($csv_content);
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
$response->headers->set('Content-Disposition', 'attachment; filename="sendgrid_statistics_' . $node->id() . '_' . date('Y-m-d') . '.csv"');
return $response;
}
/**
* Generates CSV content from statistics data.
*
* @param array $stats
* Statistics data from SendGrid.
* @param string $newsletter_title
* The newsletter title.
*
* @return string
* CSV formatted content.
*/
protected function generateCsvContent(array $stats, string $newsletter_title) {
$metrics = $this->reportsService->getMetricDefinitions();
$csv_rows = [];
// Add header row.
$header = ['Date'];
foreach ($metrics as $metric_key => $metric_label) {
$header[] = (string) $metric_label;
}
$csv_rows[] = $header;
// Add data rows.
if (!empty($stats['global'])) {
foreach ($stats['global'] as $data_point) {
$row = [$data_point['date']];
foreach (array_keys($metrics) as $metric) {
$row[] = isset($data_point[$metric]) ? $data_point[$metric] : 0;
}
$csv_rows[] = $row;
}
// Add totals row.
$totals = array_fill_keys(array_keys($metrics), 0);
foreach ($stats['global'] as $item) {
foreach ($totals as $metric => $count) {
if (isset($item[$metric])) {
$totals[$metric] += $item[$metric];
}
}
}
$total_row = ['Total'];
foreach (array_keys($metrics) as $metric) {
$total_row[] = $totals[$metric];
}
$csv_rows[] = $total_row;
}
// Convert array to CSV.
$csv_content = '';
foreach ($csv_rows as $row) {
$csv_content .= $this->csvEscapeRow($row) . "\n";
}
return $csv_content;
}
/**
* Escapes and formats a row for CSV output.
*
* @param array $row
* Array of values to format as CSV.
*
* @return string
* CSV formatted row.
*/
protected function csvEscapeRow(array $row) {
$escaped_row = [];
foreach ($row as $value) {
// Escape double quotes and wrap in quotes if contains comma, quote or newline.
$value = str_replace('"', '""', $value);
if (preg_match('/[,"\n\r]/', $value)) {
$value = '"' . $value . '"';
}
$escaped_row[] = $value;
}
return implode(',', $escaped_row);
}
/**
* Builds the report page render array.
*
......@@ -296,4 +431,6 @@ class SendGridSimplenewsReportsController extends ControllerBase {
];
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment