Completed
Push — master ( 70c3fb...bc6738 )
by Simon
01:48
created

PartialSubmissionJob::getTomorrow()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 10
Ratio 100 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 10
loc 10
rs 9.4285
cc 1
eloc 7
nc 1
nop 0
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
     * PartialSubmissionJob constructor.
46
     * @param array $params
47
     */
48
    public function __construct(array $params = array())
49
    {
50
        $this->isValidEmail();
51
        parent::__construct($params);
52
53
    }
54
55
    /**
56
     * @return string
57
     */
58
    public function getTitle()
59
    {
60
        return _t(__CLASS__ . '.Title', 'Export partial submissions to Email');
61
    }
62
63
    /**
64
     * Do some processing yourself!
65
     */
66
    public function process()
67
    {
68
        $this->config = SiteConfig::current_site_config();
69
70
        if (!$this->config->SendDailyEmail ||
71
            !count($this->addresses)
72
        ) {
73
            $this->addMessage(_t(__CLASS__ . '.EmailError', 'Can not process without valid email'));
74
            $this->isComplete = true;
75
76
            return;
77
        }
78
79
        $userDefinedForms = $this->getParents();
80
81
        /** @var UserDefinedForm $form */
82
        foreach ($userDefinedForms as $form) {
83
            $fileName = _t(__CLASS__ . '.Export', 'Export of ') .
84
                $form->Title . ' - ' .
85
                DBDatetime::now()->Format(DBDatetime::ISO_DATETIME);
86
            $file = '/tmp/' . $fileName . '.csv';
87
            $this->files[] = $file;
88
            $this->buildCSV($file, $form);
89
        }
90
91
        $this->sendEmail();
92
93
94
        $this->isComplete = true;
95
    }
96
97
    /**
98
     * Only add valid email addresses
99
     */
100
    protected function isValidEmail()
101
    {
102
        $email = SiteConfig::current_site_config()->SendMailTo;
103
        $result = Email::is_valid_address($email);
104
        if ($result) {
105
            $this->addresses[] = $email;
106
        }
107
        if (strpos(',', $email) !== false) {
108
            $emails = explode(',', $email);
109
            foreach ($emails as $address) {
110
                $result = Email::is_valid_address(trim($address));
111
                if ($result) {
112
                    $this->addresses[] = trim($address);
113
                } else {
114
                    $this->addMessage($address . _t(__CLASS__ . '.invalidMail', ' is not a valid email address'));
115
                }
116
            }
117
        }
118
    }
119
120
    /**
121
     * @return ArrayList
122
     */
123
    protected function getParents()
124
    {
125
        /** @var DataList|PartialFormSubmission[] $exportForms */
126
        $allSubmissions = PartialFormSubmission::get()->filter(['IsSend' => false]);
127
        /** @var ArrayList|UserDefinedForm[]|ElementForm[] $parents */
128
        $userDefinedForms = ArrayList::create();
129
130
        /** @var PartialFormSubmission $submission */
131
        foreach ($allSubmissions as $submission) {
132
            // Due to having to support Elemental ElementForm, we need to manually get the parent
133
            // It's a bit a pickle, but it works
134
            $parentClass = $submission->ParentClass;
135
            $parent = $parentClass::get()->byID($submission->UserDefinedFormID);
136
            if ($parent &&
137
                $parent->ExportPartialSubmissions &&
138
                !$userDefinedForms->find('ID', $parent->ID)
139
            ) {
140
                $userDefinedForms->push($parent);
141
            }
142
            $submission->destroy();
143
        }
144
145
        return $userDefinedForms;
146
    }
147
148
    /**
149
     * @param $file
150
     * @param $form
151
     */
152
    protected function buildCSV($file, $form)
153
    {
154
        $resource = fopen($file, 'w+');
155
        /** @var PartialFormSubmission $submissions */
156
        $submissions = PartialFormSubmission::get()->filter(['UserDefinedFormID' => $form->ID]);
157
        $headerFields = $form
158
            ->Fields()
159
            ->exclude(['Name:PartialMatch' => 'EditableFormStep'])
160
            ->column('Title');
161
        fputcsv($resource, $headerFields);
162
163
        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...
164
            $this->processSubmissions($form, $submissions, $resource);
165
        }
166
        fclose($resource);
167
    }
168
169
    /**
170
     * @param $form
171
     * @param $submissions
172
     * @param $resource
173
     */
174
    protected function processSubmissions($form, $submissions, $resource)
175
    {
176
        $editableFields = $form->Fields()->map('Name', 'Title')->toArray();
177
        $submitted = [];
178
        foreach ($submissions as $submission) {
179
            $values = $submission->PartialFields()->map('Name', 'Value')->toArray();
180
            $i = 0;
181
            foreach ($editableFields as $field => $title) {
182
                $submitted[] = '';
183
                if (isset($values[$field])) {
184
                    $submitted[] = $values[$field];
185
                }
186
                $i++;
187
            }
188
            fputcsv($resource, $submitted);
189
            $submission->IsSend = true;
190
            $submission->write();
191
        }
192
    }
193
194
    /**
195
     * @throws \Exception
196
     */
197
    public function afterComplete()
198
    {
199
        // Remove the files created in the process
200
        foreach ($this->files as $file) {
201
            unlink($file);
202
        }
203
204
        parent::afterComplete();
205
        if ($this->config->CleanupAfterSend) {
206
            $this->cleanupSubmissions();
207
        }
208
        if ($this->config->SendDailyEmail) {
209
            $this->createNewJob();
210
        }
211
    }
212
213
    /**
214
     * Remove submissions that have been sent out
215
     */
216
    protected function cleanupSubmissions()
217
    {
218
        /** @var DataList|PartialFormSubmission[] $forms */
219
        $forms = PartialFormSubmission::get()->filter(['IsSend' => true]);
220
        foreach ($forms as $form) {
221
            /** @var DataList|PartialFieldSubmission[] $fields */
222
            $fields = PartialFieldSubmission::get()->filter(['ID' => $form->PartialFields()->column('ID')]);
223
            $fields->removeAll();
224
            $form->delete();
225
            $form->destroy();
226
        }
227
    }
228
229
    /**
230
     * Create a new queued job for tomorrow
231
     * @throws \Exception
232
     */
233
    protected function createNewJob()
234
    {
235
        $job = new self();
236
        /** @var QueuedJobService $queuedJob */
237
        $queuedJob = Injector::inst()->get(QueuedJobService::class);
238
        $tomorrow = $this->getTomorrow();
239
        $queuedJob->queueJob($job, $tomorrow);
240
    }
241
242
    /**
243
     * @return DBDatetime|static
244
     * @throws \Exception
245
     */
246 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...
247
    {
248
        $dateTime = new DateTime(DBDatetime::now());
249
        $interval = new DateInterval('P1D');
250
        $tomorrow = $dateTime->add($interval);
251
        $dbDateTime = DBDatetime::create();
252
        $dbDateTime->setValue($tomorrow->format('Y-m-d 00:00:00'));
253
254
        return $dbDateTime;
255
    }
256
257
    /**
258
     * @return array
259
     */
260
    public function getMessages()
261
    {
262
        return $this->messages;
263
    }
264
265
    /**
266
     * @return array
267
     */
268
    public function getAddresses()
269
    {
270
        return $this->addresses;
271
    }
272
273
    protected function sendEmail()
274
    {
275
        /** @var Email $mail */
276
        $mail = Email::create();
277
278
        $mail->setSubject('Partial form submissions of ' . DBDatetime::now()->Format(DBDatetime::ISO_DATETIME));
279
        foreach ($this->files as $file) {
280
            $mail->addAttachment($file);
281
        }
282
283
        Debug::dump($this->addresses);
284
        $mail->setFrom('[email protected]');
285
        $mail->setTo($this->addresses);
286
        $mail->send();
287
    }
288
}
289