Mail::getBody()   A
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 6
eloc 13
c 3
b 0
f 0
nc 6
nop 1
dl 0
loc 22
rs 9.2222
1
<?php
2
3
namespace Dacastro4\LaravelGmail\Services\Message;
4
5
use Carbon\Carbon;
6
use Dacastro4\LaravelGmail\GmailConnection;
7
use Dacastro4\LaravelGmail\Traits\HasDecodableBody;
8
use Dacastro4\LaravelGmail\Traits\HasParts;
9
use Dacastro4\LaravelGmail\Traits\Modifiable;
10
use Dacastro4\LaravelGmail\Traits\Replyable;
11
use Google_Service_Gmail;
12
use Google_Service_Gmail_MessagePart;
13
use Illuminate\Support\Collection;
14
use Illuminate\Support\Str;
15
16
/**
17
 * Class SingleMessage
18
 *
19
 * @package Dacastro4\LaravelGmail\services
20
 */
21
class Mail extends GmailConnection
22
{
23
24
	use HasDecodableBody,
0 ignored issues
show
Bug introduced by
The trait Dacastro4\LaravelGmail\Traits\Replyable requires the property $users_messages which is not provided by Dacastro4\LaravelGmail\Services\Message\Mail.
Loading history...
Bug introduced by
The trait Dacastro4\LaravelGmail\Traits\Modifiable requires the property $users_messages which is not provided by Dacastro4\LaravelGmail\Services\Message\Mail.
Loading history...
25
		Modifiable,
26
		HasParts,
27
		Replyable {
28
		Replyable::__construct as private __rConstruct;
29
		Modifiable::__construct as private __mConstruct;
30
	}
31
32
	/**
33
	 * @var
34
	 */
35
	public $id;
36
37
	/**
38
	 * @var
39
	 */
40
	public $userId;
41
42
	/**
43
	 * @var
44
	 */
45
	public $internalDate;
46
47
	/**
48
	 * @var
49
	 */
50
	public $labels;
51
52
	/**
53
	 * @var
54
	 */
55
	public $size;
56
57
	/**
58
	 * @var
59
	 */
60
	public $threadId;
61
62
    /**
63
     * @var
64
     */
65
    public $historyId;
66
67
	/**
68
	 * @var \Google_Service_Gmail_MessagePart
69
	 */
70
	public $payload;
71
72
	public $parts;
73
74
	/**
75
	 * @var Google_Service_Gmail
76
	 */
77
	public $service;
78
79
    /**
80
	 * SingleMessage constructor.
81
	 *
82
	 * @param \Google_Service_Gmail_Message $message
83
	 * @param bool $preload
84
	 * @param  int 	$userId
85
	 */
86
	public function __construct(\Google_Service_Gmail_Message $message = null, $preload = false, $userId = null)
87
	{
88
		$this->service = new Google_Service_Gmail($this);
89
90
		$this->__rConstruct();
91
		$this->__mConstruct();
92
		parent::__construct(config(), $userId);
0 ignored issues
show
Unused Code introduced by
The call to Dacastro4\LaravelGmail\T...difiable::__construct() has too many arguments starting with config(). ( Ignorable by Annotation )

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

92
		parent::/** @scrutinizer ignore-call */ 
93
          __construct(config(), $userId);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
93
94
		if (!is_null($message)) {
95
			if ($preload) {
96
				$message = $this->service->users_messages->get('me', $message->getId());
97
			}
98
99
			$this->setUserId($userId);
100
101
			$this->setMessage($message);
102
103
			if ($preload) {
104
				$this->setMetadata();
105
			}
106
		}
107
	}
108
109
	/**
110
	 * Set user Id
111
	 *
112
	 * @param int $userId
113
	 */
114
	protected function setUserId($userId)
115
	{
116
		$this->userId = $userId;
117
	}
118
119
	/**
120
	 * Sets data from mail
121
	 *
122
	 * @param \Google_Service_Gmail_Message $message
123
	 */
124
	protected function setMessage(\Google_Service_Gmail_Message $message)
125
	{
126
		$this->id = $message->getId();
127
		$this->internalDate = $message->getInternalDate();
128
		$this->labels = $message->getLabelIds();
129
		$this->size = $message->getSizeEstimate();
130
		$this->threadId = $message->getThreadId();
131
		$this->historyId = $message->getHistoryId();
132
		$this->payload = $message->getPayload();
133
		if ($this->payload) {
134
			$this->parts = collect($this->payload->getParts());
135
		}
136
	}
137
138
	/**
139
	 * Sets the metadata from Mail when preloaded
140
	 */
141
	protected function setMetadata()
142
	{
143
		$this->to = $this->getTo();
144
		$from = $this->getFrom();
145
		$this->from = isset($from['email']) ? $from['email'] : null;
146
		$this->nameFrom = isset($from['email']) ? $from['email'] : null;
147
148
		$this->subject = $this->getSubject();
149
	}
150
151
	/**
152
	 * Return a UNIX version of the date
153
	 *
154
	 * @return int UNIX date
155
	 */
156
	public function getInternalDate()
157
	{
158
		return $this->internalDate;
159
	}
160
161
	/**
162
	 * Returns the labels of the email
163
	 * Example: INBOX, STARRED, UNREAD
164
	 *
165
	 * @return array
166
	 */
167
	public function getLabels()
168
	{
169
		return $this->labels;
170
	}
171
172
	/**
173
	 * Returns approximate size of the email
174
	 *
175
	 * @return mixed
176
	 */
177
	public function getSize()
178
	{
179
		return $this->size;
180
	}
181
182
	/**
183
	 * Returns thread ID of the email
184
	 *
185
	 * @return string
186
	 */
187
	public function getThreadId()
188
	{
189
		return $this->threadId;
190
	}
191
192
	/**
193
	 * Returns history ID of the email
194
	 *
195
	 * @return string
196
	 */
197
	public function getHistoryId()
198
	{
199
		return $this->historyId;
200
	}
201
202
	/**
203
	 * Returns all the headers of the email
204
	 *
205
	 * @return Collection
206
	 */
207
	public function getHeaders()
208
	{
209
		return $this->buildHeaders($this->payload->getHeaders());
210
	}
211
212
	/**
213
	 * Returns the subject of the email
214
	 *
215
	 * @return string
216
	 */
217
	public function getSubject()
218
	{
219
		return $this->getHeader('Subject');
220
	}
221
222
	/**
223
	 * Returns the subject of the email
224
	 *
225
	 * @return array|string
226
	 */
227
	public function getReplyTo()
228
	{
229
		$replyTo = $this->getHeader('Reply-To');
230
231
		return $this->getFrom($replyTo ? $replyTo : $this->getHeader('From'));
232
	}
233
234
	/**
235
	 * Returns array of name and email of each recipient
236
	 *
237
	 * @param string|null $email
238
	 * @return array
239
	 */
240
	public function getFrom($email = null)
241
	{
242
		$from = $email ? $email : $this->getHeader('From');
243
244
		preg_match('/<(.*)>/', $from, $matches);
0 ignored issues
show
Bug introduced by
It seems like $from can also be of type null; however, parameter $subject of preg_match() 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

244
		preg_match('/<(.*)>/', /** @scrutinizer ignore-type */ $from, $matches);
Loading history...
245
246
		$name = preg_replace('/ <(.*)>/', '', $from);
247
248
		return [
249
			'name'  => $name,
250
			'email' => isset($matches[1]) ? $matches[1] : null,
251
		];
252
	}
253
254
	/**
255
	 * Returns email of sender
256
	 *
257
	 * @return string|null
258
	 */
259
	public function getFromEmail()
260
	{
261
		$from = $this->getHeader('From');
262
263
		if (filter_var($from, FILTER_VALIDATE_EMAIL)) {
264
			return $from;
265
		}
266
267
		preg_match('/<(.*)>/', $from, $matches);
0 ignored issues
show
Bug introduced by
It seems like $from can also be of type null; however, parameter $subject of preg_match() 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

267
		preg_match('/<(.*)>/', /** @scrutinizer ignore-type */ $from, $matches);
Loading history...
268
269
		return isset($matches[1]) ? $matches[1] : null;
270
	}
271
272
	/**
273
	 * Returns name of the sender
274
	 *
275
	 * @return string|null
276
	 */
277
	public function getFromName()
278
	{
279
		$from = $this->getHeader('From');
280
281
		$name = preg_replace('/ <(.*)>/', '', $from);
282
283
		return $name;
284
	}
285
286
	/**
287
	 * Returns array list of recipients
288
	 *
289
	 * @return array
290
	 */
291
	public function getTo()
292
	{
293
		$allTo = $this->getHeader('To');
294
295
		return $this->formatEmailList($allTo);
296
	}
297
298
	/**
299
	 * Returns array list of cc recipients
300
	 *
301
	 * @return array
302
	 */
303
	public function getCc()
304
	{
305
		$allCc = $this->getHeader('Cc');
306
307
		return $this->formatEmailList($allCc);
308
	}
309
310
	/**
311
	 * Returns array list of bcc recipients
312
	 *
313
	 * @return array
314
	 */
315
	public function getBcc()
316
	{
317
		$allBcc = $this->getHeader('Bcc');
318
319
		return $this->formatEmailList($allBcc);
320
	}
321
322
	/**
323
	 * Returns an array of emails from an string in RFC 822 format
324
	 *
325
	 * @param string $emails email list in RFC 822 format
326
	 *
327
	 * @return array
328
	 */
329
	public function formatEmailList($emails)
330
	{
331
		$all = [];
332
		$explodedEmails = explode(',', $emails);
333
334
		foreach ($explodedEmails as $email) {
335
336
			$item = [];
337
338
			preg_match('/<(.*)>/', $email, $matches);
339
340
			$item['email'] = str_replace(' ', '', isset($matches[1]) ? $matches[1] : $email);
341
342
			$name = preg_replace('/ <(.*)>/', '', $email);
343
344
			if (Str::startsWith($name, ' ')) {
345
				$name = substr($name, 1);
346
			}
347
348
			$item['name'] = str_replace("\"", '', $name ?: null);
349
350
			$all[] = $item;
351
352
		}
353
354
		return $all;
355
	}
356
357
	/**
358
	 * Returns the original date that the email was sent
359
	 *
360
	 * @return Carbon
361
	 */
362
	public function getDate()
363
	{
364
		return Carbon::parse($this->getHeader('Date'));
365
	}
366
367
	/**
368
	 * Returns email of the original recipient
369
	 *
370
	 * @return string
371
	 */
372
	public function getDeliveredTo()
373
	{
374
		return $this->getHeader('Delivered-To');
375
	}
376
377
	/**
378
	 * Base64 version of the body
379
	 *
380
	 * @return string
381
	 */
382
	public function getRawPlainTextBody()
383
	{
384
		return $this->getPlainTextBody(true);
385
	}
386
387
	/**
388
	 * @param bool $raw
389
	 *
390
	 * @return string
391
	 */
392
	public function getPlainTextBody($raw = false)
393
	{
394
		$content = $this->getBody();
395
396
		return $raw ? $content : $this->getDecodedBody($content);
397
	}
398
399
	/**
400
	 * Returns a specific body part from an email
401
	 *
402
	 * @param string $type
403
	 *
404
	 * @return null|string
405
	 * @throws \Exception
406
	 */
407
	public function getBody($type = 'text/plain')
408
	{
409
		$parts = $this->getAllParts($this->parts);
410
411
		try {
412
			if (!$parts->isEmpty()) {
413
				foreach ($parts as $part) {
414
					if ($part->mimeType == $type) {
415
						return $part->body->data;
416
						//if there are no parts in payload, try to get data from body->data
417
					} elseif ($this->payload->body->data) {
418
						return $this->payload->body->data;
419
					}
420
				}
421
			} else {
422
				return $this->payload->body->data;
423
			}
424
		} catch (\Exception $exception) {
425
			throw new \Exception("Preload or load the single message before getting the body.");
426
		}
427
428
		return null;
429
	}
430
431
	/**
432
	 * True if message has at least one attachment.
433
	 *
434
	 * @return boolean
435
	 */
436
	public function hasAttachments()
437
	{
438
		$parts = $this->getAllParts($this->parts);
439
		$has = false;
440
441
		/** @var Google_Service_Gmail_MessagePart $part */
442
		foreach ($parts as $part) {
443
			if (!empty($part->body->attachmentId) && $part->getFilename() != null && strlen($part->getFilename()) > 0) {
444
				$has = true;
445
				break;
446
			}
447
		}
448
449
		return $has;
450
	}
451
452
	/**
453
	 * Number of attachments of the message.
454
	 *
455
	 * @return int
456
	 */
457
	public function countAttachments()
458
	{
459
		$numberOfAttachments = 0;
460
		$parts = $this->getAllParts($this->parts);
461
462
		foreach ($parts as $part) {
463
			if (!empty($part->body->attachmentId)) {
464
				$numberOfAttachments++;
465
			}
466
		}
467
468
		return $numberOfAttachments;
469
	}
470
471
	/**
472
	 * Decodes the body from gmail to make it readable
473
	 *
474
	 * @param $content
475
	 * @return bool|string
476
	 */
477
	public function getDecodedBody($content)
478
	{
479
		$content = str_replace('_', '/', str_replace('-', '+', $content));
480
481
		return base64_decode($content);
482
	}
483
484
	/**
485
	 * @return string base64 version of the body
486
	 */
487
	public function getRawHtmlBody()
488
	{
489
		return $this->getHtmlBody(true);
490
	}
491
492
	/**
493
	 * Gets the HTML body
494
	 *
495
	 * @param bool $raw
496
	 *
497
	 * @return string
498
	 */
499
	public function getHtmlBody($raw = false)
500
	{
501
		$content = $this->getBody('text/html');
502
503
		return $raw ? $content : $this->getDecodedBody($content);
504
	}
505
506
	/**
507
	 * Get a collection of attachments with full information
508
	 *
509
	 * @return Collection
510
	 * @throws \Exception
511
	 */
512
	public function getAttachmentsWithData()
513
	{
514
		return $this->getAttachments(true);
515
	}
516
517
	/**
518
	 * Returns a collection of attachments
519
	 *
520
	 * @param bool $preload Preload only the attachment's 'data'.
521
	 * But does not load the other attachment info like filename, mimetype, etc..
522
	 *
523
	 * @return Collection
524
	 * @throws \Exception
525
	 */
526
	public function getAttachments($preload = false)
527
	{
528
		$attachments = new Collection();
529
		$parts = $this->getAllParts($this->parts);
530
531
		foreach ($parts as $part) {
532
			if (!empty($part->body->attachmentId)) {
533
				$attachment = (new Attachment($part->body->attachmentId, $part, $this->userId));
534
535
				if ($preload) {
536
					$attachment = $attachment->getData();
537
				}
538
539
				$attachments->push($attachment);
540
			}
541
		}
542
543
		return $attachments;
544
	}
545
546
	/**
547
	 * Returns ID of the email
548
	 *
549
	 * @return string
550
	 */
551
	public function getId()
552
	{
553
		return $this->id;
554
	}
555
556
	/**
557
	 * Gets the user email from the config file
558
	 *
559
	 * @return mixed|null
560
	 */
561
	public function getUser()
562
	{
563
		return $this->config('email');
564
	}
565
566
	/**
567
	 * Get's the gmail information from the Mail
568
	 *
569
	 * @return Mail
570
	 */
571
	public function load()
572
	{
573
		$message = $this->service->users_messages->get('me', $this->getId());
574
575
		return new self($message);
576
	}
577
578
	/**
579
	 * Sets the access token in case we wanna use a different token
580
	 *
581
	 * @param string $token
582
	 *
583
	 * @return Mail
584
	 */
585
	public function using($token)
586
	{
587
		$this->setToken($token);
588
589
		return $this;
590
	}
591
592
	/**
593
	 * checks if message has at least one part without iterating through all parts
594
	 *
595
	 * @return bool
596
	 */
597
	public function hasParts()
598
	{
599
		return !!$this->iterateParts($this->parts, $returnOnFirstFound = true);
600
	}
601
602
	/**
603
	 * Gets all the headers from an email and returns a collections
604
	 *
605
	 * @param $emailHeaders
606
	 * @return Collection
607
	 */
608
	private function buildHeaders($emailHeaders)
609
	{
610
		$headers = [];
611
612
		foreach ($emailHeaders as $header) {
613
			/** @var \Google_Service_Gmail_MessagePartHeader $header */
614
615
			$head = new \stdClass();
616
617
			$head->key = $header->getName();
618
			$head->value = $header->getValue();
619
620
			$headers[] = $head;
621
		}
622
623
		return collect($headers);
624
	}
625
}
626