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

Mail::load()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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

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