Skip to content

Commit e71350b

Browse files
authored
Merge pull request #28 from moreonion/target-messages
Implement a target message export
2 parents 3ac62ed + d872f14 commit e71350b

File tree

3 files changed

+161
-1
lines changed

3 files changed

+161
-1
lines changed

campaignion_csv.module

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use Drupal\campaignion_csv\Exporter\ActivityExporter;
1010
use Drupal\campaignion_csv\Exporter\ContactExporter;
1111
use Drupal\campaignion_csv\Exporter\OptInExporter;
1212
use Drupal\campaignion_csv\Exporter\TargetStatsExporter;
13+
use Drupal\campaignion_csv\Exporter\TargetMessageExporter;
14+
use Drupal\campaignion_csv\Exporter\WebformFormatted\SubmissionPropertySelector;
1315
use Drupal\campaignion_csv\Exporter\WebformGeneric\Exporter as WebformExporter;
1416
use Drupal\campaignion_csv\Files\ContactRangeFilePattern;
1517
use Drupal\campaignion_csv\Files\MonthlyFilePattern;
@@ -127,6 +129,32 @@ function campaignion_csv_campaignion_csv_info() {
127129
'class' => TargetStatsExporter::class,
128130
],
129131
];
132+
$export['target_messages'] = [
133+
'file_pattern' => [
134+
'class' => MonthlyFilePattern::class,
135+
'path' => 'target-messages/%Y-%m.csv',
136+
'retention_period' => new \DateInterval('P6M'),
137+
'refresh_interval' => new \DateInterval('PT23H30M'),
138+
],
139+
'exporter' => [
140+
'class' => TargetMessageExporter::class,
141+
'columns' => [
142+
'nid' => [
143+
'selector' => SubmissionPropertySelector::class,
144+
'property' => 'nid',
145+
],
146+
'node.type' => [
147+
'selector' => SubmissionPropertySelector::class,
148+
'property' => 'node.type',
149+
],
150+
'sid' => [
151+
'selector' => SubmissionPropertySelector::class,
152+
'property' => 'sid',
153+
],
154+
'Email address' => ['keys' => ['email']],
155+
],
156+
],
157+
];
130158
return $export;
131159
}
132160

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<?php
2+
3+
namespace Drupal\campaignion_csv\Exporter;
4+
5+
use Drupal\campaignion_csv\Exporter\WebformFormatted\Column;
6+
use Drupal\campaignion_csv\Files\CsvFileInterface;
7+
use Drupal\campaignion_csv\Timeframe;
8+
use Drupal\little_helpers\Webform\Submission;
9+
10+
/**
11+
* Export messages sent to targets.
12+
*/
13+
class TargetMessageExporter {
14+
15+
/**
16+
* The timeframe for the current export.
17+
*
18+
* @var \Drupal\campaignion_csv\Timeframe
19+
*/
20+
protected $timeframe;
21+
22+
/**
23+
* Mapping of column headers to data paths.
24+
*
25+
* @var string[]
26+
*/
27+
protected $mapping;
28+
29+
/**
30+
* Submission columns to export in addition to the target / message data.
31+
*
32+
* @var \Drupal\campaignion_csv\Exporter\WebformFormatted\Column[] $columns
33+
*/
34+
protected $columns;
35+
36+
/**
37+
* Create a new exporter based on the info.
38+
*/
39+
public static function fromInfo(array $info) {
40+
$info += [
41+
'columns' => [],
42+
'mapping' => [
43+
'cid' => 'cid',
44+
'Salutation' => 'target.salutation',
45+
'Area / Constituency' => 'target.area.name',
46+
'Area type' => 'target.area.type',
47+
'Area code' => 'target.area.gss_code',
48+
'Country' => 'target.area.country__name',
49+
'Display name' => 'message.display',
50+
'To-name' => 'message.toName',
51+
'Subject' => 'message.subject',
52+
'Header' => 'message.header',
53+
'Message' => 'message.message',
54+
'Footer' => 'message.footer',
55+
],
56+
];
57+
foreach ($info['columns'] as $label => $column_info) {
58+
$column_info['label'] = $label;
59+
$columns[] = Column::fromInfo($column_info);
60+
}
61+
return new static($info['timeframe'], $columns, $info['mapping']);
62+
}
63+
64+
/**
65+
* Create a new instance.
66+
*
67+
* @param \Drupal\campaignion_csv\Timeframe $timeframe
68+
* Export data for submissions within this timeframe.
69+
* @param \Drupal\campaignion_csv\Exporter\WebformFormatted\Column[] $columns
70+
* Submission columns to export in addition to the target / message data.
71+
* @param string[] $mapping
72+
* Mapping of column headers to data paths in the e2t_selector data.
73+
*/
74+
public function __construct(Timeframe $timeframe, array $columns, array $mapping) {
75+
$this->timeframe = $timeframe;
76+
$this->columns = $columns;
77+
$this->mapping = $mapping;
78+
}
79+
80+
/**
81+
* Iterate through submitted data of e2t_selector components.
82+
*/
83+
protected function readSubmittedData() {
84+
$last_sid = 0;
85+
list($start, $end) = $this->timeframe->getTimestamps();
86+
$sql_sids = <<<SQL
87+
SELECT s.nid, s.sid, c.cid
88+
FROM webform_submissions s
89+
INNER JOIN webform_component c USING(nid)
90+
WHERE s.is_draft=0 AND c.type='e2t_selector' AND s.submitted BETWEEN :start AND :end AND s.sid>:last_sid
91+
GROUP BY s.sid
92+
ORDER BY s.sid
93+
LIMIT 100
94+
SQL;
95+
$args = [':start' => $start, ':end' => $end - 1];
96+
while ($rows = db_query($sql_sids, [':last_sid' => $last_sid] + $args)->fetchAll()) {
97+
foreach ($rows as $row) {
98+
$submission = Submission::load($row->nid, $row->sid);
99+
$values = array_map('unserialize', $submission->valuesByCid($row->cid));
100+
foreach ($values as $value) {
101+
$value['cid'] = $row->cid;
102+
yield [$submission, $value];
103+
}
104+
$last_sid = $row->sid;
105+
}
106+
drupal_static_reset('webform_get_submission');
107+
}
108+
}
109+
110+
/**
111+
* Write the data to the CsvFile.
112+
*/
113+
public function writeTo(CsvFileInterface $file) {
114+
$header = array_map(function ($v) {
115+
return $v->label;
116+
}, $this->columns);
117+
$file->writeRow(array_merge($header, array_keys($this->mapping)));
118+
119+
foreach ($this->readSubmittedData() as $pair) {
120+
list($submission, $value) = $pair;
121+
$row = [];
122+
foreach ($this->columns as $column) {
123+
$row[] = $column->value($submission);
124+
}
125+
$value_row = array_map(function ($path) use ($value) {
126+
return drupal_array_get_nested_value($value, explode('.', $path)) ?? '';
127+
}, $this->mapping);
128+
$file->writeRow(array_merge($row, $value_row));
129+
}
130+
}
131+
132+
}

src/Exporter/WebformFormatted/Exporter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ protected static function getNodes(Timeframe $timeframe, array $criteria = []) {
4949
public static function fromInfo(array $info) {
5050
$info += [
5151
'criteria' => [],
52-
'colmuns' => [],
52+
'columns' => [],
5353
];
5454
if (!isset($info['nodes'])) {
5555
$info['nodes'] = static::getNodes($info['timeframe'], $info['criteria']);

0 commit comments

Comments
 (0)