Completed
Push — emailobjects ( 991f7d...4aa702 )
by Richard
07:34
created

Email::withAttachments()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 11
ccs 7
cts 7
cp 1
crap 2
rs 9.4285
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 25
    public function __construct(
113
        ?string $subject = null,
114
        ?string $body = null,
115
        ?EmailAddress $fromAddress = null,
116
        ?EmailAddress $toAddress = null
117
    ) {
118 25
        if (null!==$subject) {
119 3
            $subject = trim($subject);
120 3
            Assert::stringNotEmpty($subject, static::MESSAGE_SUBJECT);
121 2
            $this->subject = $subject;
122
        }
123 25
        if (null!==$body) {
124 3
            $body = trim($body);
125 3
            Assert::stringNotEmpty($body, static::MESSAGE_BODY);
126 2
            $this->body = $body;
127
        }
128
        try {
129 25
            if (null!==$fromAddress) {
130 2
                $fromAddress->getEmail();
131 1
                $this->fromAddress = $fromAddress;
132
            }
133 25
            if (null!==$toAddress) {
134 2
                $toAddress->getEmail();
135 25
                $this->toAddresses = new EmailAddressList([$toAddress]);
136
            }
137 2
        } catch (\LogicException $e) {
138 2
            throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
139
        }
140 25
    }
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 1
    public function withBody(string $body) : Email
152
    {
153 1
        $body = trim($body);
154 1
        Assert::stringNotEmpty($body, static::MESSAGE_BODY);
155 1
        $new = clone $this;
156 1
        $new->body = $body;
157 1
        return $new;
158
    }
159
160
    /**
161
     * Return a new object with a the specified fromAddress
162
     *
163
     * @param EmailAddress $fromAddress the sending/from email address
164
     *
165
     * @return Email a new object with specified change
166
     *
167
     * @throws \InvalidArgumentException (property was not properly set before used)
168
     */
169 1
    public function withFromAddress(EmailAddress $fromAddress) : Email
170
    {
171
        try {
172 1
            $fromAddress->getEmail();
173 1
        } catch (\LogicException $e) {
174 1
            throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
175
        }
176
177 1
        $new = clone $this;
178 1
        $new->fromAddress = $fromAddress;
179 1
        return $new;
180
    }
181
182
    /**
183
     * Return a new object with a the specified subject
184
     *
185
     * @param string $subject message subject
186
     *
187
     * @return Email
188
     *
189
     * @throws \InvalidArgumentException
190
     */
191 1
    public function withSubject(string $subject) : Email
192
    {
193 1
        $subject = trim($subject);
194 1
        Assert::stringNotEmpty($subject, static::MESSAGE_SUBJECT);
195 1
        $new = clone $this;
196 1
        $new->subject = $subject;
197 1
        return $new;
198
    }
199
200
    /**
201
     * withAddresses - utility method to validate and assign a set of addresses
202
     *
203
     * @param string           $property  property to set, one of VALID_ADDRESS_PROPERTIES
204
     * @param EmailAddressList $addresses addresses to be assigned to property
205
     *
206
     * @return Email a new object with a the specified property set to the specified addresses
207
     *
208
     * @throws \InvalidArgumentException (a property was not set before used)
209
     */
210 4
    protected function withAddresses(string $property, EmailAddressList $addresses) : Email
211
    {
212 4
        Assert::oneOf($property, static::VALID_ADDRESS_PROPERTIES);
213
        try {
214 4
            $addresses->getAddresses();
215 4
        } catch (\LogicException $e) {
216 4
            throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
217
        }
218
219 4
        $new = clone $this;
220 4
        $new->{$property} = $addresses;
221 4
        return $new;
222
    }
223
224
    /**
225
     * Return a new object with a the specified bccAddresses
226
     *
227
     * @param EmailAddressList $bccAddresses the addresses to be BCC'ed
228
     *
229
     * @return Email
230
     *
231
     * @throws \InvalidArgumentException (a property was not properly set before used)
232
     */
233 1
    public function withBccAddresses(EmailAddressList $bccAddresses) : Email
234
    {
235 1
        return $this->withAddresses(static::PROPERTY_ADDRESS_BCC, $bccAddresses);
236
    }
237
238
    /**
239
     * Return a new object with a the specified ccAddresses
240
     *
241
     * @param EmailAddressList $ccAddresses the addresses to be CC'ed
242
     *
243
     * @return Email
244
     *
245
     * @throws \InvalidArgumentException (a property was not properly set before used)
246
     */
247 1
    public function withCcAddresses(EmailAddressList $ccAddresses) : Email
248
    {
249 1
        return $this->withAddresses(static::PROPERTY_ADDRESS_CC, $ccAddresses);
250
    }
251
252
    /**
253
     * Return a new object with a the specified replyToAddresses
254
     *
255
     * @param EmailAddressList $replyToAddresses the addresses to receive replies
256
     *
257
     * @return Email
258
     *
259
     * @throws \InvalidArgumentException (a property was not properly set before used)
260
     */
261 1
    public function withReplyToAddresses(EmailAddressList $replyToAddresses) : Email
262
    {
263 1
        return $this->withAddresses(static::PROPERTY_ADDRESS_REPLY, $replyToAddresses);
264
    }
265
266
    /**
267
     * Return a new object with a the specified toAddresses
268
     *
269
     * @param EmailAddressList $toAddresses the addresses to receive the message
270
     *
271
     * @return Email
272
     *
273
     * @throws \InvalidArgumentException (a property was not properly set before used)
274
     */
275 1
    public function withToAddresses(EmailAddressList $toAddresses) : Email
276
    {
277 1
        return $this->withAddresses(static::PROPERTY_ADDRESS_TO, $toAddresses);
278
    }
279
280
    /**
281
     * Return a new object with a the specified fromAddress
282
     *
283
     * @param EmailAddress $readReceiptAddress requests a read receipt to this address
284
     *
285
     * @return Email a new object with specified change
286
     *
287
     * @throws \InvalidArgumentException (property was not properly set before used)
288
     */
289 1
    public function withReadReceiptAddress(EmailAddress $readReceiptAddress) : Email
290
    {
291
        try {
292 1
            $readReceiptAddress->getEmail();
293 1
        } catch (\LogicException $e) {
294 1
            throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
295
        }
296
297 1
        $new = clone $this;
298 1
        $new->readReceiptAddress = $readReceiptAddress;
299 1
        return $new;
300
    }
301
302
    /**
303
     * withAttachments - return a new object with a the specified set of attachments
304
     *
305
     * @param EmailAttachmentSet $attachmentSet
306
     *
307
     * @return Email
308
     *
309
     * @throws \InvalidArgumentException
310
     */
311 1
    public function withAttachments(EmailAttachmentSet $attachmentSet) : Email
312
    {
313
        try {
314 1
            $attachmentSet->getAttachments();
315 1
        } catch (\LogicException $e) {
316 1
            throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
317
        }
318
319 1
        $new = clone $this;
320 1
        $new->attachmentSet = $attachmentSet;
321 1
        return $new;
322
    }
323
324
    /**
325
     * getBody
326
     *
327
     * @return string the message body
328
     *
329
     * @throws \LogicException (property was not properly set before used)
330
     */
331 4
    public function getBody() : string
332
    {
333
        try {
334 4
            Assert::stringNotEmpty($this->body, static::MESSAGE_BODY);
335 1
        } catch (\InvalidArgumentException $e) {
336 1
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
337
        }
338 3
        return $this->body;
339
    }
340
341
    /**
342
     * getFromAddress
343
     *
344
     * @return EmailAddress the fromAddress
345
     *
346
     * @throws \LogicException (property was not properly set before used)
347
     */
348 4
    public function getFromAddress() : EmailAddress
349
    {
350
        try {
351 4
            Assert::notNull($this->fromAddress, static::MESSAGE_FROM);
352 3
            Assert::isInstanceOf($this->fromAddress, EmailAddress::class, static::MESSAGE_FROM);
353 3
            $this->fromAddress->getEmail();
354 2
        } catch (\InvalidArgumentException | \LogicException $e) {
355 2
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
356
        }
357 2
        return $this->fromAddress;
358
    }
359
360
    /**
361
     * getSubject
362
     *
363
     * @return string the message subject
364
     *
365
     * @throws \LogicException (property was not properly set before used)
366
     */
367 4
    public function getSubject() : string
368
    {
369
        try {
370 4
            Assert::stringNotEmpty($this->subject, static::MESSAGE_SUBJECT);
371 1
        } catch (\InvalidArgumentException $e) {
372 1
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
373
        }
374
375 3
        return $this->subject;
376
    }
377
378
    /**
379
     * getAddresses
380
     *
381
     * @param string $property addresses property to get, one of VALID_ADDRESS_PROPERTIES
382
     * @param string $message  message for any Assert exception
383
     *
384
     * @return EmailAddressList|null the specified addresses property or null if not set
385
     *
386
     * @throws \LogicException (property was not properly set before used)
387
     */
388 6
    protected function getAddresses(string $property, string $message) : ?EmailAddressList
389
    {
390
        try {
391 6
            Assert::oneOf($property, static::VALID_ADDRESS_PROPERTIES);
392 6
            if (null !== $this->{$property}) {
393 6
                Assert::allIsInstanceOf($this->{$property}->getAddresses(), EmailAddress::class, $message);
394
            }
395 1
        } catch (\InvalidArgumentException | \LogicException $e) {
396 1
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
397
        }
398 5
        return $this->{$property};
399
    }
400
401
    /**
402
     * getBccAddresses
403
     *
404
     * @return EmailAddressList|null the BCC address list or null if not set
405
     *
406
     * @throws \LogicException (property was not properly set before used)
407
     */
408 1
    public function getBccAddresses() : ?EmailAddressList
409
    {
410 1
        return $this->getAddresses(static::PROPERTY_ADDRESS_BCC, static::MESSAGE_BCC);
411
    }
412
413
    /**
414
     * getCcAddresses
415
     *
416
     * @return EmailAddressList|null the CC address list or null if not set
417
     *
418
     * @throws \LogicException (property was not properly set before used)
419
     */
420 1
    public function getCcAddresses() : ?EmailAddressList
421
    {
422 1
        return $this->getAddresses(static::PROPERTY_ADDRESS_CC, static::MESSAGE_CC);
423
    }
424
425
    /**
426
     * getReplyToAddresses
427
     *
428
     * @return EmailAddressList|null the ReplyTo address list or null if not set
429
     *
430
     * @throws \LogicException (property was not properly set before used)
431
     */
432 1
    public function getReplyToAddresses() : ?EmailAddressList
433
    {
434 1
        return $this->getAddresses(static::PROPERTY_ADDRESS_REPLY, static::MESSAGE_REPLY);
435
    }
436
437
    /**
438
     * getToAddresses
439
     *
440
     * @return EmailAddressList the To addresses
441
     *
442
     * @throws \LogicException (property was not properly set before used)
443
     */
444 5
    public function getToAddresses() : EmailAddressList
445
    {
446
        try {
447 5
            Assert::notEmpty($this->toAddresses, static::MESSAGE_TO);
448 2
        } catch (\InvalidArgumentException $e) {
449 2
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
450
        }
451 3
        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...
452
    }
453
454
    /**
455
     * getReadReceiptAddress
456
     *
457
     * @return EmailAddress|null the readReceiptAddress or null if not set
458
     *
459
     * @throws \LogicException (property was not properly set before used)
460
     */
461 2
    public function getReadReceiptAddress() : ?EmailAddress
462
    {
463 2
        if (null !== $this->readReceiptAddress) {
464
            try {
465 2
                Assert::isInstanceOf($this->readReceiptAddress, EmailAddress::class, static::MESSAGE_RR);
466 2
                $this->readReceiptAddress->getEmail();
467 1
            } catch (\InvalidArgumentException | \LogicException $e) {
468 1
                throw new \LogicException($e->getMessage(), $e->getCode(), $e);
469
            }
470
        }
471 1
        return $this->readReceiptAddress;
472
    }
473
474
    /**
475
     * getAttachments
476
     *
477
     * @return EmailAttachmentSet|null the set of attachments or null if not set
478
     *
479
     * @throws \LogicException (property was not properly set before used)
480
     */
481 2
    public function getAttachments() : ?EmailAttachmentSet
482
    {
483 2
        if (null !== $this->attachmentSet) {
484
            try {
485 2
                $this->attachmentSet->getAttachments();
486 1
            } catch (\LogicException $e) {
487 1
                throw new \LogicException($e->getMessage(), $e->getCode(), $e);
488
            }
489
        }
490 1
        return $this->attachmentSet;
491
    }
492
}
493