Passed
Pull Request — master (#140)
by
unknown
04:07 queued 01:40
created

Mail::getFrom()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 4
nop 1
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Ddomanskyi\LaravelGmail\Services\Message;
4
5
use Carbon\Carbon;
6
use Ddomanskyi\LaravelGmail\GmailConnection;
7
use Ddomanskyi\LaravelGmail\Traits\HasDecodableBody;
8
use Ddomanskyi\LaravelGmail\Traits\HasParts;
9
use Ddomanskyi\LaravelGmail\Traits\Modifiable;
10
use Ddomanskyi\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 Ddomanskyi\LaravelGmail\services
20
 */
21
class Mail extends GmailConnection
22
{
23
24
	use HasDecodableBody,
0 ignored issues
show
Bug introduced by
The trait Ddomanskyi\LaravelGmail\Traits\Replyable requires the property $users_messages which is not provided by Ddomanskyi\LaravelGmail\Services\Message\Mail.
Loading history...
Bug introduced by
The trait Ddomanskyi\LaravelGmail\Traits\Modifiable requires the property $users_messages which is not provided by Ddomanskyi\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 $internalDate;
41
42
	/**
43
	 * @var
44
	 */
45
	public $labels;
46
47
	/**
48
	 * @var
49
	 */
50
	public $size;
51
52
	/**
53
	 * @var
54
	 */
55
	public $threadId;
56
57
	/**
58
	 * @var \Google_Service_Gmail_MessagePart
59
	 */
60
	public $payload;
61
62
	public $parts;
63
64
	/**
65
	 * @var Google_Service_Gmail
66
	 */
67
	public $service;
68
69
	/**
70
	 * SingleMessage constructor.
71
	 *
72
	 * @param \Google_Service_Gmail_Message $message
73
	 * @param bool $preload
74
	 * @param  int 	$userId
75
	 */
76
	public function __construct($tokenFile, \Google_Service_Gmail_Message $message = null, $preload = false)
77
	{
78
		$this->service = new Google_Service_Gmail($this);
79
80
		$this->__rConstruct();
81
		$this->__mConstruct();
82
		parent::__construct(config(), $tokenFile);
0 ignored issues
show
Unused Code introduced by
The call to Ddomanskyi\LaravelGmail\...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

82
		parent::/** @scrutinizer ignore-call */ 
83
          __construct(config(), $tokenFile);

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