Passed
Pull Request — master (#87)
by Daniel
01:44
created

Mail::getThreadId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
	 *
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
		}
85
	}
86
87
	protected function setMessage(\Google_Service_Gmail_Message $message)
88
	{
89
		$this->id = $message->getId();
90
		$this->internalDate = $message->getInternalDate();
91
		$this->labels = $message->getLabelIds();
92
		$this->size = $message->getSizeEstimate();
93
		$this->threadId = $message->getThreadId();
94
		$this->payload = $message->getPayload();
95
	}
96
97
	/**
98
	 * Return a UNIX version of the date
99
	 *
100
	 * @return int UNIX date
101
	 */
102
	public function getInternalDate()
103
	{
104
		return $this->internalDate;
105
	}
106
107
	/**
108
	 * Returns the labels of the email
109
	 * Example: INBOX, STARRED, UNREAD
110
	 *
111
	 * @return array
112
	 */
113
	public function getLabels()
114
	{
115
		return $this->labels;
116
	}
117
118
	/**
119
	 * Returns approximate size of the email
120
	 *
121
	 * @return mixed
122
	 */
123
	public function getSize()
124
	{
125
		return $this->size;
126
	}
127
128
	/**
129
	 * Returns thread ID of the email
130
	 *
131
	 * @return string
132
	 */
133
	public function getThreadId()
134
	{
135
		return $this->threadId;
136
	}
137
138
	/**
139
	 * Returns all the headers of the email
140
	 *
141
	 * @return Collection
142
	 */
143
	public function getHeaders()
144
	{
145
		return $this->buildHeaders($this->payload->getHeaders());
146
	}
147
148
	private function buildHeaders($emailHeaders)
149
	{
150
		$headers = [];
151
152
		foreach ($emailHeaders as $header) {
153
			/** @var \Google_Service_Gmail_MessagePartHeader $header */
154
155
			$head = new \stdClass();
156
157
			$head->key = $header->getName();
158
			$head->value = $header->getValue();
159
160
			$headers[] = $head;
161
		}
162
163
		return collect($headers);
164
165
	}
166
167
	/**
168
	 * Returns the subject of the email
169
	 *
170
	 * @return string
171
	 */
172
	public function getSubject()
173
	{
174
		return $this->getHeader('Subject');
175
	}
176
177
	/**
178
	 * Returns array of name and email of each recipient
179
	 *
180
	 * @return array
181
	 */
182
	public function getFrom()
183
	{
184
		$from = $this->getHeader('From');
185
186
		preg_match('/<(.*)>/', $from, $matches);
187
188
		$name = preg_replace('/ <(.*)>/', '', $from);
189
190
		return [
191
			'name' => $name,
192
			'email' => isset($matches[1]) ? $matches[1] : null,
193
		];
194
	}
195
196
	/**
197
	 * Returns email of sender
198
	 *
199
	 * @return string|null
200
	 */
201
	public function getFromEmail()
202
	{
203
		$from = $this->getHeader('From');
204
205
		preg_match('/<(.*)>/', $from, $matches);
206
207
		return isset($matches[1]) ? $matches[1] : null;
208
	}
209
210
	/**
211
	 * Returns name of the sender
212
	 *
213
	 * @return string|null
214
	 */
215
	public function getFromName()
216
	{
217
		$from = $this->getHeader('From');
218
219
		$name = preg_replace('/ <(.*)>/', '', $from);
220
221
		return $name;
222
	}
223
224
	/**
225
	 * Returns array list of recipients
226
	 *
227
	 * @return array
228
	 */
229
	public function getTo()
230
	{
231
		$allTo = $this->getHeader('To');
232
233
		return $this->formatEmailList($allTo);
234
	}
235
236
	/**
237
	 * Returns an array of emails from an string in RFC 822 format
238
	 *
239
	 * @param  string  $emails  email list in RFC 822 format
240
	 *
241
	 * @return array
242
	 */
243
	public function formatEmailList($emails)
244
	{
245
		$all = [];
246
		$explodedEmails = explode(',', $emails);
247
248
		foreach ($explodedEmails as $email) {
249
250
			$item = [];
251
252
			preg_match('/<(.*)>/', $email, $matches);
253
254
			$item['email'] = str_replace(' ', '', isset($matches[1]) ? $matches[1] : $email);
255
256
			$name = preg_replace('/ <(.*)>/', '', $email);
257
258
			if (starts_with($name, ' ')) {
259
				$name = substr($name, 1);
260
			}
261
262
			$item['name'] = str_replace("\"", '', $name ?: null);
263
264
			$all[] = $item;
265
266
		}
267
268
		return $all;
269
	}
270
271
	/**
272
	 * Returns the original date that the email was sent
273
	 *
274
	 * @return Carbon
275
	 */
276
	public function getDate()
277
	{
278
		return Carbon::parse($this->getHeader('Date'));
279
	}
280
281
	/**
282
	 * Returns email of the original recipient
283
	 *
284
	 * @return string
285
	 */
286
	public function getDeliveredTo()
287
	{
288
		return $this->getHeader('Delivered-To');
289
	}
290
291
	/**
292
	 * @return string base64 version of the body
293
	 */
294
	public function getRawPlainTextBody()
295
	{
296
		return $this->getPlainTextBody(true);
297
	}
298
299
	/**
300
	 * @param  bool  $raw
301
	 *
302
	 * @return string
303
	 */
304
	public function getPlainTextBody($raw = false)
305
	{
306
		$content = $this->getBody();
307
308
		return $raw ? $content : $this->getDecodedBody($content);
309
	}
310
311
	/**
312
	 * Returns a specific body part from an email
313
	 *
314
	 * @param  string  $type
315
	 *
316
	 * @return null|string
317
	 */
318
	public function getBody($type = 'text/plain')
319
	{
320
		$part = $this->getBodyPart($type);
321
322
		if ($part) {
323
			$body = $part->getBody();
324
325
			return $body->getData();
326
327
			//if there are no parts in payload, try to get data from body->data
328
		} elseif ($this->payload->body->data) {
329
			return $this->payload->body->data;
330
		}
331
332
		return null;
333
	}
334
335
	/**
336
	 * @param  string  $type
337
	 *
338
	 * @return \Google_Service_Gmail_MessagePart|null
339
	 */
340
	private function getBodyPart($type = 'text/plain')
341
	{
342
		$body = $this->payload->getParts();
343
344
		if ($this->hasAttachments()) {
345
			//Get the first attachment that is the main body
346
			$body = isset($body[0]) ? $body[0] : [];
347
			$parts = $body->getParts();
348
		} else {
349
			$parts = $body;
350
		}
351
352
		/** @var \Google_Service_Gmail_MessagePart $part */
353
		foreach ($parts as $part) {
354
			if ($part->getMimeType() === $type) {
355
				break;
356
			}
357
		}
358
359
		return isset($part) ? $part : null;
360
361
	}
362
363
	/**
364
	 * @return boolean
365
	 */
366
	public function hasAttachments()
367
	{
368
		$attachments = 0;
369
		$parts = $this->payload->getParts();
370
371
		/**  @var \Google_Service_Gmail_MessagePart $part */
372
		foreach ($parts as $part) {
373
			$body = $part->getBody();
374
			if ($body->getAttachmentId()) {
375
				$attachments++;
376
				break;
377
			}
378
		}
379
380
		return !!$attachments;
381
	}
382
383
	public function getDecodedBody($content)
384
	{
385
		$content = str_replace('_', '/', str_replace('-', '+', $content));
386
387
		return base64_decode($content);
388
	}
389
390
	/**
391
	 * @return string base64 version of the body
392
	 */
393
	public function getRawHtmlBody()
394
	{
395
		return $this->getHtmlBody(true);
396
	}
397
398
	/**
399
	 * @param  bool  $raw
400
	 *
401
	 * @return string
402
	 */
403
	public function getHtmlBody($raw = false)
404
	{
405
		$content = $this->getBody('text/html');
406
407
		return $raw ? $content : $this->getDecodedBody($content);
408
	}
409
410
	/**
411
	 * @return Collection
412
	 * @throws \Exception
413
	 */
414
	public function getAttachmentsWithData()
415
	{
416
		return $this->getAttachments(true);
417
	}
418
419
	/**
420
	 * Returns a collection of attachments
421
	 *
422
	 * @param  bool  $preload  Preload the attachment's data
423
	 *
424
	 * @return Collection
425
	 * @throws \Exception
426
	 */
427
	public function getAttachments($preload = false)
428
	{
429
		$attachments = new Collection([]);
430
		$parts = $this->payload->getParts();
431
432
		/** @var \Google_Service_Gmail_MessagePart $part */
433
		foreach ($parts as $part) {
434
435
			$body = $part->getBody();
436
437
			if ($body->getAttachmentId()) {
438
				$attachment = (new Attachment($this->getId(), $part));
439
				if ($preload) {
440
					$attachment = $attachment->getData();
441
				}
442
				$attachments->push(
443
					$attachment
444
				);
445
			}
446
447
		}
448
449
		return $attachments;
450
451
	}
452
453
	/**
454
	 * Returns ID of the email
455
	 *
456
	 * @return string
457
	 */
458
	public function getId()
459
	{
460
		return $this->id;
461
	}
462
463
464
	/* added by buckfuddey */
465
466
	/**
467
	 * Get's the gmail information from the Mail
468
	 *
469
	 * @return Mail
470
	 */
471
	public function load()
472
	{
473
		$message = $this->service->users_messages->get('me', $this->getId());
474
475
		return new self($message);
476
	}
477
478
	/**
479
	 * Sets the access token in case we wanna use a different token
480
	 *
481
	 * @param  string  $token
482
	 *
483
	 * @return Mail
484
	 */
485
	public function using($token)
486
	{
487
		$this->setToken($token);
488
489
		return $this;
490
	}
491
492
	public function extractFromBody()
493
	{
494
495
		if ($this->hasNoParts()) {
496
			$type = $this->payload->getMimeType();
497
			$body = $this->payload->getBody();
498
			if ($type == 'text/html' || $type == 'text/plain') {
499
				$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...
500
			}
501
			if ($body->getAttachmentId()) {
502
				$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...
503
					'id' => $body->getAttachmentId(),
504
					'mimeType' => $type,
505
				];
506
			}
507
		} else {
508
			$parts = $this->payload->getParts();
509
			foreach ($parts as $part) {
510
				if (empty($part->getParts())) {
511
					$type = $part->getMimeType();
512
					$body = $part->getBody();
513
					if ($type == 'text/html' || $type == 'text/plain') {
514
						if (isset($this->messageBodyArr[$type])) {
515
							$this->messageBodyArr[$type] .= $this->getDecodedBody($body->getData());
516
						} else {
517
							$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...
518
						}
519
					}
520
521
					if ($body->getAttachmentId()) {
522
						$this->attachmentData[] = [
523
							'id' => $body->getAttachmentId(),
524
							'fileName' => $part->getFilename(),
525
							'mimeType' => $type,
526
						];
527
					}
528
				} else {
529
					$subParts = $part->getParts();
530
					$this->traverseData($subParts);
531
				}
532
			}
533
		}
534
	}
535
536
	public function hasNoParts()
537
	{
538
		if (empty($this->payload->getParts())) {
539
			return true;
540
		} else {
541
			return false;
542
		}
543
	}
544
545
	public function traverseData($parts)
546
	{
547
		foreach ($parts as $part) {
548
			if (empty($part->getParts())) {
549
				$type = $part->getMimeType();
550
				$body = $part->getBody();
551
				if ($type == 'text/html' || $type == 'text/plain') {
552
					if (isset($this->messageBodyArr[$type])) {
553
						$this->messageBodyArr[$type] .= $this->getDecodedBody($body->getData());
554
					} else {
555
						$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...
556
					}
557
				}
558
559
				if ($body->getAttachmentId()) {
560
					$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...
561
						'id' => $body->getAttachmentId(),
562
						'fileName' => $part->getFilename(),
563
						'mimeType' => $type,
564
					];
565
566
				}
567
			} else {
568
				$subParts = $part->getParts();
569
				$this->traverseData($subParts);
570
			}
571
		}
572
	}
573
574
}
575