Completed
Branch master (0b66f1)
by Michael
33:21
created

Email::getBccAddresses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * You may not change or alter any portion of this comment or credits of supporting
4
 * developers from this source code or any supporting source code which is considered
5
 * copyrighted (c) material of the original  comment or credit authors.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
 *
11
 * @copyright 2018 XOOPS Project (https://xoops.org)
12
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
13
 * @link      https://xoops.org
14
 */
15
16
namespace Xoops\Core\Service\Data;
17
18
use Xmf\Assert;
19
use Xoops\Core\Service\Data\EmailAddress;
20
use Xoops\Core\Service\Data\EmailAddressList;
21
use Xoops\Core\Service\Data\EmailAttachment;
22
use Xoops\Core\Service\Data\EmailAttachmentSet;
23
24
/**
25
 * The Email data object is a full email message using EmailAddress addresses.
26
 * This differs from the Message object by allowing communication to occur with
27
 * non-users and/or with full email capabilities such as multiple recipients,
28
 * CC, BCC, Reply To and attachments.
29
 *
30
 * This is an Immutable data object. That means any changes to the data (state)
31
 * return a new object, while the internal state of the original object is preserved.
32
 *
33
 * All data is validated for type and value, and an exception is generated when
34
 * data on any operation for a property when it is not valid.
35
 *
36
 * The Email data object is used for message and mailer services
37
 *
38
 * @category  Xoops\Core\Service\Data
39
 * @package   Xoops\Core
40
 * @author    Richard Griffith <[email protected]>
41
 * @copyright 2018 XOOPS Project (https://xoops.org)
42
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
43
 * @link      https://xoops.org
44
 */
45
class Email
46
{
47
    /** @var string $subject the subject of the message, a required non-empty string */
48
    protected $subject;
49
50
    /** @var string $body the body of the message, a required non-empty string */
51
    protected $body;
52
53
    /** @var string $htmlBody an alternate representation of the message body, a non-empty string */
54
    protected $htmlBody;
55
56
    /** @var EmailAddress $fromAddress the email address that message is from */
57
    protected $fromAddress;
58
59
    /** @var EmailAddressList $toAddresses addresses that the message is to */
60
    protected $toAddresses;
61
62
    /** @var EmailAddressList $ccAddresses addresses the message should be CC'ed to */
63
    protected $ccAddresses;
64
65
    /** @var EmailAddressList $bccAddresses addresses the message should be BCC'ed to */
66
    protected $bccAddresses;
67
68
    /** @var EmailAddressList $replyToAddresses addresses that should receive replies to this message */
69
    protected $replyToAddresses;
70
71
    /** @var EmailAddress $readReceiptAddress the email address requesting a read receipt */
72
    protected $readReceiptAddress;
73
74
    /** @var EmailAttachmentSet attachments to be part of the email */
75
    protected $attachmentSet;
76
77
    /* assert messages */
78
    protected const MESSAGE_BODY    = 'Body must be specified';
79
    protected const MESSAGE_FROM    = 'From address must be specified';
80
    protected const MESSAGE_SUBJECT = 'Subject must be specified';
81
    protected const MESSAGE_BCC     = 'Invalid BCC address specified';
82
    protected const MESSAGE_CC      = 'Invalid CC address specified';
83
    protected const MESSAGE_REPLY   = 'Invalid Reply To address specified';
84
    protected const MESSAGE_RR      = 'Invalid Read Receipt address specified';
85
    protected const MESSAGE_TO      = 'A valid To address must be specified';
86
87
    protected const PROPERTY_ADDRESS_BCC   = 'bccAddresses';
88
    protected const PROPERTY_ADDRESS_CC    = 'ccAddresses';
89
    protected const PROPERTY_ADDRESS_REPLY = 'replyToAddresses';
90
    protected const PROPERTY_ADDRESS_TO    = 'toAddresses';
91
92
    protected const VALID_ADDRESS_PROPERTIES = [
93
        self::PROPERTY_ADDRESS_BCC,
94
        self::PROPERTY_ADDRESS_CC,
95
        self::PROPERTY_ADDRESS_REPLY,
96
        self::PROPERTY_ADDRESS_TO,
97
    ];
98
99
    /**
100
     * Email constructor.
101
     *
102
     * If an argument is null, the corresponding value will not be set. Values can be set
103
     * later with the with*() methods, but each will result in a new object.
104
     *
105
     * @param null|string       $subject     the subject of the message, a non-empty string
106
     * @param null|string       $body        the body of the message, a non-empty string
107
     * @param null|EmailAddress $fromAddress the user id sending the message, a positive integer
108
     * @param null|EmailAddress $toAddress   the user id to receive the message, a positive integer
109
     *
110
     * @throws \InvalidArgumentException
111
     */
112
    public function __construct(
113
        ?string $subject = null,
114
        ?string $body = null,
115
        ?EmailAddress $fromAddress = null,
116
        ?EmailAddress $toAddress = null
117
    ) {
118
        if (null!==$subject) {
119
            $subject = trim($subject);
120
            Assert::stringNotEmpty($subject, static::MESSAGE_SUBJECT);
121
            $this->subject = $subject;
122
        }
123
        if (null!==$body) {
124
            $body = trim($body);
125
            Assert::stringNotEmpty($body, static::MESSAGE_BODY);
126
            $this->body = $body;
127
        }
128
        try {
129
            if (null!==$fromAddress) {
130
                $fromAddress->getEmail();
131
                $this->fromAddress = $fromAddress;
132
            }
133
            if (null!==$toAddress) {
134
                $toAddress->getEmail();
135
                $this->toAddresses = new EmailAddressList([$toAddress]);
136
            }
137
        } catch (\LogicException $e) {
138
            throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
139
        }
140
    }
141
142
    /**
143
     * Return a new object with a the specified body
144
     *
145
     * @param string $body message body
146
     *
147
     * @return Email
148
     *
149
     * @throws \InvalidArgumentException
150
     */
151
    public function withBody(string $body) : Email
152
    {
153
        $body = trim($body);
154
        Assert::stringNotEmpty($body, static::MESSAGE_BODY);
155
        $new = clone $this;
156
        $new->body = $body;
157
        return $new;
158
    }
159
160
    /**
161
     * Return a new object with a the specified HTML body
162
     *
163
     * The htmlBody is optional, while a body (plain text) is required, and must always be specified.
164
     *
165
     * @param string $body HTML message body
166
     *
167
     * @return Email
168
     *
169
     * @throws \InvalidArgumentException
170
     */
171
    public function withHtmlBody(string $body) : Email
172
    {
173
        $body = trim($body);
174
        Assert::stringNotEmpty($body, static::MESSAGE_BODY);
175
        $new = clone $this;
176
        $new->htmlBody = $body;
177
        return $new;
178
    }
179
180
    /**
181
     * Return a new object with a the specified fromAddress
182
     *
183
     * @param EmailAddress $fromAddress the sending/from email address
184
     *
185
     * @return Email a new object with specified change
186
     *
187
     * @throws \InvalidArgumentException (property was not properly set before used)
188
     */
189
    public function withFromAddress(EmailAddress $fromAddress) : Email
190
    {
191
        try {
192
            $fromAddress->getEmail();
193
        } catch (\LogicException $e) {
194
            throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
195
        }
196
197
        $new = clone $this;
198
        $new->fromAddress = $fromAddress;
199
        return $new;
200
    }
201
202
    /**
203
     * Return a new object with a the specified subject
204
     *
205
     * @param string $subject message subject
206
     *
207
     * @return Email
208
     *
209
     * @throws \InvalidArgumentException
210
     */
211
    public function withSubject(string $subject) : Email
212
    {
213
        $subject = trim($subject);
214
        Assert::stringNotEmpty($subject, static::MESSAGE_SUBJECT);
215
        $new = clone $this;
216
        $new->subject = $subject;
217
        return $new;
218
    }
219
220
    /**
221
     * withAddresses - utility method to validate and assign a set of addresses
222
     *
223
     * @param string           $property  property to set, one of VALID_ADDRESS_PROPERTIES
224
     * @param EmailAddressList $addresses addresses to be assigned to property
225
     *
226
     * @return Email a new object with a the specified property set to the specified addresses
227
     *
228
     * @throws \InvalidArgumentException (a property was not set before used)
229
     */
230
    protected function withAddresses(string $property, EmailAddressList $addresses) : Email
231
    {
232
        Assert::oneOf($property, static::VALID_ADDRESS_PROPERTIES);
233
        try {
234
            $addresses->getAddresses();
235
        } catch (\LogicException $e) {
236
            throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
237
        }
238
239
        $new = clone $this;
240
        $new->{$property} = $addresses;
241
        return $new;
242
    }
243
244
    /**
245
     * Return a new object with a the specified bccAddresses
246
     *
247
     * @param EmailAddressList $bccAddresses the addresses to be BCC'ed
248
     *
249
     * @return Email
250
     *
251
     * @throws \InvalidArgumentException (a property was not properly set before used)
252
     */
253
    public function withBccAddresses(EmailAddressList $bccAddresses) : Email
254
    {
255
        return $this->withAddresses(static::PROPERTY_ADDRESS_BCC, $bccAddresses);
256
    }
257
258
    /**
259
     * Return a new object with a the specified ccAddresses
260
     *
261
     * @param EmailAddressList $ccAddresses the addresses to be CC'ed
262
     *
263
     * @return Email
264
     *
265
     * @throws \InvalidArgumentException (a property was not properly set before used)
266
     */
267
    public function withCcAddresses(EmailAddressList $ccAddresses) : Email
268
    {
269
        return $this->withAddresses(static::PROPERTY_ADDRESS_CC, $ccAddresses);
270
    }
271
272
    /**
273
     * Return a new object with a the specified replyToAddresses
274
     *
275
     * @param EmailAddressList $replyToAddresses the addresses to receive replies
276
     *
277
     * @return Email
278
     *
279
     * @throws \InvalidArgumentException (a property was not properly set before used)
280
     */
281
    public function withReplyToAddresses(EmailAddressList $replyToAddresses) : Email
282
    {
283
        return $this->withAddresses(static::PROPERTY_ADDRESS_REPLY, $replyToAddresses);
284
    }
285
286
    /**
287
     * Return a new object with a the specified toAddresses
288
     *
289
     * @param EmailAddressList $toAddresses the addresses to receive the message
290
     *
291
     * @return Email
292
     *
293
     * @throws \InvalidArgumentException (a property was not properly set before used)
294
     */
295
    public function withToAddresses(EmailAddressList $toAddresses) : Email
296
    {
297
        return $this->withAddresses(static::PROPERTY_ADDRESS_TO, $toAddresses);
298
    }
299
300
    /**
301
     * Return a new object with a the specified fromAddress
302
     *
303
     * @param EmailAddress $readReceiptAddress requests a read receipt to this address
304
     *
305
     * @return Email a new object with specified change
306
     *
307
     * @throws \InvalidArgumentException (property was not properly set before used)
308
     */
309
    public function withReadReceiptAddress(EmailAddress $readReceiptAddress) : Email
310
    {
311
        try {
312
            $readReceiptAddress->getEmail();
313
        } catch (\LogicException $e) {
314
            throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
315
        }
316
317
        $new = clone $this;
318
        $new->readReceiptAddress = $readReceiptAddress;
319
        return $new;
320
    }
321
322
    /**
323
     * withAttachments - return a new object with a the specified set of attachments
324
     *
325
     * @param EmailAttachmentSet $attachmentSet
326
     *
327
     * @return Email
328
     *
329
     * @throws \InvalidArgumentException
330
     */
331
    public function withAttachments(EmailAttachmentSet $attachmentSet) : Email
332
    {
333
        try {
334
            $attachmentSet->getAttachments();
335
        } catch (\LogicException $e) {
336
            throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
337
        }
338
339
        $new = clone $this;
340
        $new->attachmentSet = $attachmentSet;
341
        return $new;
342
    }
343
344
    /**
345
     * getBody
346
     *
347
     * @return string the message body
348
     *
349
     * @throws \LogicException (property was not properly set before used)
350
     */
351
    public function getBody() : string
352
    {
353
        try {
354
            Assert::stringNotEmpty($this->body, static::MESSAGE_BODY);
355
        } catch (\InvalidArgumentException $e) {
356
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
357
        }
358
        return $this->body;
359
    }
360
361
    /**
362
     * getHtmlBody
363
     *
364
     * @return string the message body
365
     *
366
     * @throws \LogicException (property was not properly set before used)
367
     */
368
    public function getHtmlBody() : ?string
369
    {
370
        try {
371
            Assert::nullOrStringNotEmpty($this->htmlBody, static::MESSAGE_BODY);
372
        } catch (\InvalidArgumentException $e) {
373
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
374
        }
375
        return $this->htmlBody;
376
    }
377
378
    /**
379
     * getFromAddress
380
     *
381
     * @return EmailAddress the fromAddress
382
     *
383
     * @throws \LogicException (property was not properly set before used)
384
     */
385
    public function getFromAddress() : EmailAddress
386
    {
387
        try {
388
            Assert::notNull($this->fromAddress, static::MESSAGE_FROM);
389
            Assert::isInstanceOf($this->fromAddress, EmailAddress::class, static::MESSAGE_FROM);
390
            $this->fromAddress->getEmail();
391
        } catch (\InvalidArgumentException | \LogicException $e) {
392
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
393
        }
394
        return $this->fromAddress;
395
    }
396
397
    /**
398
     * getSubject
399
     *
400
     * @return string the message subject
401
     *
402
     * @throws \LogicException (property was not properly set before used)
403
     */
404
    public function getSubject() : string
405
    {
406
        try {
407
            Assert::stringNotEmpty($this->subject, static::MESSAGE_SUBJECT);
408
        } catch (\InvalidArgumentException $e) {
409
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
410
        }
411
412
        return $this->subject;
413
    }
414
415
    /**
416
     * getAddresses
417
     *
418
     * @param string $property addresses property to get, one of VALID_ADDRESS_PROPERTIES
419
     * @param string $message  message for any Assert exception
420
     *
421
     * @return EmailAddressList|null the specified addresses property or null if not set
422
     *
423
     * @throws \LogicException (property was not properly set before used)
424
     */
425
    protected function getAddresses(string $property, string $message) : ?EmailAddressList
426
    {
427
        try {
428
            Assert::oneOf($property, static::VALID_ADDRESS_PROPERTIES);
429
            if (null !== $this->{$property}) {
430
                Assert::allIsInstanceOf($this->{$property}->getAddresses(), EmailAddress::class, $message);
431
            }
432
        } catch (\InvalidArgumentException | \LogicException $e) {
433
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
434
        }
435
        return $this->{$property};
436
    }
437
438
    /**
439
     * getBccAddresses
440
     *
441
     * @return EmailAddressList|null the BCC address list or null if not set
442
     *
443
     * @throws \LogicException (property was not properly set before used)
444
     */
445
    public function getBccAddresses() : ?EmailAddressList
446
    {
447
        return $this->getAddresses(static::PROPERTY_ADDRESS_BCC, static::MESSAGE_BCC);
448
    }
449
450
    /**
451
     * getCcAddresses
452
     *
453
     * @return EmailAddressList|null the CC address list or null if not set
454
     *
455
     * @throws \LogicException (property was not properly set before used)
456
     */
457
    public function getCcAddresses() : ?EmailAddressList
458
    {
459
        return $this->getAddresses(static::PROPERTY_ADDRESS_CC, static::MESSAGE_CC);
460
    }
461
462
    /**
463
     * getReplyToAddresses
464
     *
465
     * @return EmailAddressList|null the ReplyTo address list or null if not set
466
     *
467
     * @throws \LogicException (property was not properly set before used)
468
     */
469
    public function getReplyToAddresses() : ?EmailAddressList
470
    {
471
        return $this->getAddresses(static::PROPERTY_ADDRESS_REPLY, static::MESSAGE_REPLY);
472
    }
473
474
    /**
475
     * getToAddresses
476
     *
477
     * @return EmailAddressList the To addresses
478
     *
479
     * @throws \LogicException (property was not properly set before used)
480
     */
481
    public function getToAddresses() : EmailAddressList
482
    {
483
        try {
484
            Assert::notEmpty($this->toAddresses, static::MESSAGE_TO);
485
        } catch (\InvalidArgumentException $e) {
486
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
487
        }
488
        return $this->getAddresses(static::PROPERTY_ADDRESS_TO, static::MESSAGE_TO);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getAddress...TO, static::MESSAGE_TO) could return the type null which is incompatible with the type-hinted return Xoops\Core\Service\Data\EmailAddressList. Consider adding an additional type-check to rule them out.
Loading history...
489
    }
490
491
    /**
492
     * getReadReceiptAddress
493
     *
494
     * @return EmailAddress|null the readReceiptAddress or null if not set
495
     *
496
     * @throws \LogicException (property was not properly set before used)
497
     */
498
    public function getReadReceiptAddress() : ?EmailAddress
499
    {
500
        if (null !== $this->readReceiptAddress) {
501
            try {
502
                Assert::isInstanceOf($this->readReceiptAddress, EmailAddress::class, static::MESSAGE_RR);
503
                $this->readReceiptAddress->getEmail();
504
            } catch (\InvalidArgumentException | \LogicException $e) {
505
                throw new \LogicException($e->getMessage(), $e->getCode(), $e);
506
            }
507
        }
508
        return $this->readReceiptAddress;
509
    }
510
511
    /**
512
     * getAttachments
513
     *
514
     * @return EmailAttachmentSet|null the set of attachments or null if not set
515
     *
516
     * @throws \LogicException (property was not properly set before used)
517
     */
518
    public function getAttachments() : ?EmailAttachmentSet
519
    {
520
        if (null !== $this->attachmentSet) {
521
            try {
522
                $this->attachmentSet->getAttachments();
523
            } catch (\LogicException $e) {
524
                throw new \LogicException($e->getMessage(), $e->getCode(), $e);
525
            }
526
        }
527
        return $this->attachmentSet;
528
    }
529
}
530