Passed
Push — master ( 666eb8...8c815e )
by Daniel
03:19 queued 12s
created

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

81
		parent::/** @scrutinizer ignore-call */ 
82
          __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...
82
83
		if (!is_null($message)) {
84
			if ($preload) {
85
				$message = $this->service->users_messages->get('me', $message->getId());
86
			}
87
88
			$this->setMessage($message);
89
90
			if ($preload) {
91
				$this->setMetadata();
92
			}
93
		}
94
	}
95
96
	/**
97
	 * Sets data from mail
98
	 *
99
	 * @param \Google_Service_Gmail_Message $message
100
	 */
101
	protected function setMessage(\Google_Service_Gmail_Message $message)
102
	{
103
		$this->id = $message->getId();
104
		$this->internalDate = $message->getInternalDate();
105
		$this->labels = $message->getLabelIds();
106
		$this->size = $message->getSizeEstimate();
107
		$this->threadId = $message->getThreadId();
108
		$this->payload = $message->getPayload();
109
		if ($this->payload) {
110
			$this->parts = collect($this->payload->getParts());
111
		}
112
	}
113
114
	/**
115
	 * Sets the metadata from Mail when preloaded
116
	 */
117
	protected function setMetadata()
118
	{
119
		$this->to = $this->getTo();
120
		$from = $this->getFrom();
121
		$this->from = isset($from['email']) ? $from['email'] : null;
122
		$this->nameFrom = isset($from['email']) ? $from['email'] : null;
123
124
		$this->subject = $this->getSubject();
125
	}
126
127
	/**
128
	 * Return a UNIX version of the date
129
	 *
130
	 * @return int UNIX date
131
	 */
132
	public function getInternalDate()
133
	{
134
		return $this->internalDate;
135
	}
136
137
	/**
138
	 * Returns the labels of the email
139
	 * Example: INBOX, STARRED, UNREAD
140
	 *
141
	 * @return array
142
	 */
143
	public function getLabels()
144
	{
145
		return $this->labels;
146
	}
147
148
	/**
149
	 * Returns approximate size of the email
150
	 *
151
	 * @return mixed
152
	 */
153
	public function getSize()
154
	{
155
		return $this->size;
156
	}
157
158
	/**
159
	 * Returns thread ID of the email
160
	 *
161
	 * @return string
162
	 */
163
	public function getThreadId()
164
	{
165
		return $this->threadId;
166
	}
167
168
	/**
169
	 * Returns all the headers of the email
170
	 *
171
	 * @return Collection
172
	 */
173
	public function getHeaders()
174
	{
175
		return $this->buildHeaders($this->payload->getHeaders());
176
	}
177
178
	/**
179
	 * Returns the subject of the email
180
	 *
181
	 * @return string
182
	 */
183
	public function getSubject()
184
	{
185
		return $this->getHeader('Subject');
186
	}
187
188
	/**
189
	 * Returns the subject of the email
190
	 *
191
	 * @return array|string
192
	 */
193
	public function getReplyTo()
194
	{
195
		$replyTo = $this->getHeader('Reply-To');
196
197
		return $this->getFrom($replyTo ? $replyTo : $this->getHeader('From'));
198
	}
199
200
	/**
201
	 * Returns array of name and email of each recipient
202
	 *
203
	 * @param string|null $email
204
	 * @return array
205
	 */
206
	public function getFrom($email = null)
207
	{
208
		$from = $email ? $email : $this->getHeader('From');
209
210
		preg_match('/<(.*)>/', $from, $matches);
211
212
		$name = preg_replace('/ <(.*)>/', '', $from);
213
214
		return [
215
			'name'  => $name,
216
			'email' => isset($matches[1]) ? $matches[1] : null,
217
		];
218
	}
219
220
	/**
221
	 * Returns email of sender
222
	 *
223
	 * @return string|null
224
	 */
225
	public function getFromEmail()
226
	{
227
		$from = $this->getHeader('From');
228
229
		if (filter_var($from, FILTER_VALIDATE_EMAIL)) {
230
			return $from;
231
		}
232
233
		preg_match('/<(.*)>/', $from, $matches);
234
235
		return isset($matches[1]) ? $matches[1] : null;
236
	}
237
238
	/**
239
	 * Returns name of the sender
240
	 *
241
	 * @return string|null
242
	 */
243
	public function getFromName()
244
	{
245
		$from = $this->getHeader('From');
246
247
		$name = preg_replace('/ <(.*)>/', '', $from);
248
249
		return $name;
250
	}
251
252
	/**
253
	 * Returns array list of recipients
254
	 *
255
	 * @return array
256
	 */
257
	public function getTo()
258
	{
259
		$allTo = $this->getHeader('To');
260
261
		return $this->formatEmailList($allTo);
262
	}
263
264
    /**
265
     * Returns array list of cc recipients
266
     *
267
     * @return array
268
     */
269
    public function getCc()
270
    {
271
        $allCc = $this->getHeader('Cc');
272
273
        return $this->formatEmailList($allCc);
274
    }
275
276
    /**
277
     * Returns array list of bcc recipients
278
     *
279
     * @return array
280
     */
281
    public function getBcc()
282
    {
283
        $allBcc = $this->getHeader('Bcc');
284
285
        return $this->formatEmailList($allBcc);
286
    }
287
288
	/**
289
	 * Returns an array of emails from an string in RFC 822 format
290
	 *
291
	 * @param string $emails email list in RFC 822 format
292
	 *
293
	 * @return array
294
	 */
295
	public function formatEmailList($emails)
296
	{
297
		$all = [];
298
		$explodedEmails = explode(',', $emails);
299
300
		foreach ($explodedEmails as $email) {
301
302
			$item = [];
303
304
			preg_match('/<(.*)>/', $email, $matches);
305
306
			$item['email'] = str_replace(' ', '', isset($matches[1]) ? $matches[1] : $email);
307
308
			$name = preg_replace('/ <(.*)>/', '', $email);
309
310
			if (starts_with($name, ' ')) {
0 ignored issues
show
Bug introduced by
The function starts_with was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

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