1: <?php
2:
3: namespace Charcoal\Email;
4:
5: use \Exception;
6: use \InvalidArgumentException;
7:
8: // Module `pimple/pimple` dependencies
9: use \Pimple\Container;
10:
11: // Module `charcoal/factory` dependencies
12: use \Charcoal\Factory\FactoryInterface;
13:
14: // Module `charcoal-core` dependencies
15: use \Charcoal\Model\AbstractModel;
16:
17: // Module `charcoal-queue` dependencies
18: use \Charcoal\Queue\QueueItemInterface;
19: use \Charcoal\Queue\QueueItemTrait;
20:
21: // Module `charcoal-app` dependencies
22: use \Charcoal\App\App;
23: use \Charcoal\Email\Email;
24:
25: /**
26: * Email queue item.
27: */
28: class EmailQueueItem extends AbstractModel implements QueueItemInterface
29: {
30: use QueueItemTrait;
31: use EmailAwareTrait;
32:
33: /**
34: * The queue item ID.
35: *
36: * @var string $ident
37: */
38: private $ident;
39:
40: /**
41: * The recipient's email address.
42: *
43: * @var string $to
44: */
45: private $to;
46:
47: /**
48: * The sender's email address.
49: *
50: * @var string $from
51: */
52: private $from;
53:
54: /**
55: * The email subject.
56: *
57: * @var string $subject.
58: */
59: private $subject;
60:
61: /**
62: * The HTML message body.
63: *
64: * @var string $msgHtml
65: */
66: private $msgHtml;
67:
68: /**
69: * The plain-text message body.
70: *
71: * @var string $msgTxt
72: */
73: private $msgTxt;
74:
75: /**
76: * The campaign ID.
77: *
78: * @var string $campaign
79: */
80: private $campaign;
81:
82: /**
83: * @var FactoryInterface $emailFactory
84: */
85: private $emailFactory;
86:
87: /**
88: * @param Container $container Pimple DI container.
89: * @return void
90: */
91: public function setDependencies(Container $container)
92: {
93: parent::setDependencies($container);
94: $this->setEmailFactory($container['email/factory']);
95: }
96:
97: /**
98: * @param FactoryInterface $factory The factory to create email objects.
99: * @return EmailQueueItem Chainable
100: */
101: protected function setEmailFactory(FactoryInterface $factory)
102: {
103: $this->emailFactory = $factory;
104: return $this;
105: }
106:
107: /**
108: * @return FactoryInterface
109: */
110: protected function emailFactory()
111: {
112: return $this->emailFactory;
113: }
114:
115: /**
116: * Get the primary key that uniquely identifies each queue item.
117: *
118: * @return string
119: */
120: public function key()
121: {
122: return 'id';
123: }
124:
125: /**
126: * Set the queue item's ID.
127: *
128: * @param string|null $ident The unique queue item identifier.
129: * @throws InvalidArgumentException If the identifier is not a string.
130: * @return AbstractMessage Chainable
131: */
132: public function setIdent($ident)
133: {
134: if ($ident === null) {
135: $this->ident = null;
136: return $this;
137: }
138:
139: if (!is_string($ident)) {
140: throw new InvalidArgumentException(
141: 'Ident needs to be a string'
142: );
143: }
144:
145: $this->ident = $ident;
146:
147: return $this;
148: }
149:
150: /**
151: * Get the queue item's ID.
152: *
153: * @return string
154: */
155: public function ident()
156: {
157: return $this->ident;
158: }
159:
160: /**
161: * Set the recipient's email address.
162: *
163: * @param string|array $email An email address.
164: * @throws InvalidArgumentException If the email address is invalid.
165: * @return EmailQueueItem Chainable
166: */
167: public function setTo($email)
168: {
169: if (is_string($email)) {
170: $this->to = $email;
171: } elseif (is_array($email)) {
172: $this->to = $this->emailFromArray($email);
173: } else {
174: throw new InvalidArgumentException(
175: 'Queue item recipient: Email address must to be a string.'
176: );
177: }
178:
179: $this->to = $email;
180:
181: return $this;
182: }
183:
184: /**
185: * Get the recipient's email address.
186: *
187: * @return string
188: */
189: public function to()
190: {
191: return $this->to;
192: }
193:
194: /**
195: * Set the sender's email address.
196: *
197: * @param string|array $email An email address.
198: * @throws InvalidArgumentException If the email address is invalid.
199: * @return EmailQueueItem Chainable
200: */
201: public function setFrom($email)
202: {
203: if (is_string($email)) {
204: $this->from = $email;
205: } elseif (is_array($email)) {
206: $this->from = $this->emailFromArray($email);
207: } else {
208: throw new InvalidArgumentException(
209: 'Queue item sender: Email address must to be a string.'
210: );
211: }
212:
213: $this->from = $email;
214:
215: return $this;
216: }
217:
218: /**
219: * Get the sender's email address.
220: *
221: * @return string
222: */
223: public function from()
224: {
225: return $this->from;
226: }
227:
228: /**
229: * Set the email subject.
230: *
231: * @param string $subject The email subject.
232: * @throws InvalidArgumentException If the subject is not a string.
233: * @return EmailQueueItem Chainable
234: */
235: public function setSubject($subject)
236: {
237: if (!is_string($subject)) {
238: throw new InvalidArgumentException(
239: 'Subject needs to be a string'
240: );
241: }
242:
243: $this->subject = $subject;
244:
245: return $this;
246: }
247:
248: /**
249: * Get the email subject.
250: *
251: * @return string
252: */
253: public function subject()
254: {
255: return $this->subject;
256: }
257:
258: /**
259: * Set the email's HTML message body.
260: *
261: * @param string $body The HTML message body.
262: * @throws InvalidArgumentException If the message is not a string.
263: * @return EmailQueueItem Chainable
264: */
265: public function setMsgHtml($body)
266: {
267: if (!is_string($body)) {
268: throw new InvalidArgumentException(
269: 'HTML message needs to be a string'
270: );
271: }
272:
273: $this->msgHtml = $body;
274:
275: return $this;
276: }
277:
278: /**
279: * Get the email's HTML message body.
280: *
281: * @return string
282: */
283: public function msgHtml()
284: {
285: return $this->msgHtml;
286: }
287:
288: /**
289: * Set the email's plain-text message body.
290: *
291: * @param string $body The plain-text mesage body.
292: * @throws InvalidArgumentException If the message is not a string.
293: * @return EmailQueueItem Chainable
294: */
295: public function setMsgTxt($body)
296: {
297: if (!is_string($body)) {
298: throw new InvalidArgumentException(
299: 'Plan-text message needs to be a string'
300: );
301: }
302:
303: $this->msgTxt = $body;
304:
305: return $this;
306: }
307:
308: /**
309: * Get the email's plain-text message body.
310: *
311: * @return string
312: */
313: public function msgTxt()
314: {
315: return $this->msgTxt;
316: }
317:
318: /**
319: * Set the campaign ID.
320: *
321: * @param string $campaign The campaign identifier.
322: * @throws InvalidArgumentException If the campaign is not a string.
323: * @return EmailQueueItem Chainable
324: */
325: public function setCampaign($campaign)
326: {
327: if (!is_string($campaign)) {
328: throw new InvalidArgumentException(
329: 'Campaign ID needs to be a string'
330: );
331: }
332:
333: $this->campaign = $campaign;
334:
335: return $this;
336: }
337:
338: /**
339: * Get the campaign ID.
340: *
341: * If it has not been explicitely set, it will be auto-generated (with uniqid).
342: *
343: * @return string
344: */
345: public function campaign()
346: {
347: return $this->campaign;
348: }
349:
350: /**
351: * Process the item.
352: *
353: * @param callable $callback An optional callback routine executed after the item is processed.
354: * @param callable $successCallback An optional callback routine executed when the item is resolved.
355: * @param callable $failureCallback An optional callback routine executed when the item is rejected.
356: * @return boolean Success / Failure
357: */
358: public function process(
359: callable $callback = null,
360: callable $successCallback = null,
361: callable $failureCallback = null
362: ) {
363: if ($this->processed() === true) {
364: // Do not process twice, ever.
365: return null;
366: }
367:
368: $email = $this->emailFactory()->create('email');
369:
370: $email->setData($this->data());
371:
372: try {
373: $res = $email->send();
374: if ($res === true) {
375: $this->setProcessed(true);
376: $this->setProcessedDate('now');
377: $this->update(['processed', 'processed_date']);
378:
379: if ($successCallback !== null) {
380: $successCallback($this);
381: }
382: } else {
383: if ($failureCallback !== null) {
384: $failureCallback($this);
385: }
386: }
387:
388: if ($callback !== null) {
389: $callback($this);
390: }
391:
392: return $res;
393: } catch (Exception $e) {
394: // Todo log error
395: if ($failureCallback !== null) {
396: $failureCallback($this);
397: }
398:
399: return false;
400: }
401: }
402:
403: /**
404: * Hook called before saving the item.
405: *
406: * @return boolean
407: * @see \Charcoal\Email\Queue\QueueItemTrait::preSaveQueueItem()
408: */
409: public function preSave()
410: {
411: parent::preSave();
412:
413: $this->preSaveQueueItem();
414:
415: return true;
416: }
417: }
418: