Test Failed
Push — master ( 741545...e25e21 )
by Julien
11:23
created

Email::getBcc()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * This file is part of the Zemit Framework.
4
 *
5
 * (c) Zemit Team <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE.txt
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Zemit\Models;
12
13
use Zemit\Models\Base\AbstractEmail;
14
use Phalcon\Mailer\Manager;
15
use Phalcon\Messages\Message;
16
use Phalcon\Validation\Validator\PresenceOf;
17
use Phalcon\Validation\Validator\StringLength\Max;
18
use Phalcon\Validation\Validator\Uniqueness;
19
use Phalcon\Validation\Validator\Numericality;
20
21
/**
22
 * Class Email
23
 *
24
 * @property Template $TemplateEntity
25
 * @property EmailFile $FileNode
26
 * @property File $FileList
27
 *
28
 * @method Template getTemplateEntity($params = null)
29
 * @method EmailFile getFileNode($params = null)
30
 * @method File getFileList($params = null)
31
 *
32
 * @package Zemit\Models
33
 */
34
class Email extends AbstractEmail
35
{
36
    protected $deleted = self::NO;
37
    protected $sent = self::NO;
38
39
    /**
40
     * @param string|null $index
41
     *
42
     * @return mixed
43
     */
44
    public function setTemplateByIndex(string $index = null)
45
    {
46
        $template = Template::findFirstByIndex($index);
0 ignored issues
show
Bug introduced by
The method findFirstByIndex() does not exist on Zemit\Models\Template. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

46
        /** @scrutinizer ignore-call */ 
47
        $template = Template::findFirstByIndex($index);
Loading history...
47
        if ($template) {
0 ignored issues
show
introduced by
$template is of type Zemit\Mvc\Model\Phalcon\Mvc\Model\Resultset, thus it always evaluated to true.
Loading history...
48
            $this->setTemplateId((int)$template->getId());
49
            $this->syncTemplate($template);
50
        }
51
52
        return $template;
53
    }
54
55
    /**
56
     * Get Subject
57
     * - Interpolation
58
     *
59
     * @param array|null $meta
60
     */
61
    public function getSubject(array $meta = null)
62
    {
63
        $meta ??= $this->getMeta();
64
65
        return $this->cleanEmptyParameters($this->interpolate(parent::getSubject(), $meta));
66
    }
67
68
    /**
69
     * Get Content
70
     * - Interpolation
71
     *
72
     * @param array|null $meta
73
     */
74
    public function getContent(array $meta = null)
75
    {
76
        $meta ??= $this->getMeta();
77
78
        return $this->cleanEmptyParameters($this->interpolate(parent::getContent(), $meta));
79
    }
80
81
    /**
82
     * Method to set the value of field meta
83
     * - Json Encode Meta
84
     *
85
     * @param null $meta
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $meta is correct as it would always require null to be passed?
Loading history...
86
     *
87
     * @return $this|Email
88
     */
89
    public function setMeta($meta = null)
90
    {
91
        return parent::setMeta($this->jsonEncode($meta));
0 ignored issues
show
Bug introduced by
It seems like $this->jsonEncode($meta) can also be of type false; however, parameter $meta of Zemit\Models\Base\AbstractEmail::setMeta() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

91
        return parent::setMeta(/** @scrutinizer ignore-type */ $this->jsonEncode($meta));
Loading history...
92
    }
93
94
    /**
95
     * Returns the value of field meta
96
     * - Json Decode Meta
97
     */
98
    public function getMeta()
99
    {
100
        return $this->jsonDecode(parent::getMeta());
101
    }
102
103
    /**
104
     * Method to set the value of field bcc
105
     * - Json Encode Bcc
106
     *
107
     * @param null $bcc
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $bcc is correct as it would always require null to be passed?
Loading history...
108
     *
109
     * @return $this|Email
110
     */
111
    public function setBcc($bcc = null)
112
    {
113
        return parent::setBcc($this->jsonEncode($bcc));
0 ignored issues
show
Bug introduced by
It seems like $this->jsonEncode($bcc) can also be of type false; however, parameter $bcc of Zemit\Models\Base\AbstractEmail::setBcc() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

113
        return parent::setBcc(/** @scrutinizer ignore-type */ $this->jsonEncode($bcc));
Loading history...
114
    }
115
116
    /**
117
     * Returns the value of field bcc
118
     * - Json Decode Bcc
119
     */
120
    public function getBcc()
121
    {
122
        return $this->jsonDecode(parent::getBcc());
123
    }
124
125
    /**
126
     * Method to set the value of field cc
127
     * - Json Encode Cc
128
     *
129
     * @param null $cc
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $cc is correct as it would always require null to be passed?
Loading history...
130
     *
131
     * @return $this|Email
132
     */
133
    public function setCc($cc = null)
134
    {
135
        return parent::setCc($this->jsonEncode($cc));
0 ignored issues
show
Bug introduced by
It seems like $this->jsonEncode($cc) can also be of type false; however, parameter $cc of Zemit\Models\Base\AbstractEmail::setCc() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

135
        return parent::setCc(/** @scrutinizer ignore-type */ $this->jsonEncode($cc));
Loading history...
136
    }
137
138
    /**
139
     * Returns the value of field cc
140
     * - Json Decode Cc
141
     */
142
    public function getCc()
143
    {
144
        return $this->jsonDecode(parent::getCc());
145
    }
146
147
    /**
148
     * Method to set the value of field to
149
     * - Json Encode To
150
     *
151
     * @param null $to
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $to is correct as it would always require null to be passed?
Loading history...
152
     *
153
     * @return $this|Email
154
     */
155
    public function setTo($to = null)
156
    {
157
        return parent::setTo($this->jsonEncode($to));
0 ignored issues
show
Bug introduced by
It seems like $this->jsonEncode($to) can also be of type false; however, parameter $to of Zemit\Models\Base\AbstractEmail::setTo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

157
        return parent::setTo(/** @scrutinizer ignore-type */ $this->jsonEncode($to));
Loading history...
158
    }
159
160
    /**
161
     * Returns the value of field to
162
     * - Json Decode To
163
     */
164
    public function getTo()
165
    {
166
        return $this->jsonDecode(parent::getTo());
167
    }
168
169
    /**
170
     * Method to set the value of field `from`
171
     * - Json Encode From
172
     *
173
     * @param null $from
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $from is correct as it would always require null to be passed?
Loading history...
174
     *
175
     * @return $this|Email
176
     */
177
    public function setFrom($from = null)
178
    {
179
        return parent::setFrom($this->jsonEncode($from));
0 ignored issues
show
Bug introduced by
It seems like $this->jsonEncode($from) can also be of type false; however, parameter $from of Zemit\Models\Base\AbstractEmail::setFrom() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

179
        return parent::setFrom(/** @scrutinizer ignore-type */ $this->jsonEncode($from));
Loading history...
180
    }
181
182
    /**
183
     * Returns the value of field `from`
184
     * - Json Decode From
185
     */
186
    public function getFrom()
187
    {
188
        return $this->jsonDecode(parent::getFrom());
189
    }
190
191
    /**
192
     * Method to set the value of field `read_receipt_to`
193
     * - Json Encode `ReadReceiptTo`
194
     *
195
     * @param null $readReceiptTo
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $readReceiptTo is correct as it would always require null to be passed?
Loading history...
196
     *
197
     * @return $this|Email
198
     */
199
    public function setReadReceiptTo($readReceiptTo = null)
200
    {
201
        return parent::setReadReceiptTo($this->jsonEncode($readReceiptTo));
0 ignored issues
show
Bug introduced by
It seems like $this->jsonEncode($readReceiptTo) can also be of type false; however, parameter $readReceiptTo of Zemit\Models\Base\Abstra...ail::setReadReceiptTo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

201
        return parent::setReadReceiptTo(/** @scrutinizer ignore-type */ $this->jsonEncode($readReceiptTo));
Loading history...
202
    }
203
204
    /**
205
     * Returns the value of field `read_receipt_to`
206
     * - Json Decode `ReadReceiptTo`
207
     */
208
    public function getReadReceiptTo()
209
    {
210
        return $this->jsonDecode(parent::getReadReceiptTo());
211
    }
212
213
    /**
214
     * Initialize
215
     * - Relationships
216
     */
217
    public function initialize()
218
    {
219
        parent::initialize();
220
221
        $this->hasOne('templateId', Template::class, 'id', ['alias' => 'TemplateEntity']);
222
        $this->hasMany('id', EmailFile::class, 'emailId', ['alias' => 'FileNode']);
223
224
        $this->hasManyToMany('id', EmailFile::class, 'emailId',
225
            'fieldId', File::class, 'id', ['alias' => 'FileList']);
226
    }
227
228
    /**
229
     * Basic default validation
230
     * @return bool
231
     */
232
    public function validation()
233
    {
234
        $validator = $this->genericValidation();
235
236
        $validator->add('templateId', new PresenceOf(['message' => $this->_('required')]));
237
238
        $validator->add('uuid', new PresenceOf(['message' => $this->_('required')]));
239
        $validator->add('uuid', new Uniqueness(['message' => $this->_('not-unique')]));
240
        $validator->add('uuid', new Max(['max' => 255, 'message' => $this->_('length-exceeded')]));
241
242
        $validator->add('from', new PresenceOf(['message' => $this->_('required')]));
243
        $validator->add('from', new Max(['max' => 500, 'message' => $this->_('length-exceeded')]));
244
        $validator->add('to', new PresenceOf(['message' => $this->_('required')]));
245
246
        $validator->add('subject', new PresenceOf(['message' => $this->_('required')]));
247
        $validator->add('subject', new Max(['max' => 255, 'message' => $this->_('length-exceeded')]));
248
249
        $validator->add('content', new PresenceOf(['message' => $this->_('required')]));
250
251
        $validator->add('sent', new Numericality(['message' => $this->_('not-numeric')]));
252
253
        $validator->add('viewPath ', new Max(['max' => 255, 'message' => $this->_('length-exceeded')]));
254
255
        return $this->validate($validator);
256
    }
257
258
    /**
259
     * @TODO
260
     */
261
    public function prepareSave()
262
    {
263
        $this->setFrom(is_array($this->getFrom()) ? $this->jsonEncode($this->getFrom()) : $this->getFrom());
0 ignored issues
show
Bug introduced by
It seems like is_array($this->getFrom(...m()) : $this->getFrom() can also be of type false and string; however, parameter $from of Zemit\Models\Email::setFrom() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

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

263
        $this->setFrom(/** @scrutinizer ignore-type */ is_array($this->getFrom()) ? $this->jsonEncode($this->getFrom()) : $this->getFrom());
Loading history...
264
    }
265
266
267
    /**
268
     * Sync template data into this model
269
     * - Subject
270
     * - Content
271
     *
272
     * @param null $template
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $template is correct as it would always require null to be passed?
Loading history...
273
     */
274
    public function syncTemplate($template = null)
275
    {
276
        $template ??= $this->getTemplateEntity();
277
278
        $subject = $this->getSubject();
279
        $content = $this->getContent();
280
281
        if ($template) {
0 ignored issues
show
introduced by
$template is of type Zemit\Models\Template, thus it always evaluated to true.
Loading history...
282
            if (empty($subject)) {
283
                $this->setSubject($template->getSubject());
284
            }
285
            if (empty($content)) {
286
                $this->setContent($template->getContent());
287
            }
288
        }
289
    }
290
291
    /**
292
     * Remove un-replaced {}
293
     *
294
     * @param $string
295
     *
296
     * @return array|mixed|string|string[]|\Traversable|null
297
     */
298
    public function cleanEmptyParameters($string, $regex = '/\{+([^\}]|)+\}+/im')
299
    {
300
        if (is_string($string)) {
301
            $string = preg_replace($regex, null, $string);
302
        }
303
        else if (is_array($string) || $string instanceof \Traversable) {
304
            foreach ($string as $key => $value) {
305
                $string[$key] = $this->cleanEmptyParameters($value);
306
            }
307
        }
308
309
        return $string;
310
    }
311
312
    /**
313
     * Interpolation
314
     *
315
     * @param $string
316
     * @param $meta
317
     *
318
     * @return array|string|string[]
319
     */
320
    public function interpolate($string, $meta)
321
    {
322
        $meta ??= $this->getMeta();
323
324
        if (is_string($string)) {
325
            $from = [];
326
            $to = [];
327
            self::loopMeta($from, $to, $meta);
0 ignored issues
show
Bug introduced by
The method loopMeta() does not exist on Zemit\Models\Email. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

327
            self::/** @scrutinizer ignore-call */ 
328
                  loopMeta($from, $to, $meta);
Loading history...
328
329
            return str_replace($from, $to, $string);
330
        }
331
        if (is_array($string) || $string instanceof \Traversable) {
332
            foreach ($string as $key => $value) {
333
                $string[$key] = $this->interpolate($value, $meta);
334
            }
335
        }
336
337
        return $string;
338
    }
339
340
    /**
341
     * Send the email
342
     *
343
     * @return bool
344
     */
345
    public function send($force = false)
346
    {
347
        // skip or force resend
348
        if (!$force && $this->getSent()) {
349
            return false;
350
        }
351
352
        // Preparing message
353
        /** @var Manager $mailer */
354
        $mailer = $this->getDI()->get('mailer');
355
        $viewPath = $this->getViewPath();
356
357
        $config = $this->getDI()->get('config');
358
        $frontendPath = dirname($config->modules->frontend->path);
359
        $frontendViewPath = $frontendPath . '/Views/';
360
361
        // Set email entity into view parameter
362
        $params = ['email' => $this, 't' => $this->getTranslate()];
0 ignored issues
show
Bug introduced by
The method getTranslate() does not exist on Zemit\Models\Email. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

362
        $params = ['email' => $this, 't' => $this->/** @scrutinizer ignore-call */ getTranslate()];
Loading history...
363
364
        // Append meta to view parameters
365
        $meta = $this->getMeta() ?: [];
366
        if (is_array($meta)) {
367
            foreach ($meta as $param => $object) {
368
                $params[$param] = $object;
369
            }
370
        }
371
372
        // Retrieve the message raw content
373
        $message = empty($viewPath) ? $mailer->createMessage()->content($this->getContent()) : $mailer->createMessageFromView('template/layout', $params, $frontendViewPath);
374
375
        $emails = [];
376
        foreach (['readReceiptTo', 'from', 'to', 'cc', 'bcc'] as $key) {
377
            $tmp = $this->{'get' . ucfirst($key)}();
378
            $tmp = is_array($tmp) ? $tmp : [$tmp];
379
            $emails[$key] = array_values(array_filter(array_unique($tmp))) ? : null;
380
        }
381
382
        // If from is empty, build it from the config
383
        if (empty($emails['from'])) {
384
            $from = $this->getDI()->get('config')->mailer->from;
385
            $this->setFrom([$from->email => $from->name]);
386
        }
387
388
        // Build the message
389
        $message->getMessage()
390
            ->setSubject($this->getSubject())
391
            ->setReadReceiptTo($this->getReadReceiptTo())
0 ignored issues
show
Bug introduced by
It seems like $this->getReadReceiptTo() can also be of type string; however, parameter $addresses of Swift_Mime_SimpleMessage::setReadReceiptTo() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

391
            ->setReadReceiptTo(/** @scrutinizer ignore-type */ $this->getReadReceiptTo())
Loading history...
392
            ->setFrom($this->getFrom())
393
            ->setCc($this->getCc())
394
            ->setBcc($this->getBcc())
395
            ->setTo($this->getTo())
396
            ->setCharset('utf-8');
397
398
        //Attach file to email
399
        $emailFileNode = $this->getFileNode();
400
        foreach ($emailFileNode as $node) {
401
            /** @var File $file */
402
            $file = $node->getFile();
403
404
            if ($file) {
405
                if (file_exists($file->getFilePath())) {
0 ignored issues
show
Bug introduced by
It seems like $file->getFilePath() can also be of type null; however, parameter $filename of file_exists() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

405
                if (file_exists(/** @scrutinizer ignore-type */ $file->getFilePath())) {
Loading history...
406
                    $attachFile = \Swift_Attachment::fromPath($file->getFilePath());
407
                    $attachFile->setFilename($file->getName());
408
                    $message->getMessage()->attach($attachFile);
409
                }
410
            }
411
        }
412
413
        // Sending message
414
        $this->setSent($message->send());
415
416
        // Message not sent, append an error message
417
        if (!$this->getSent()) {
418
            $this->appendMessage(new Message('Message not sent', 'sent', 'NotSent', 400));
419
        }
420
421
        // Message sent, update time and sender identity
422
        else {
423
            $this->setSentAt(date(self::DATETIME_FORMAT));
424
            $this->setSentBy($this->getCurrentUserId());
425
        }
426
427
        return (!$this->hasSnapshotData() || $this->hasChanged()) && $this->save();
428
    }
429
}
430