Passed
Push — master ( 2ea0b2...d8ed7e )
by Thomas
02:39 queued 11s
created

Emailing::getEmailByLocales()   B

Complexity

Conditions 7
Paths 18

Size

Total Lines 35
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

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