Passed
Push — master ( ee4518...8da34e )
by Thomas
01:57
created

Emailing::getAllRecipients()   B

Complexity

Conditions 7
Paths 15

Size

Total Lines 29
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 7
eloc 22
c 2
b 0
f 1
nc 15
nop 0
dl 0
loc 29
rs 8.6346
1
<?php
2
3
namespace LeKoala\EmailTemplates\Models;
4
5
use Exception;
6
use SilverStripe\ORM\DB;
7
use SilverStripe\Forms\Tab;
8
use SilverStripe\i18n\i18n;
9
use SilverStripe\ORM\DataList;
10
use SilverStripe\ORM\DataObject;
11
use SilverStripe\Forms\TextField;
12
use SilverStripe\Security\Member;
13
use SilverStripe\Core\Config\Config;
14
use SilverStripe\Forms\LiteralField;
15
use SilverStripe\Control\Email\Email;
16
use SilverStripe\Forms\DropdownField;
17
use SilverStripe\Forms\ReadonlyField;
18
use SilverStripe\Forms\TextareaField;
19
use SilverStripe\Security\Permission;
20
use SilverStripe\SiteConfig\SiteConfig;
21
use LeKoala\EmailTemplates\Email\BetterEmail;
22
use LeKoala\EmailTemplates\Helpers\FluentHelper;
23
use LeKoala\EmailTemplates\Admin\EmailTemplatesAdmin;
24
use SilverStripe\Forms\FormAction;
25
26
/**
27
 * Send emails to a group of members
28
 *
29
 * @property string $Subject
30
 * @property string $Recipients
31
 * @property string $RecipientsList
32
 * @property string $Sender
33
 * @property string $Content
34
 * @property string $Callout
35
 * @author lekoala
36
 */
37
class Emailing extends DataObject
38
{
39
    private static $table_name = 'Emailing';
0 ignored issues
show
introduced by
The private property $table_name is not used, and could be removed.
Loading history...
40
41
    private static $db = array(
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
42
        'Subject' => 'Varchar(255)',
43
        'Recipients' => 'Varchar(255)',
44
        'RecipientsList' => 'Text',
45
        'Sender' => 'Varchar(255)',
46
        'LastSent' => 'Datetime',
47
        // Content
48
        'Content' => 'HTMLText',
49
        'Callout' => 'HTMLText',
50
    );
51
    private static $summary_fields = array(
0 ignored issues
show
introduced by
The private property $summary_fields is not used, and could be removed.
Loading history...
52
        'Subject', 'LastSent'
53
    );
54
    private static $searchable_fields = array(
0 ignored issues
show
introduced by
The private property $searchable_fields is not used, and could be removed.
Loading history...
55
        'Subject',
56
    );
57
    private static $translate = array(
0 ignored issues
show
introduced by
The private property $translate is not used, and could be removed.
Loading history...
58
        'Subject', 'Content', 'Callout'
59
    );
60
61
    public function getTitle()
62
    {
63
        return $this->Subject;
64
    }
65
66
    public function getCMSActions()
67
    {
68
        $actions = parent::getCMSActions();
69
        $label = _t('Emailing.SEND', 'Send');
70
        $sure = _t('Emailing.SURE', 'Are you sure?');
71
        $onclick = 'return confirm(\'' . $sure . '\');';
72
73
        $sanitisedModel =  str_replace('\\', '-', Emailing::class);
74
        $adminSegment = EmailTemplatesAdmin::config()->url_segment;
75
        $link = '/admin/' . $adminSegment . '/' . $sanitisedModel . '/SendEmailing/?id=' . $this->ID;
76
        $btnContent = '<a href="' . $link . '" id="action_doSend" onclick="' . $onclick . '" class="btn action btn-info font-icon-angle-double-right">';
77
        $btnContent .= '<span class="btn__title">' . $label . '</span></a>';
78
        $actions->push(new LiteralField('doSend', $btnContent));
79
        return $actions;
80
    }
81
82
    public function getCMSFields()
83
    {
84
        $fields = parent::getCMSFields();
85
86
        // Do not allow changing subsite
87
        $fields->removeByName('SubsiteID');
88
89
        // Recipients
90
        $recipientsList = $this->listRecipients();
91
        $fields->replaceField('Recipients', $Recipients = new DropdownField('Recipients', null, $recipientsList));
92
        $Recipients->setDescription(_t('Emailing.EMAIL_COUNT', "Email will be sent to {count} members", ['count' => $this->getAllRecipients()->count()]));
93
94
        $fields->dataFieldByName('Callout')->setRows(5);
95
96
        if ($this->ID) {
97
            $fields->addFieldToTab('Root.Preview', $this->previewTab());
98
        }
99
100
        $fields->addFieldsToTab('Root.Settings', new TextField('Sender'));
0 ignored issues
show
Bug introduced by
new SilverStripe\Forms\TextField('Sender') of type SilverStripe\Forms\TextField is incompatible with the type array expected by parameter $fields of SilverStripe\Forms\FieldList::addFieldsToTab(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

100
        $fields->addFieldsToTab('Root.Settings', /** @scrutinizer ignore-type */ new TextField('Sender'));
Loading history...
101
        $fields->addFieldsToTab('Root.Settings', new ReadonlyField('LastSent'));
0 ignored issues
show
Bug introduced by
new SilverStripe\Forms\ReadonlyField('LastSent') of type SilverStripe\Forms\ReadonlyField is incompatible with the type array expected by parameter $fields of SilverStripe\Forms\FieldList::addFieldsToTab(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
        $fields->addFieldsToTab('Root.Settings', /** @scrutinizer ignore-type */ new ReadonlyField('LastSent'));
Loading history...
102
        $fields->addFieldsToTab('Root.Settings', $RecipientsList = new TextareaField('RecipientsList'));
0 ignored issues
show
Bug introduced by
$RecipientsList = new Si...Field('RecipientsList') of type SilverStripe\Forms\TextareaField is incompatible with the type array expected by parameter $fields of SilverStripe\Forms\FieldList::addFieldsToTab(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

102
        $fields->addFieldsToTab('Root.Settings', /** @scrutinizer ignore-type */ $RecipientsList = new TextareaField('RecipientsList'));
Loading history...
103
        $RecipientsList->setDescription(_t('Emailing.RECIPIENTSLISTHELP', 'A list of IDs or emails on each line or separated by commas. Select "Selected members" to use this list'));
104
105
        return $fields;
106
    }
107
108
    /**
109
     * @return DataList
110
     */
111
    public function getAllRecipients()
112
    {
113
        $list = null;
114
        $locales = self::getMembersLocales();
115
        foreach ($locales as $locale) {
116
            if ($this->Recipients == $locale . '_MEMBERS') {
117
                $list = Member::get()->filter('Locale', $locale);
118
            }
119
        }
120
        $recipients = $this->Recipients;
121
        if (!$list) {
122
            switch ($recipients) {
123
                case 'ALL_MEMBERS':
124
                    $list = Member::get();
125
                    break;
126
                case 'SELECTED_MEMBERS':
127
                    $IDs =  $this->getNormalizedRecipientsList();
128
                    if (empty($IDs)) {
129
                        $IDs = 0;
130
                    }
131
                    $list = Member::get()->filter('ID', $IDs);
132
                    break;
133
                default:
134
                    $list = Member::get()->filter('ID', 0);
135
                    break;
136
            }
137
        }
138
        $this->extend('updateGetAllRecipients', $list, $locales, $recipients);
139
        return $list;
140
    }
141
142
    /**
143
     * List of ids
144
     *
145
     * @return array
146
     */
147
    public function getNormalizedRecipientsList()
148
    {
149
        $list = $this->RecipientsList;
150
151
        $perLine = explode("\n", $list);
152
153
        $arr = [];
154
        foreach ($perLine as $line) {
155
            $items = explode(',', $line);
156
            foreach ($items as $item) {
157
                if (!$item) {
158
                    continue;
159
                }
160
                if (is_numeric($item)) {
161
                    $arr[] = $item;
162
                } elseif (strpos($item, '@') !== false) {
163
                    $arr[] = DB::prepared_query("SELECT ID FROM Member WHERE Email = ?", [$item])->value();
164
                } else {
165
                    throw new Exception("Unprocessable item $item");
166
                }
167
            }
168
        }
169
        return $arr;
170
    }
171
172
    /**
173
     * @return array
174
     */
175
    public static function getMembersLocales()
176
    {
177
        return DB::query("SELECT DISTINCT Locale FROM Member")->column();
178
    }
179
180
    /**
181
     * @return array
182
     */
183
    public function listRecipients()
184
    {
185
        $arr = [];
186
        $arr['ALL_MEMBERS'] = _t('Emailing.ALL_MEMBERS', 'All members');
187
        $arr['SELECTED_MEMBERS'] = _t('Emailing.SELECTED_MEMBERS', 'Selected members');
188
        $locales = self::getMembersLocales();
189
        foreach ($locales as $locale) {
190
            $arr[$locale . '_MEMBERS'] = _t('Emailing.LOCALE_MEMBERS', '{locale} members', ['locale' => $locale]);
191
        }
192
        $this->extend("updateListRecipients", $arr, $locales);
193
        return $arr;
194
    }
195
196
    /**
197
     * Provide content for the Preview tab
198
     *
199
     * @return Tab
200
     */
201
    protected function previewTab()
202
    {
203
        $tab = new Tab('Preview');
204
205
        // Preview iframe
206
        $sanitisedModel =  str_replace('\\', '-', Emailing::class);
207
        $adminSegment = EmailTemplatesAdmin::config()->url_segment;
208
        $iframeSrc = '/admin/' . $adminSegment . '/' . $sanitisedModel . '/PreviewEmailing/?id=' . $this->ID;
209
        $iframe = new LiteralField('iframe', '<iframe src="' . $iframeSrc . '" style="width:800px;background:#fff;border:1px solid #ccc;min-height:500px;vertical-align:top"></iframe>');
210
        $tab->push($iframe);
211
212
        return $tab;
213
    }
214
215
    public function canView($member = null)
216
    {
217
        return true;
218
    }
219
220
    public function canEdit($member = null)
221
    {
222
        return Permission::check('CMS_ACCESS', 'any', $member);
223
    }
224
225
    public function canCreate($member = null, $context = [])
226
    {
227
        return Permission::check('CMS_ACCESS', 'any', $member);
228
    }
229
230
    public function canDelete($member = null)
231
    {
232
        return Permission::check('CMS_ACCESS', 'any', $member);
233
    }
234
235
    /**
236
     * Get rendered body
237
     *
238
     * @return string
239
     */
240
    public function renderTemplate()
241
    {
242
        // Disable debug bar in the iframe
243
        Config::modify()->set('LeKoala\\DebugBar\\DebugBar', 'auto_inject', false);
244
245
        $email = $this->getEmail();
246
        $html = $email->getRenderedBody();
247
        return $html;
248
    }
249
250
251
    /**
252
     * Returns an instance of an Email with the content of the emailing
253
     *
254
     * @return BetterEmail
255
     */
256
    public function getEmail()
257
    {
258
        $email = Email::create();
259
        if (!$email instanceof BetterEmail) {
260
            throw new Exception("Make sure you are injecting the BetterEmail class instead of your base Email class");
261
        }
262
        if ($this->Sender) {
263
            $email->setFrom($this->Sender);
264
        }
265
        foreach ($this->getAllRecipients() as $r) {
266
            $email->addBCC($r->Email, $r->FirstName . ' ' . $r->Surname);
267
        }
268
        $email->setSubject($this->Subject);
269
        $email->addData('EmailContent', $this->Content);
270
        $email->addData('Callout', $this->Callout);
271
        return $email;
272
    }
273
274
    /**
275
     * Returns an array of email with members by locale
276
     *
277
     * @return array
278
     */
279
    public function getEmailByLocales()
280
    {
281
        $membersByLocale = [];
282
        foreach ($this->getAllRecipients() as $r) {
283
            if (!isset($membersByLocale[$r->Locale])) {
284
                $membersByLocale[$r->Locale] = [];
285
            }
286
            $membersByLocale[$r->Locale][] = $r;
287
        }
288
289
        $emails = [];
290
        foreach ($membersByLocale as $locale => $membersList) {
291
            $email = Email::create();
292
            if (!$email instanceof BetterEmail) {
293
                throw new Exception("Make sure you are injecting the BetterEmail class instead of your base Email class");
294
            }
295
            if ($this->Sender) {
296
                $email->setFrom($this->Sender);
297
            }
298
            foreach ($membersList as $r) {
299
                $email->addBCC($r->Email, $r->FirstName . ' ' . $r->Surname);
300
            }
301
302
            // Localize
303
            $EmailingID = $this->ID;
304
            FluentHelper::withLocale($locale, function () use ($EmailingID, $email) {
305
                $Emailing = Emailing::get()->byID($EmailingID);
306
                $email->setSubject($Emailing->Subject);
307
                $email->addData('EmailContent', $Emailing->Content);
308
                $email->addData('Callout', $Emailing->Callout);
309
            });
310
311
            $emails[$locale] = $email;
312
        }
313
        return $emails;
314
    }
315
}
316