Passed
Pull Request — master (#87)
by Daniel
02:52
created

Mail::getPlainTextBody()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 2
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 5
rs 10
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\Modifiable;
9
use Dacastro4\LaravelGmail\Traits\Replyable;
10
use Google_Service_Gmail;
11
use Illuminate\Support\Collection;
12
13
/**
14
 * Class SingleMessage
15
 * @package Dacastro4\LaravelGmail\services
16
 */
17
class Mail extends GmailConnection
18
{
19
	use HasDecodableBody,
0 ignored issues
show
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...
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...
20
		Modifiable,
21
		Replyable {
22
		Replyable::__construct as private __rConstruct;
23
		Modifiable::__construct as private __mConstruct;
24
	}
25
26
	/**
27
	 * @var
28
	 */
29
	public $id;
30
31
	/**
32
	 * @var
33
	 */
34
	public $internalDate;
35
36
	/**
37
	 * @var
38
	 */
39
	public $labels;
40
41
	/**
42
	 * @var
43
	 */
44
	public $size;
45
46
	/**
47
	 * @var
48
	 */
49
	public $threadId;
50
51
	/**
52
	 * @var \Google_Service_Gmail_MessagePart
53
	 */
54
	public $payload;
55
56
	/**
57
	 * @var Google_Service_Gmail
58
	 */
59
	public $service;
60
61
	/**
62
	 * SingleMessage constructor.
63
	 *
64
	 * @param  \Google_Service_Gmail_Message  $message
65
	 * @param  bool  $preload
66
	 * @param  bool  $setMessage
67
	 */
68
	public function __construct(\Google_Service_Gmail_Message $message = null, $preload = false)
69
	{
70
71
		$this->service = new Google_Service_Gmail($this);
72
73
		$this->__rConstruct();
74
		$this->__mConstruct();
75
		parent::__construct(config());
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

75
		parent::/** @scrutinizer ignore-call */ 
76
          __construct(config());

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...
76
77
		if (!is_null($message)) {
78
			if ($preload) {
79
				$message = $this->service->users_messages->get('me', $message->getId());
80
			}
81
82
			$this->setMessage($message);
83
84
			if($preload) {
85
				$this->setMetadata();
86
			}
87
		}
88
	}
89
90
	protected function setMessage(\Google_Service_Gmail_Message $message)
91
	{
92
		$this->id = $message->getId();
93
		$this->internalDate = $message->getInternalDate();
94
		$this->labels = $message->getLabelIds();
95
		$this->size = $message->getSizeEstimate();
96
		$this->threadId = $message->getThreadId();
97
		$this->payload = $message->getPayload();
98
	}
99
100
	protected function setMetadata()
101
	{
102
		$this->to = $this->getTo();
103
		$from = $this->getFrom();
104
		$this->from = isset($from['email']) ? $from['email'] : null;
105
		$this->nameFrom = isset($from['email']) ? $from['email'] : null;
106
107
		$this->subject = $this->getSubject();
108
	}
109
110
	/**
111
	 * Return a UNIX version of the date
112
	 *
113
	 * @return int UNIX date
114
	 */
115
	public function getInternalDate()
116
	{
117
		return $this->internalDate;
118
	}
119
120
	/**
121
	 * Returns the labels of the email
122
	 * Example: INBOX, STARRED, UNREAD
123
	 *
124
	 * @return array
125
	 */
126
	public function getLabels()
127
	{
128
		return $this->labels;
129
	}
130
131
	/**
132
	 * Returns approximate size of the email
133
	 *
134
	 * @return mixed
135
	 */
136
	public function getSize()
137
	{
138
		return $this->size;
139
	}
140
141
	/**
142
	 * Returns thread ID of the email
143
	 *
144
	 * @return string
145
	 */
146
	public function getThreadId()
147
	{
148
		return $this->threadId;
149
	}
150
151
	/**
152
	 * Returns all the headers of the email
153
	 *
154
	 * @return Collection
155
	 */
156
	public function getHeaders()
157
	{
158
		return $this->buildHeaders($this->payload->getHeaders());
159
	}
160
161
	private function buildHeaders($emailHeaders)
162
	{
163
		$headers = [];
164
165
		foreach ($emailHeaders as $header) {
166
			/** @var \Google_Service_Gmail_MessagePartHeader $header */
167
168
			$head = new \stdClass();
169
170
			$head->key = $header->getName();
171
			$head->value = $header->getValue();
172
173
			$headers[] = $head;
174
		}
175
176
		return collect($headers);
177
178
	}
179
180
	/**
181
	 * Returns the subject of the email
182
	 *
183
	 * @return string
184
	 */
185
	public function getSubject()
186
	{
187
		return $this->getHeader('Subject');
188
	}
189
190
	/**
191
	 * Returns the subject of the email
192
	 *
193
	 * @return array|string
194
	 */
195
	public function getReplyTo()
196
	{
197
		$replyTo = $this->getHeader('Reply-To');
198
199
		return $this->getFrom($replyTo ? $replyTo : $this->getHeader('From'));
0 ignored issues
show
Bug introduced by
It seems like $replyTo ? $replyTo : $this->getHeader('From') can also be of type string; however, parameter $email of Dacastro4\LaravelGmail\S...Message\Mail::getFrom() does only seem to accept null, 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

199
		return $this->getFrom(/** @scrutinizer ignore-type */ $replyTo ? $replyTo : $this->getHeader('From'));
Loading history...
200
	}
201
202
	/**
203
	 * Returns array of name and email of each recipient
204
	 *
205
	 * @param  null  $email
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $email is correct as it would always require null to be passed?
Loading history...
206
	 * @return array
207
	 */
208
	public function getFrom($email = null)
209
	{
210
		$from = $email ? $email : $this->getHeader('From');
0 ignored issues
show
introduced by
$email is of type null, thus it always evaluated to false.
Loading history...
211
212
		preg_match('/<(.*)>/', $from, $matches);
213
214
		$name = preg_replace('/ <(.*)>/', '', $from);
215
216
		return [
217
			'name' => $name,
218
			'email' => isset($matches[1]) ? $matches[1] : null,
219
		];
220
	}
221
222
	/**
223
	 * Returns email of sender
224
	 *
225
	 * @return string|null
226
	 */
227
	public function getFromEmail()
228
	{
229
		$from = $this->getHeader('From');
230
231
		preg_match('/<(.*)>/', $from, $matches);
232
233
		return isset($matches[1]) ? $matches[1] : null;
234
	}
235
236
	/**
237
	 * Returns name of the sender
238
	 *
239
	 * @return string|null
240
	 */
241
	public function getFromName()
242
	{
243
		$from = $this->getHeader('From');
244
245
		$name = preg_replace('/ <(.*)>/', '', $from);
246
247
		return $name;
248
	}
249
250
	/**
251
	 * Returns array list of recipients
252
	 *
253
	 * @return array
254
	 */
255
	public function getTo()
256
	{
257
		$allTo = $this->getHeader('To');
258
259
		return $this->formatEmailList($allTo);
260
	}
261
262
	/**
263
	 * Returns an array of emails from an string in RFC 822 format
264
	 *
265
	 * @param  string  $emails  email list in RFC 822 format
266
	 *
267
	 * @return array
268
	 */
269
	public function formatEmailList($emails)
270
	{
271
		$all = [];
272
		$explodedEmails = explode(',', $emails);
273
274
		foreach ($explodedEmails as $email) {
275
276
			$item = [];
277
278
			preg_match('/<(.*)>/', $email, $matches);
279
280
			$item['email'] = str_replace(' ', '', isset($matches[1]) ? $matches[1] : $email);
281
282
			$name = preg_replace('/ <(.*)>/', '', $email);
283
284
			if (starts_with($name, ' ')) {
285
				$name = substr($name, 1);
286
			}
287
288
			$item['name'] = str_replace("\"", '', $name ?: null);
289
290
			$all[] = $item;
291
292
		}
293
294
		return $all;
295
	}
296
297
	/**
298
	 * Returns the original date that the email was sent
299
	 *
300
	 * @return Carbon
301
	 */
302
	public function getDate()
303
	{
304
		return Carbon::parse($this->getHeader('Date'));
305
	}
306
307
	/**
308
	 * Returns email of the original recipient
309
	 *
310
	 * @return string
311
	 */
312
	public function getDeliveredTo()
313
	{
314
		return $this->getHeader('Delivered-To');
315
	}
316
317
	/**
318
	 * @return string base64 version of the body
319
	 */
320
	public function getRawPlainTextBody()
321
	{
322
		return $this->getPlainTextBody(true);
323
	}
324
325
	/**
326
	 * @param  bool  $raw
327
	 *
328
	 * @return string
329
	 */
330
	public function getPlainTextBody($raw = false)
331
	{
332
		$content = $this->getBody();
333
334
		return $raw ? $content : $this->getDecodedBody($content);
335
	}
336
337
	/**
338
	 * Returns a specific body part from an email
339
	 *
340
	 * @param  string  $type
341
	 *
342
	 * @return null|string
343
	 */
344
	public function getBody($type = 'text/plain')
345
	{
346
		$part = $this->getBodyPart($type);
347
348
		if ($part) {
349
			$body = $part->getBody();
350
351
			return $body->getData();
352
353
			//if there are no parts in payload, try to get data from body->data
354
		} elseif ($this->payload->body->data) {
355
			return $this->payload->body->data;
356
		}
357
358
		return null;
359
	}
360
361
	/**
362
	 * @param  string  $type
363
	 *
364
	 * @return \Google_Service_Gmail_MessagePart|null
365
	 */
366
	private function getBodyPart($type = 'text/plain')
367
	{
368
		$body = $this->payload->getParts();
369
370
		if ($this->hasAttachments()) {
371
			//Get the first attachment that is the main body
372
			$body = isset($body[0]) ? $body[0] : [];
373
			$parts = $body->getParts();
374
		} else {
375
			$parts = $body;
376
		}
377
378
		/** @var \Google_Service_Gmail_MessagePart $part */
379
		foreach ($parts as $part) {
380
			if ($part->getMimeType() === $type) {
381
				break;
382
			}
383
		}
384
385
		return isset($part) ? $part : null;
386
387
	}
388
389
	/**
390
	 * @return boolean
391
	 */
392
	public function hasAttachments()
393
	{
394
		$attachments = 0;
395
		$parts = $this->payload->getParts();
396
397
		/**  @var \Google_Service_Gmail_MessagePart $part */
398
		foreach ($parts as $part) {
399
			$body = $part->getBody();
400
			if ($body->getAttachmentId()) {
401
				$attachments++;
402
				break;
403
			}
404
		}
405
406
		return !!$attachments;
407
	}
408
409
	public function getDecodedBody($content)
410
	{
411
		$content = str_replace('_', '/', str_replace('-', '+', $content));
412
413
		return base64_decode($content);
414
	}
415
416
	/**
417
	 * @return string base64 version of the body
418
	 */
419
	public function getRawHtmlBody()
420
	{
421
		return $this->getHtmlBody(true);
422
	}
423
424
	/**
425
	 * @param  bool  $raw
426
	 *
427
	 * @return string
428
	 */
429
	public function getHtmlBody($raw = false)
430
	{
431
		$content = $this->getBody('text/html');
432
433
		return $raw ? $content : $this->getDecodedBody($content);
434
	}
435
436
	/**
437
	 * @return Collection
438
	 * @throws \Exception
439
	 */
440
	public function getAttachmentsWithData()
441
	{
442
		return $this->getAttachments(true);
443
	}
444
445
	/**
446
	 * Returns a collection of attachments
447
	 *
448
	 * @param  bool  $preload  Preload the attachment's data
449
	 *
450
	 * @return Collection
451
	 * @throws \Exception
452
	 */
453
	public function getAttachments($preload = false)
454
	{
455
		$attachments = new Collection([]);
456
		$parts = $this->payload->getParts();
457
458
		/** @var \Google_Service_Gmail_MessagePart $part */
459
		foreach ($parts as $part) {
460
461
			$body = $part->getBody();
462
463
			if ($body->getAttachmentId()) {
464
				$attachment = (new Attachment($this->getId(), $part));
465
				if ($preload) {
466
					$attachment = $attachment->getData();
467
				}
468
				$attachments->push(
469
					$attachment
470
				);
471
			}
472
473
		}
474
475
		return $attachments;
476
477
	}
478
479
	/**
480
	 * Returns ID of the email
481
	 *
482
	 * @return string
483
	 */
484
	public function getId()
485
	{
486
		return $this->id;
487
	}
488
489
490
	public function getUser()
491
	{
492
		return $this->config('email');
493
	}
494
495
	/* added by buckfuddey */
496
497
	/**
498
	 * Get's the gmail information from the Mail
499
	 *
500
	 * @return Mail
501
	 */
502
	public function load()
503
	{
504
		$message = $this->service->users_messages->get('me', $this->getId());
505
506
		return new self($message);
507
	}
508
509
	/**
510
	 * Sets the access token in case we wanna use a different token
511
	 *
512
	 * @param  string  $token
513
	 *
514
	 * @return Mail
515
	 */
516
	public function using($token)
517
	{
518
		$this->setToken($token);
519
520
		return $this;
521
	}
522
523
	public function extractFromBody()
524
	{
525
526
		if ($this->hasNoParts()) {
527
			$type = $this->payload->getMimeType();
528
			$body = $this->payload->getBody();
529
			if ($type == 'text/html' || $type == 'text/plain') {
530
				$this->bodyArr[$type] = $this->getDecodedBody($body->getData());
0 ignored issues
show
Bug Best Practice introduced by
The property bodyArr does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
531
			}
532
			if ($body->getAttachmentId()) {
533
				$this->attachmentData[] = [
0 ignored issues
show
Bug Best Practice introduced by
The property attachmentData does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
534
					'id' => $body->getAttachmentId(),
535
					'mimeType' => $type,
536
				];
537
			}
538
		} else {
539
			$parts = $this->payload->getParts();
540
			foreach ($parts as $part) {
541
				if (empty($part->getParts())) {
542
					$type = $part->getMimeType();
543
					$body = $part->getBody();
544
					if ($type == 'text/html' || $type == 'text/plain') {
545
						if (isset($this->messageBodyArr[$type])) {
546
							$this->messageBodyArr[$type] .= $this->getDecodedBody($body->getData());
547
						} else {
548
							$this->messageBodyArr[$type] = $this->getDecodedBody($body->getData());
0 ignored issues
show
Bug Best Practice introduced by
The property messageBodyArr does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
549
						}
550
					}
551
552
					if ($body->getAttachmentId()) {
553
						$this->attachmentData[] = [
554
							'id' => $body->getAttachmentId(),
555
							'fileName' => $part->getFilename(),
556
							'mimeType' => $type,
557
						];
558
					}
559
				} else {
560
					$subParts = $part->getParts();
561
					$this->traverseData($subParts);
562
				}
563
			}
564
		}
565
	}
566
567
	public function hasNoParts()
568
	{
569
		if (empty($this->payload->getParts())) {
570
			return true;
571
		} else {
572
			return false;
573
		}
574
	}
575
576
	public function traverseData($parts)
577
	{
578
		foreach ($parts as $part) {
579
			if (empty($part->getParts())) {
580
				$type = $part->getMimeType();
581
				$body = $part->getBody();
582
				if ($type == 'text/html' || $type == 'text/plain') {
583
					if (isset($this->messageBodyArr[$type])) {
584
						$this->messageBodyArr[$type] .= $this->getDecodedBody($body->getData());
585
					} else {
586
						$this->messageBodyArr[$type] = $this->getDecodedBody($body->getData());
0 ignored issues
show
Bug Best Practice introduced by
The property messageBodyArr does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
587
					}
588
				}
589
590
				if ($body->getAttachmentId()) {
591
					$this->attachmentData[] = [
0 ignored issues
show
Bug Best Practice introduced by
The property attachmentData does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
592
						'id' => $body->getAttachmentId(),
593
						'fileName' => $part->getFilename(),
594
						'mimeType' => $type,
595
					];
596
597
				}
598
			} else {
599
				$subParts = $part->getParts();
600
				$this->traverseData($subParts);
601
			}
602
		}
603
	}
604
605
}
606