Completed
Push — emailobjects ( 991f7d )
by Richard
07:33
created

Email::withReplyToAddresses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
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
23
/**
24
 * The Email data object is a full email message using EmailAddress addresses.
25
 * This differs from the Message object by allowing communication to occur with
26
 * non-users and/or with full email capabilities such as multiple recipients,
27
 * CC, BCC, Reply To and attachments.
28
 *
29
 * This is an Immutable data object. That means any changes to the data (state)
30
 * return a new object, while the internal state of the original object is preserved.
31
 *
32
 * All data is validated for type and value, and an exception is generated when
33
 * data on any operation for a property when it is not valid.
34
 *
35
 * The Email data object is used for message and mailer services
36
 *
37
 * @category  Xoops\Core\Service\Data
38
 * @package   Xoops\Core
39
 * @author    Richard Griffith <[email protected]>
40
 * @copyright 2018 XOOPS Project (https://xoops.org)
41
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
42
 * @link      https://xoops.org
43
 */
44
class Email
45
{
46
    /** @var string $subject the subject of the message, a required non-empty string */
47
    protected $subject;
48
49
    /** @var string $body the body of the message, a required non-empty string */
50
    protected $body;
51
52
    /** @var string $htmlBody an alternate representation of the message body, a non-empty string */
53
    protected $htmlBody;
54
55
    /** @var EmailAddress $fromAddress the email address that message is from */
56
    protected $fromAddress;
57
58
    /** @var EmailAddressList $toAddresses array of addresses that the message is to */
59
    protected $toAddresses;
60
61
    /** @var EmailAddressList $ccAddresses array of addresses the message should be CC'ed to */
62
    protected $ccAddresses;
63
64
    /** @var EmailAddressList $bccAddresses array of addresses the message should be BCC'ed to */
65
    protected $bccAddresses;
66
67
    /** @var EmailAddressList $replyToAddresses array of addresses that should receive replies to this message */
68
    protected $replyToAddresses;
69
70
    /** @var EmailAddress $readReceiptAddress the email address that message is from */
71
    protected $readReceiptAddress;
72
73
    /* assert messages */
74
    protected const MESSAGE_BODY    = 'Body must be specified';
75
    protected const MESSAGE_FROM    = 'From address must be specified';
76
    protected const MESSAGE_SUBJECT = 'Subject must be specified';
77
    protected const MESSAGE_BCC     = 'Invalid BCC address specified';
78
    protected const MESSAGE_CC      = 'Invalid CC address specified';
79
    protected const MESSAGE_REPLY   = 'Invalid Reply To address specified';
80
    protected const MESSAGE_RR      = 'Invalid Read Receipt address specified';
81
    protected const MESSAGE_TO      = 'A valid To address must be specified';
82
83
    protected const PROPERTY_ADDRESS_BCC   = 'bccAddresses';
84
    protected const PROPERTY_ADDRESS_CC    = 'ccAddresses';
85
    protected const PROPERTY_ADDRESS_REPLY = 'replyToAddresses';
86
    protected const PROPERTY_ADDRESS_TO    = 'toAddresses';
87
88
    protected const VALID_ADDRESS_PROPERTIES = [
89
        self::PROPERTY_ADDRESS_BCC,
90
        self::PROPERTY_ADDRESS_CC,
91
        self::PROPERTY_ADDRESS_REPLY,
92
        self::PROPERTY_ADDRESS_TO,
93
    ];
94
95
    /**
96
     * Email constructor.
97
     *
98
     * If an argument is null, the corresponding value will not be set. Values can be set
99
     * later with the with*() methods, but each will result in a new object.
100
     *
101
     * @param null|string       $subject     the subject of the message, a non-empty string
102
     * @param null|string       $body        the body of the message, a non-empty string
103
     * @param null|EmailAddress $fromAddress the user id sending the message, a positive integer
104
     * @param null|EmailAddress $toAddress   the user id to receive the message, a positive integer
105
     *
106
     * @throws \InvalidArgumentException
107
     */
108 23
    public function __construct(
109
        ?string $subject = null,
110
        ?string $body = null,
111
        ?EmailAddress $fromAddress = null,
112
        ?EmailAddress $toAddress = null
113
    ) {
114 23
        if (null!==$subject) {
115 3
            $subject = trim($subject);
116 3
            Assert::stringNotEmpty($subject, static::MESSAGE_SUBJECT);
117 2
            $this->subject = $subject;
118
        }
119 23
        if (null!==$body) {
120 3
            $body = trim($body);
121 3
            Assert::stringNotEmpty($body, static::MESSAGE_BODY);
122 2
            $this->body = $body;
123
        }
124 23
        if (null!==$fromAddress) {
125
            try {
126 2
                $fromAddress->getEmail();
127 1
            } catch (\LogicException $e) {
128 1
                throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
129
            }
130 1
            $this->fromAddress = $fromAddress;
131
        }
132 23
        if (null!==$toAddress) {
133
            try {
134 2
                $toAddress->getEmail();
135 1
            } catch (\LogicException $e) {
136 1
                throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
137
            }
138 1
            $this->toAddresses = new EmailAddressList([$toAddress]);
139
        }
140 23
    }
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
     * getBody
304
     *
305
     * @return string the message body
306
     *
307
     * @throws \LogicException (property was not properly set before used)
308
     */
309 4
    public function getBody() : string
310
    {
311
        try {
312 4
            Assert::stringNotEmpty($this->body, static::MESSAGE_BODY);
313 1
        } catch (\InvalidArgumentException $e) {
314 1
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
315
        }
316 3
        return $this->body;
317
    }
318
319
    /**
320
     * getFromAddress
321
     *
322
     * @return EmailAddress the fromAddress
323
     *
324
     * @throws \LogicException (property was not properly set before used)
325
     */
326 4
    public function getFromAddress() : EmailAddress
327
    {
328
        try {
329 4
            Assert::notNull($this->fromAddress, static::MESSAGE_FROM);
330 3
            Assert::isInstanceOf($this->fromAddress, EmailAddress::class, static::MESSAGE_FROM);
331 3
            $this->fromAddress->getEmail();
332 2
        } catch (\InvalidArgumentException | \LogicException $e) {
333 2
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
334
        }
335 2
        return $this->fromAddress;
336
    }
337
338
    /**
339
     * getSubject
340
     *
341
     * @return string the message subject
342
     *
343
     * @throws \LogicException (property was not properly set before used)
344
     */
345 4
    public function getSubject() : string
346
    {
347
        try {
348 4
            Assert::stringNotEmpty($this->subject, static::MESSAGE_SUBJECT);
349 1
        } catch (\InvalidArgumentException $e) {
350 1
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
351
        }
352
353 3
        return $this->subject;
354
    }
355
356
    /**
357
     * getAddresses
358
     *
359
     * @param string $property addresses property to get, one of VALID_ADDRESS_PROPERTIES
360
     *
361
     * @return EmailAddressList|null the specified addresses property or null if not set
362
     *
363
     * @throws \LogicException (property was not properly set before used)
364
     */
365 6
    protected function getAddresses(string $property, string $message) : ?EmailAddressList
366
    {
367
        try {
368 6
            Assert::oneOf($property, static::VALID_ADDRESS_PROPERTIES);
369 6
            if (null !== $this->{$property}) {
370 6
                Assert::allIsInstanceOf($this->{$property}->getAddresses(), EmailAddress::class, $message);
371 5
                $this->{$property}->getAddresses();
372
            }
373 1
        } catch (\InvalidArgumentException | \LogicException $e) {
374 1
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
375
        }
376 5
        return $this->{$property};
377
    }
378
379
    /**
380
     * getBccAddresses
381
     *
382
     * @return EmailAddressList|null the BCC address list or null if not set
383
     *
384
     * @throws \LogicException (property was not properly set before used)
385
     */
386 1
    public function getBccAddresses() : ?EmailAddressList
387
    {
388 1
        return $this->getAddresses(static::PROPERTY_ADDRESS_BCC, static::MESSAGE_BCC);
389
    }
390
391
    /**
392
     * getCcAddresses
393
     *
394
     * @return EmailAddressList|null the CC address list or null if not set
395
     *
396
     * @throws \LogicException (property was not properly set before used)
397
     */
398 1
    public function getCcAddresses() : ?EmailAddressList
399
    {
400 1
        return $this->getAddresses(static::PROPERTY_ADDRESS_CC, static::MESSAGE_CC);
401
    }
402
403
    /**
404
     * getReplyToAddresses
405
     *
406
     * @return EmailAddressList|null the ReplyTo address list or null if not set
407
     *
408
     * @throws \LogicException (property was not properly set before used)
409
     */
410 1
    public function getReplyToAddresses() : ?EmailAddressList
411
    {
412 1
        return $this->getAddresses(static::PROPERTY_ADDRESS_REPLY, static::MESSAGE_REPLY);
413
    }
414
415
    /**
416
     * getToAddresses
417
     *
418
     * @return EmailAddressList the To addresses
419
     *
420
     * @throws \LogicException (property was not properly set before used)
421
     */
422 5
    public function getToAddresses() : EmailAddressList
423
    {
424
        try {
425 5
            Assert::notEmpty($this->toAddresses, static::MESSAGE_TO);
426 2
        } catch (\InvalidArgumentException $e) {
427 2
            throw new \LogicException($e->getMessage(), $e->getCode(), $e);
428
        }
429 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...
430
    }
431
432
    /**
433
     * getReadReceiptAddress
434
     *
435
     * @return EmailAddress|null the readReceiptAddress or null if not set
436
     *
437
     * @throws \LogicException (property was not properly set before used)
438
     */
439 2
    public function getReadReceiptAddress() : ?EmailAddress
440
    {
441 2
        if (null !== $this->readReceiptAddress) {
442
            try {
443 2
                Assert::isInstanceOf($this->readReceiptAddress, EmailAddress::class, static::MESSAGE_RR);
444 2
                $this->readReceiptAddress->getEmail();
445 1
            } catch (\InvalidArgumentException | \LogicException $e) {
446 1
                throw new \LogicException($e->getMessage(), $e->getCode(), $e);
447
            }
448
        }
449 1
        return $this->readReceiptAddress;
450
    }
451
}
452