Passed
Pull Request — master (#91)
by
unknown
02:05
created

Mail::hasParts()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 8
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 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 $threatId;
54
55
    /**
56
     * @var \Google_Service_Gmail_MessagePart
57
     */
58
    public $payload;
59
60
    /**
61
     * @var Google_Service_Gmail
62
     */
63
    public $service;
64
65
    /**
66
     * @var
67
     */
68
    private $allParts;
0 ignored issues
show
introduced by
The private property $allParts is not used, and could be removed.
Loading history...
69
70
    /**
71
     * SingleMessage constructor.
72
     *
73
     * @param  \Google_Service_Gmail_Message  $message
74
     * @param  bool  $preload
75
     *
76
     */
77
    public function __construct(
78
        \Google_Service_Gmail_Message $message = null,
79
        $preload = false
80
    ) {
81
82
        $this->service = new Google_Service_Gmail($this);
83
84
        $this->__rConstruct();
85
        $this->__mConstruct();
86
        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

86
        parent::/** @scrutinizer ignore-call */ 
87
                __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...
87
88
        if (!is_null($message)) {
89
            if ($preload) {
90
                $message = $this->service->users_messages->get('me',
91
                    $message->getId());
92
            }
93
94
            $this->setMessage($message);
95
96
        }
97
    }
98
99
    protected function setMessage(\Google_Service_Gmail_Message $message)
100
    {
101
        $this->id = $message->getId();
102
        $this->internalDate = $message->getInternalDate();
103
        $this->labels = $message->getLabelIds();
104
        $this->size = $message->getSizeEstimate();
105
        $this->threatId = $message->getThreadId();
106
        $this->payload = $message->getPayload();
107
    }
108
109
    /**
110
     * Return a UNIX version of the date
111
     *
112
     * @return int UNIX date
113
     */
114
    public function getInternalDate()
115
    {
116
        return $this->internalDate;
117
    }
118
119
    /**
120
     * Returns the labels of the email
121
     * Example: INBOX, STARRED, UNREAD
122
     *
123
     * @return array
124
     */
125
    public function getLabels()
126
    {
127
        return $this->labels;
128
    }
129
130
    /**
131
     * Returns approximate size of the email
132
     *
133
     * @return mixed
134
     */
135
    public function getSize()
136
    {
137
        return $this->size;
138
    }
139
140
    /**
141
     * Returns threat ID of the email
142
     *
143
     * @return string
144
     */
145
    public function getThreatId()
146
    {
147
        return $this->threatId;
148
    }
149
150
    /**
151
     * Returns all the headers of the email
152
     *
153
     * @return Collection
154
     */
155
    public function getHeaders()
156
    {
157
        return $this->buildHeaders($this->payload->getHeaders());
158
    }
159
160
    private function buildHeaders($emailHeaders)
161
    {
162
        $headers = [];
163
164
        foreach ($emailHeaders as $header) {
165
            /** @var \Google_Service_Gmail_MessagePartHeader $header */
166
167
            $head = new \stdClass();
168
169
            $head->key = $header->getName();
170
            $head->value = $header->getValue();
171
172
            $headers[] = $head;
173
        }
174
175
        return collect($headers);
176
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 array of name and email of each recipient
191
     *
192
     * @return array
193
     */
194
    public function getFrom()
195
    {
196
        $from = $this->getHeader('From');
197
198
        preg_match('/<(.*)>/', $from, $matches);
199
200
        $name = preg_replace('/ <(.*)>/', '', $from);
201
202
        return [
203
            'name' => $name,
204
            'email' => isset($matches[1]) ? $matches[1] : null,
205
        ];
206
    }
207
208
    /**
209
     * Returns email of sender
210
     *
211
     * @return string|null
212
     */
213
    public function getFromEmail()
214
    {
215
        $from = $this->getHeader('From');
216
217
        preg_match('/<(.*)>/', $from, $matches);
218
219
        return isset($matches[1]) ? $matches[1] : null;
220
    }
221
222
    /**
223
     * Returns name of the sender
224
     *
225
     * @return string|null
226
     */
227
    public function getFromName()
228
    {
229
        $from = $this->getHeader('From');
230
231
        $name = preg_replace('/ <(.*)>/', '', $from);
232
233
        return $name;
234
    }
235
236
    /**
237
     * Returns array list of recipients
238
     *
239
     * @return array
240
     */
241
    public function getTo()
242
    {
243
        $allTo = $this->getHeader('To');
244
245
        return $this->formatEmailList($allTo);
246
    }
247
248
    /**
249
     * Returns an array of emails from an string in RFC 822 format
250
     *
251
     * @param  string  $emails  email list in RFC 822 format
252
     *
253
     * @return array
254
     */
255
    public function formatEmailList($emails)
256
    {
257
        $all = [];
258
        $explodedEmails = explode(',', $emails);
259
260
        foreach ($explodedEmails as $email) {
261
262
            $item = [];
263
264
            preg_match('/<(.*)>/', $email, $matches);
265
266
            $item['email'] = str_replace(' ', '',
267
                isset($matches[1]) ? $matches[1] : $email);
268
269
            $name = preg_replace('/ <(.*)>/', '', $email);
270
271
            if (starts_with($name, ' ')) {
272
                $name = substr($name, 1);
273
            }
274
275
            $item['name'] = str_replace("\"", '', $name ?: null);
276
277
            $all[] = $item;
278
279
        }
280
281
        return $all;
282
    }
283
284
    /**
285
     * Returns the original date that the email was sent
286
     *
287
     * @return Carbon
288
     */
289
    public function getDate()
290
    {
291
        return Carbon::parse($this->getHeader('Date'));
292
    }
293
294
    /**
295
     * Returns email of the original recipient
296
     *
297
     * @return string
298
     */
299
    public function getDeliveredTo()
300
    {
301
        return $this->getHeader('Delivered-To');
302
    }
303
304
    /**
305
     * @return string base64 version of the body
306
     */
307
    public function getRawPlainTextBody()
308
    {
309
        return $this->getPlainTextBody(true);
310
    }
311
312
    /**
313
     * @param  bool  $raw
314
     *
315
     * @return string
316
     */
317
    public function getPlainTextBody($raw = false)
318
    {
319
        $content = $this->getBody();
320
321
        return $raw ? $content : $this->getDecodedBody($content);
322
    }
323
324
    /**
325
     * Returns a specific body part from an email
326
     *
327
     * @param  string  $type
328
     *
329
     * @return null|string
330
     */
331
    public function getBody($type = 'text/plain')
332
    {
333
        $parts = $this->getAllParts(collect([$this->payload]));
334
        if(!$parts->isEmpty())
335
        {
336
            foreach ($parts as $part)
337
            {
338
                if ($part->mimeType == $type)
339
                {
340
                    return $part->body->data;
341
                    //if there are no parts in payload, try to get data from body->data
342
                } elseif ($this->payload->body->data)
343
                {
344
                    return $this->payload->body->data;
345
                }
346
            }
347
        }else{
348
            return $this->payload->body->data;
349
        }
350
        return null;
351
352
    }
353
354
    /**
355
     * @return boolean. True if message has at least one attachment.
0 ignored issues
show
Documentation Bug introduced by
The doc comment boolean. at position 0 could not be parsed: Unknown type name 'boolean.' at position 0 in boolean..
Loading history...
356
     */
357
    public function hasAttachments()
358
    {
359
        $parts = $this->getAllParts(collect([$this->payload]));
360
        foreach ($parts as $part) {
361
            if (!empty($part->body->attachmentId)) {
362
                return true;
363
            }
364
        }
365
        return false;
366
    }
367
368
    /**
369
     * @return Integer. Number of attachments of the message.
0 ignored issues
show
Documentation Bug introduced by
The doc comment Integer. at position 0 could not be parsed: Unknown type name 'Integer.' at position 0 in Integer..
Loading history...
370
     */
371
    public function countAttachments()
372
    {
373
        $numberOfAttachments = 0;
374
        $parts = $this->getAllParts(collect([$this->payload]));
375
        foreach ($parts as $part) {
376
            if (!empty($part->body->attachmentId)) {
377
                $numberOfAttachments++;
378
            }
379
        }
380
        return $numberOfAttachments;
381
    }
382
383
384
    public function getDecodedBody($content)
385
    {
386
        $content = str_replace('_', '/', str_replace('-', '+', $content));
387
388
        return base64_decode($content);
389
    }
390
391
    /**
392
     * @return string base64 version of the body
393
     */
394
    public function getRawHtmlBody()
395
    {
396
        return $this->getHtmlBody(true);
397
    }
398
399
    /**
400
     * @param  bool  $raw
401
     *
402
     * @return string
403
     */
404
    public function getHtmlBody($raw = false)
405
    {
406
        $content = $this->getBody('text/html');
407
408
        return $raw ? $content : $this->getDecodedBody($content);
409
    }
410
411
    /**
412
     * @return Collection
413
     * @throws \Exception
414
     */
415
    public function getAttachmentsWithData()
416
    {
417
        return $this->getAttachments(true);
418
    }
419
420
    /**
421
     * Returns a collection of attachments
422
     *
423
     * @param  bool  $preload  Preload only the attachment's 'data'.
424
     * But does not load the other attachment info like filename, mimetype,
425
     *   etc.. Maybe would be better to push the data to the other info? So ot
426
     *   would all be together.
427
     *
428
     * @return Collection
429
     * @throws \Exception
430
     */
431
    public function getAttachments($preload = false)
432
    {
433
        $attachments = new Collection([]);
434
        $parts = $this->getAllParts(collect([$this->payload]));
435
        foreach ($parts as $part) {
436
            if (!empty($part->body->attachmentId)) {
437
                $attachment = (new Attachment($part->body->attachmentId,
438
                    $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
493
    /**
494
     * checks if message has at least one part without itarating through all
495
     * parts
496
     *
497
     * @return bool
498
     */
499
    public function hasParts()
500
    {
501
        if ($this->iterateParts(
502
            collect([$this->payload]), $returnOnFirstFound = true)
503
        ) {
504
            return true;
505
        } else {
506
            return false;
507
        }
508
    }
509
510
    /**
511
     * checks if message has no parts withour iterating through all parts
512
     *
513
     * @return bool
514
     */
515
    public function hasNoParts()
516
    {
517
        if ($this->hasParts()) {
518
            return false;
519
        } else {
520
            return true;
521
        }
522
    }
523
524
525
    //unused function? Could be removed?
526
    public function extractFromBody()
527
    {
528
529
        if ($this->hasNoParts()) {
530
            $type = $this->payload->getMimeType();
531
            $body = $this->payload->getBody();
532
            if ($type == 'text/html' || $type == 'text/plain') {
533
                $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...
534
            }
535
            if ($body->getAttachmentId()) {
536
                $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...
537
                    'id' => $body->getAttachmentId(),
538
                    'mimeType' => $type,
539
                ];
540
            }
541
        } else {
542
            $parts = $this->payload->getParts();
543
            foreach ($parts as $part) {
544
                if (empty($part->getParts())) {
545
                    $type = $part->getMimeType();
546
                    $body = $part->getBody();
547
                    if ($type == 'text/html' || $type == 'text/plain') {
548
                        if (isset($this->messageBodyArr[$type])) {
549
                            $this->messageBodyArr[$type] .= $this->getDecodedBody($body->getData());
550
                        } else {
551
                            $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...
552
                        }
553
                    }
554
555
                    if ($body->getAttachmentId()) {
556
                        $this->attachmentData[] = [
557
                            'id' => $body->getAttachmentId(),
558
                            'fileName' => $part->getFilename(),
559
                            'mimeType' => $type,
560
                        ];
561
                    }
562
                } else {
563
                    $subParts = $part->getParts();
564
                    $this->traverseData($subParts);
565
                }
566
            }
567
        }
568
    }
569
570
571
    //unused function? Could be removed?
572
    public function traverseData($parts)
573
    {
574
        foreach ($parts as $part) {
575
            if (empty($part->getParts())) {
576
                $type = $part->getMimeType();
577
                $body = $part->getBody();
578
                if ($type == 'text/html' || $type == 'text/plain') {
579
                    if (isset($this->messageBodyArr[$type])) {
580
                        $this->messageBodyArr[$type] .= $this->getDecodedBody($body->getData());
581
                    } else {
582
                        $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...
583
                    }
584
                }
585
586
                if ($body->getAttachmentId()) {
587
                    $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...
588
                        'id' => $body->getAttachmentId(),
589
                        'fileName' => $part->getFilename(),
590
                        'mimeType' => $type,
591
                    ];
592
593
                }
594
            } else {
595
                $subParts = $part->getParts();
596
                $this->traverseData($subParts);
597
            }
598
        }
599
    }
600
}
601