Replyable   B
last analyzed

Complexity

Total Complexity 49

Size/Duplication

Total Lines 465
Duplicated Lines 0 %

Importance

Changes 15
Bugs 6 Features 2
Metric Value
eloc 121
dl 0
loc 465
rs 8.48
c 15
b 6
f 2
wmc 49

27 Methods

Rating   Name   Duplication   Size   Complexity  
A view() 0 5 1
A convertEmailList() 0 11 3
A to() 0 6 1
A optionalParameters() 0 5 1
A bcc() 0 6 1
A priority() 0 5 1
A cc() 0 6 1
A attach() 0 13 3
A from() 0 6 1
A reply() 0 14 2
A message() 0 5 1
A emailList() 0 6 2
A subject() 0 5 1
A setReplyThread() 0 7 2
A setReplyFrom() 0 6 3
A fromAddress() 0 7 3
A returnCopies() 0 15 4
A __construct() 0 3 1
A base64_encode() 0 3 1
A setReplyTo() 0 7 2
A markdown() 0 11 2
A setHeader() 0 5 1
A setReplySubject() 0 4 2
A send() 0 7 1
A getMessageBody() 0 20 2
A toAddress() 0 7 3
A getMessageIdHeader() 0 10 3

How to fix   Complexity   

Complex Class

Complex classes like Replyable often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Replyable, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Dacastro4\LaravelGmail\Traits;
4
5
use Dacastro4\LaravelGmail\Services\Message\Mail;
6
use Google_Service_Gmail;
7
use Google_Service_Gmail_Message;
8
use Symfony\Component\Mime\Address;
9
use Symfony\Component\Mime\Email;
10
use Illuminate\Container\Container;
11
use Illuminate\Mail\Markdown;
12
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
13
14
/**
15
 * @property Google_Service_Gmail $service
16
 */
17
trait Replyable
18
{
19
	use HasHeaders;
20
21
	private $symfonyEmail;
22
23
	/**
24
	 * Gmail optional parameters
25
	 *
26
	 * @var array
27
	 */
28
	private $parameters = [];
29
30
	/**
31
	 * Text or html message to send
32
	 *
33
	 * @var string
34
	 */
35
	private $message;
36
37
	/**
38
	 * Subject of the email
39
	 *
40
	 * @var string
41
	 */
42
	private $subject;
43
44
	/**
45
	 * Sender's email
46
	 *
47
	 * @var string
48
	 */
49
	private $from;
50
51
	/**
52
	 * Sender's name
53
	 *
54
	 * @var  string
55
	 */
56
	private $nameFrom;
57
58
	/**
59
	 * Email of the recipient
60
	 *
61
	 * @var string|array
62
	 */
63
	private $to;
64
65
	/**
66
	 * Name of the recipient
67
	 *
68
	 * @var string
69
	 */
70
	private $nameTo;
71
72
	/**
73
	 * Single email or array of email for a carbon copy
74
	 *
75
	 * @var array|string
76
	 */
77
	private $cc;
78
79
	/**
80
	 * Name of the recipient
81
	 *
82
	 * @var string
83
	 */
84
	private $nameCc;
85
86
	/**
87
	 * Single email or array of email for a blind carbon copy
88
	 *
89
	 * @var array|string
90
	 */
91
	private $bcc;
92
93
	/**
94
	 * Name of the recipient
95
	 *
96
	 * @var string
97
	 */
98
	private $nameBcc;
99
100
	/**
101
	 * List of attachments
102
	 *
103
	 * @var array
104
	 */
105
	private $attachments = [];
106
107
	private $priority = 2;
108
109
	public function __construct()
110
	{
111
		$this->symfonyEmail = new Email();
112
	}
113
114
	/**
115
	 * Receives the recipient's
116
	 * If multiple recipients will receive the message an array should be used.
117
	 * Example: array('[email protected]', '[email protected]' => 'A name')
118
	 *
119
	 * If $name is passed and the first parameter is a string, this name will be
120
	 * associated with the address.
121
	 *
122
	 * @param string|array $to
123
	 *
124
	 * @param string|null $name
125
	 *
126
	 * @return Replyable
127
	 */
128
	public function to($to, $name = null)
129
	{
130
		$this->to = $this->emailList($to, $name);
131
		$this->nameTo = $name;
132
133
		return $this;
134
	}
135
136
	public function from($from, $name = null)
137
	{
138
		$this->from = $from;
139
		$this->nameFrom = $name;
140
141
		return $this;
142
	}
143
144
	/**
145
	 * @param array|string $cc
146
	 *
147
	 * @param string|null $name
148
	 *
149
	 * @return Replyable
150
	 */
151
	public function cc($cc, $name = null)
152
	{
153
		$this->cc = $this->emailList($cc, $name);
154
		$this->nameCc = $name;
155
156
		return $this;
157
	}
158
159
	private function emailList($list, $name = null)
160
	{
161
		if (is_array($list)) {
162
			return $this->convertEmailList($list, $name);
163
		} else {
164
			return $list;
165
		}
166
	}
167
168
	private function convertEmailList($emails, $name = null)
169
	{
170
		$newList = [];
171
		$count = 0;
172
		foreach ($emails as $key => $email) {
173
			$emailName = isset($name[$count]) ? $name[$count] : explode('@', $email)[0];
174
			$newList[$email] = $emailName;
175
			$count = $count + 1;
176
		}
177
178
		return $newList;
179
	}
180
181
	/**
182
	 * @param array|string $bcc
183
	 *
184
	 * @param string|null $name
185
	 *
186
	 * @return Replyable
187
	 */
188
	public function bcc($bcc, $name = null)
189
	{
190
		$this->bcc = $this->emailList($bcc, $name);
191
		$this->nameBcc = $name;
192
193
		return $this;
194
	}
195
196
	/**
197
	 * @param string $subject
198
	 *
199
	 * @return Replyable
200
	 */
201
	public function subject($subject)
202
	{
203
		$this->subject = $subject;
204
205
		return $this;
206
	}
207
208
	/**
209
	 * @param string $view
210
	 * @param array $data
211
	 * @param array $mergeData
212
	 *
213
	 * @return Replyable
214
	 * @throws \Throwable
215
	 */
216
	public function view($view, $data = [], $mergeData = [])
217
	{
218
		$this->message = view($view, $data, $mergeData)->render();
219
220
		return $this;
221
	}
222
223
	/**
224
	 * loads markdown file for message body
225
	 *
226
	 * @return Replyable
227
	 * @throws \Throwable
228
	 */
229
	public function markdown(string $markdown_view, array $data = [])
230
	{
231
		$markdown = Container::getInstance()->make(Markdown::class);
232
233
		if (config('mail.markdown.theme')) {
234
			$markdown->theme(config('mail.markdown.theme'));
235
		}
236
237
		$this->message = $markdown->render($markdown_view, $data);
238
239
		return $this;
240
	}
241
242
	/**
243
	 * @param string $message
244
	 *
245
	 * @return Replyable
246
	 */
247
	public function message($message)
248
	{
249
		$this->message = $message;
250
251
		return $this;
252
	}
253
254
	/**
255
	 * Attaches new file to the email from the Storage folder
256
	 *
257
	 * @param array $files comma separated of files
258
	 *
259
	 * @return Replyable
260
	 * @throws \Exception
261
	 */
262
	public function attach(...$files)
263
	{
264
265
		foreach ($files as $file) {
266
267
			if (!file_exists($file)) {
268
				throw new FileNotFoundException($file);
269
			}
270
271
			array_push($this->attachments, $file);
272
		}
273
274
		return $this;
275
	}
276
277
	/**
278
	 * The value is an integer where 1 is the highest priority and 5 is the lowest.
279
	 *
280
	 * @param int $priority
281
	 *
282
	 * @return Replyable
283
	 */
284
	public function priority($priority)
285
	{
286
		$this->priority = $priority;
287
288
		return $this;
289
	}
290
291
	/**
292
	 * @param array $parameters
293
	 *
294
	 * @return Replyable
295
	 */
296
	public function optionalParameters(array $parameters)
297
	{
298
		$this->parameters = $parameters;
299
300
		return $this;
301
	}
302
303
	/**
304
	 * Reply to a specific email
305
	 *
306
	 * @return Mail
307
	 * @throws \Exception
308
	 */
309
	public function reply()
310
	{
311
		if (!$this->getId()) {
312
			throw new \Exception('This is a new email. Use send().');
313
		}
314
315
		$this->setReplyThread();
316
		$this->setReplySubject();
317
		$this->setReplyTo();
318
		$this->setReplyFrom();
319
		$body = $this->getMessageBody();
320
		$body->setThreadId($this->getThreadId());
321
322
		return new Mail($this->service->users_messages->send('me', $body, $this->parameters));
323
	}
324
325
	public abstract function getId();
326
327
	private function setReplyThread()
328
	{
329
		$threadId = $this->getThreadId();
330
		if ($threadId) {
331
			$this->setHeader('In-Reply-To', $this->getMessageIdHeader());
332
			$this->setHeader('References', $this->getHeader('References'));
333
			$this->setHeader('Message-ID', $this->getMessageIdHeader());
334
		}
335
	}
336
337
	private function getMessageIdHeader()
338
	{
339
		if ($messageId = $this->getHeader('Message-ID')) {
340
			return $messageId;
341
		}
342
343
		if ($messageId = $this->getHeader('Message-Id')) {
344
			return $messageId;
345
		}
346
		return null;
347
	}
348
349
	public abstract function getThreadId();
350
351
	/**
352
	 * Add a header to the email
353
	 *
354
	 * @param string $header
355
	 * @param string $value
356
	 */
357
	public function setHeader($header, $value)
358
	{
359
		$headers = $this->symfonyEmail->getHeaders();
360
361
		$headers->addTextHeader($header, $value);
362
363
	}
364
365
	private function setReplySubject()
366
	{
367
		if (!$this->subject) {
368
			$this->subject = $this->getSubject();
369
		}
370
	}
371
372
	private function setReplyTo()
373
	{
374
		if (!$this->to) {
375
			$replyTo = $this->getReplyTo();
376
377
			$this->to = $replyTo['email'];
378
			$this->nameTo = $replyTo['name'];
379
		}
380
	}
381
382
	private function setReplyFrom()
383
	{
384
		if (!$this->from) {
385
			$this->from = $this->getUser();
386
			if (!$this->from) {
387
				throw new \Exception('Reply from is not defined');
388
			}
389
		}
390
	}
391
392
	public abstract function getSubject();
393
394
	public abstract function getReplyTo();
395
396
	public abstract function getUser();
397
398
	/**
399
	 * @return Google_Service_Gmail_Message
400
	 */
401
	private function getMessageBody()
402
	{
403
		$body = new Google_Service_Gmail_Message();
404
405
		$this->symfonyEmail
406
			->from($this->fromAddress())
407
			->to($this->toAddress())
408
			->cc($this->returnCopies($this->cc))
409
			->bcc($this->returnCopies($this->bcc))
410
			->subject($this->subject)
411
			->html($this->message)
412
			->priority($this->priority);
413
414
		foreach ($this->attachments as $file) {
415
			$this->symfonyEmail->attachFromPath($file);
416
		}
417
418
		$body->setRaw($this->base64_encode($this->symfonyEmail->toString()));
419
420
		return $body;
421
	}
422
423
	/**
424
	 * @param array|string $cc
425
	 * @return array|string
426
	 */
427
	public function returnCopies($cc)
428
	{
429
		if ($cc) {
430
			$final = $this->cc;
431
432
			if (is_array($this->cc)) {
433
				foreach ($this->cc as $emailCc => $nameCc) {
434
					$final[] = new Address($emailCc, $nameCc);
435
				}
436
			}
437
438
			return $final;
439
		}
440
441
		return [];
442
	}
443
444
	public function toAddress()
445
	{
446
		if ($this->to) {
447
			return new Address($this->to, $this->nameTo ?: '');
0 ignored issues
show
Bug introduced by
It seems like $this->to can also be of type array; however, parameter $address of Symfony\Component\Mime\Address::__construct() 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

447
			return new Address(/** @scrutinizer ignore-type */ $this->to, $this->nameTo ?: '');
Loading history...
448
		}
449
450
		return [];
451
	}
452
453
	public function fromAddress()
454
	{
455
		if ($this->from) {
456
			return new Address($this->from, $this->nameFrom ?: '');
457
		}
458
459
		return [];
460
	}
461
462
	private function base64_encode($data)
463
	{
464
		return rtrim(strtr(base64_encode($data), ['+' => '-', '/' => '_']), '=');
465
	}
466
467
	/**
468
	 * Sends a new email
469
	 *
470
	 * @return self|Mail
471
	 */
472
	public function send()
473
	{
474
		$body = $this->getMessageBody();
475
476
		$this->setMessage($this->service->users_messages->send('me', $body, $this->parameters));
477
478
		return $this;
479
	}
480
481
	protected abstract function setMessage(\Google_Service_Gmail_Message $message);
482
}
483