Passed
Pull Request — master (#251)
by
unknown
02:52
created

Mail::getDeliveredTo()   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\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
76
     */
77
    public $snippet;
78
79
	/**
80
	 * @var Google_Service_Gmail
81
	 */
82
	public $service;
83
84
    /**
85
	 * SingleMessage constructor.
86
	 *
87
	 * @param \Google_Service_Gmail_Message $message
88
	 * @param bool $preload
89
	 * @param  int 	$userId
90
	 */
91
	public function __construct(\Google_Service_Gmail_Message $message = null, $preload = false, $userId = null)
92
	{
93
		$this->service = new Google_Service_Gmail($this);
94
95
		$this->__rConstruct();
96
		$this->__mConstruct();
97
		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

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

262
		preg_match('/<(.*)>/', /** @scrutinizer ignore-type */ $from, $matches);
Loading history...
263
264
		$name = preg_replace('/ <(.*)>/', '', $from);
265
266
		return [
267
			'name'  => $name,
268
			'email' => isset($matches[1]) ? $matches[1] : null,
269
		];
270
	}
271
272
	/**
273
	 * Returns email of sender
274
	 *
275
	 * @return string|null
276
	 */
277
	public function getFromEmail()
278
	{
279
		$from = $this->getHeader('From');
280
281
		if (filter_var($from, FILTER_VALIDATE_EMAIL)) {
282
			return $from;
283
		}
284
285
		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

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