Completed
Push — master ( bc6738...1c5a06 )
by Simon
01:47
created

PartialSubmissionJob::addAddress()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 2
eloc 3
nc 2
nop 1
1
<?php
2
3
namespace Firesphere\PartialUserforms\Jobs;
4
5
use DateInterval;
6
use DateTime;
7
use DNADesign\ElementalUserForms\Model\ElementForm;
8
use Firesphere\PartialUserforms\Models\PartialFieldSubmission;
9
use Firesphere\PartialUserforms\Models\PartialFormSubmission;
10
use SilverStripe\Control\Email\Email;
11
use SilverStripe\Core\Injector\Injector;
12
use SilverStripe\Dev\Debug;
13
use SilverStripe\ORM\ArrayList;
14
use SilverStripe\ORM\DataList;
15
use SilverStripe\ORM\FieldType\DBDatetime;
16
use SilverStripe\SiteConfig\SiteConfig;
17
use SilverStripe\UserForms\Model\UserDefinedForm;
18
use Symbiote\QueuedJobs\Services\AbstractQueuedJob;
19
use Symbiote\QueuedJobs\Services\QueuedJobService;
20
21
/**
22
 * Class PartialSubmissionJob
23
 * @package Firesphere\PartialUserforms\Jobs
24
 */
25
class PartialSubmissionJob extends AbstractQueuedJob
26
{
27
28
    /**
29
     * The generated CSV files
30
     * @var array
31
     */
32
    protected $files = [];
33
34
    /**
35
     * @var SiteConfig
36
     */
37
    protected $config;
38
39
    /**
40
     * @var array
41
     */
42
    protected $addresses;
43
44
45
    /**
46
     * @return string
47
     */
48
    public function getTitle()
49
    {
50
        return _t(__CLASS__ . '.Title', 'Export partial submissions to Email');
51
    }
52
53
    /**
54
     * Do some processing yourself!
55
     */
56
    public function process()
57
    {
58
        $this->config = SiteConfig::current_site_config();
59
        $this->validateEmails();
60
61
        if (!$this->config->SendDailyEmail ||
62
            !count($this->addresses)
63
        ) {
64
            $this->addMessage(_t(__CLASS__ . '.EmailError', 'Can not process without valid email'));
65
            $this->isComplete = true;
66
67
            return;
68
        }
69
70
        $userDefinedForms = $this->getParents();
71
72
        /** @var UserDefinedForm $form */
73
        foreach ($userDefinedForms as $form) {
74
            $fileName = _t(__CLASS__ . '.Export', 'Export of ') .
75
                $form->Title . ' - ' .
76
                DBDatetime::now()->Format(DBDatetime::ISO_DATETIME);
77
            $file = '/tmp/' . $fileName . '.csv';
78
            $this->files[] = $file;
79
            $this->buildCSV($file, $form);
80
        }
81
82
        $this->sendEmail();
83
84
85
        $this->isComplete = true;
86
    }
87
88
    /**
89
     * Only add valid email addresses
90
     */
91
    protected function validateEmails()
92
    {
93
        $email = $this->config->SendMailTo;
94
        $result = Email::is_valid_address($email);
95
        if ($result) {
96
            $this->addresses[] = $email;
97
        }
98
        if (strpos(',', $email) !== false) {
99
            $emails = explode(',', $email);
100
            Debug::dump($emails);
101
            foreach ($emails as $address) {
102
                $result = Email::is_valid_address(trim($address));
103
                if ($result) {
104
                    $this->addresses[] = trim($address);
105
                } else {
106
                    $this->addMessage($address . _t(__CLASS__ . '.invalidMail', ' is not a valid email address'));
107
                }
108
            }
109
        }
110
    }
111
112
    /**
113
     * @return ArrayList
114
     */
115
    protected function getParents()
116
    {
117
        /** @var DataList|PartialFormSubmission[] $exportForms */
118
        $allSubmissions = PartialFormSubmission::get()->filter(['IsSend' => false]);
119
        /** @var ArrayList|UserDefinedForm[]|ElementForm[] $parents */
120
        $userDefinedForms = ArrayList::create();
121
122
        /** @var PartialFormSubmission $submission */
123
        foreach ($allSubmissions as $submission) {
124
            // Due to having to support Elemental ElementForm, we need to manually get the parent
125
            // It's a bit a pickle, but it works
126
            $parentClass = $submission->ParentClass;
127
            $parent = $parentClass::get()->byID($submission->UserDefinedFormID);
128
            if ($parent &&
129
                $parent->ExportPartialSubmissions &&
130
                !$userDefinedForms->find('ID', $parent->ID)
131
            ) {
132
                $userDefinedForms->push($parent);
133
            }
134
            $submission->destroy();
135
        }
136
137
        return $userDefinedForms;
138
    }
139
140
    /**
141
     * @param $file
142
     * @param $form
143
     */
144
    protected function buildCSV($file, $form)
145
    {
146
        $resource = fopen($file, 'w+');
147
        /** @var PartialFormSubmission $submissions */
148
        $submissions = PartialFormSubmission::get()->filter(['UserDefinedFormID' => $form->ID]);
149
        $headerFields = $form
150
            ->Fields()
151
            ->exclude(['Name:PartialMatch' => 'EditableFormStep'])
152
            ->column('Title');
153
        fputcsv($resource, $headerFields);
154
155
        if ($submissions->count()) {
0 ignored issues
show
Documentation Bug introduced by
The method count does not exist on object<Firesphere\Partia...\PartialFormSubmission>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
156
            $this->processSubmissions($form, $submissions, $resource);
157
        }
158
        fclose($resource);
159
    }
160
161
    /**
162
     * @param $form
163
     * @param $submissions
164
     * @param $resource
165
     */
166
    protected function processSubmissions($form, $submissions, $resource)
167
    {
168
        $editableFields = $form->Fields()->map('Name', 'Title')->toArray();
169
        $submitted = [];
170
        foreach ($submissions as $submission) {
171
            $values = $submission->PartialFields()->map('Name', 'Value')->toArray();
172
            $i = 0;
173
            foreach ($editableFields as $field => $title) {
174
                $submitted[] = '';
175
                if (isset($values[$field])) {
176
                    $submitted[] = $values[$field];
177
                }
178
                $i++;
179
            }
180
            fputcsv($resource, $submitted);
181
            $submission->IsSend = true;
182
            $submission->write();
183
        }
184
    }
185
186
    /**
187
     * @throws \Exception
188
     */
189
    public function afterComplete()
190
    {
191
        // Remove the files created in the process
192
        foreach ($this->files as $file) {
193
            unlink($file);
194
        }
195
196
        parent::afterComplete();
197
        if ($this->config->CleanupAfterSend) {
198
            $this->cleanupSubmissions();
199
        }
200
        if ($this->config->SendDailyEmail) {
201
            $this->createNewJob();
202
        }
203
    }
204
205
    /**
206
     * Remove submissions that have been sent out
207
     */
208
    protected function cleanupSubmissions()
209
    {
210
        /** @var DataList|PartialFormSubmission[] $forms */
211
        $forms = PartialFormSubmission::get()->filter(['IsSend' => true]);
212
        foreach ($forms as $form) {
213
            /** @var DataList|PartialFieldSubmission[] $fields */
214
            $fields = PartialFieldSubmission::get()->filter(['ID' => $form->PartialFields()->column('ID')]);
215
            $fields->removeAll();
216
            $form->delete();
217
            $form->destroy();
218
        }
219
    }
220
221
    /**
222
     * Create a new queued job for tomorrow
223
     * @throws \Exception
224
     */
225
    protected function createNewJob()
226
    {
227
        $job = new self();
228
        /** @var QueuedJobService $queuedJob */
229
        $queuedJob = Injector::inst()->get(QueuedJobService::class);
230
        $tomorrow = $this->getTomorrow();
231
        $queuedJob->queueJob($job, $tomorrow);
232
    }
233
234
    /**
235
     * @return DBDatetime|static
236
     * @throws \Exception
237
     */
238 View Code Duplication
    protected function getTomorrow()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
239
    {
240
        $dateTime = new DateTime(DBDatetime::now());
241
        $interval = new DateInterval('P1D');
242
        $tomorrow = $dateTime->add($interval);
243
        $dbDateTime = DBDatetime::create();
244
        $dbDateTime->setValue($tomorrow->format('Y-m-d 00:00:00'));
245
246
        return $dbDateTime;
247
    }
248
249
    /**
250
     * @return array
251
     */
252
    public function getMessages()
253
    {
254
        return $this->messages;
255
    }
256
257
    /**
258
     * @return array
259
     */
260
    public function getAddresses()
261
    {
262
        return $this->addresses;
263
    }
264
265
    public function addAddress($address)
266
    {
267
        if (Email::is_valid_address($address)) {
268
            $this->addresses[] = $address;
269
        }
270
    }
271
272
    protected function sendEmail()
273
    {
274
        /** @var Email $mail */
275
        $mail = Email::create();
276
277
        $mail->setSubject('Partial form submissions of ' . DBDatetime::now()->Format(DBDatetime::ISO_DATETIME));
278
        foreach ($this->files as $file) {
279
            $mail->addAttachment($file);
280
        }
281
282
        Debug::dump($this->addresses);
283
        // @todo make the from correct
284
        $mail->setFrom('[email protected]');
285
        $mail->setTo($this->addresses);
286
        $mail->send();
287
    }
288
}
289