Completed
Push — feat_email_envelope ( e5445d )
by Stefano
02:37
created

Envelope   C

Complexity

Total Complexity 71

Size/Duplication

Total Lines 174
Duplicated Lines 17.82 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 71
c 1
b 0
f 0
lcom 1
cbo 0
dl 31
loc 174
rs 5.5904

14 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 15 10
B add_emails() 0 17 5
A from() 3 6 4
A to() 3 6 4
A cc() 3 6 4
A bcc() 3 6 4
A replyTo() 3 6 4
A subject() 0 7 4
A contentType() 7 7 4
A message() 7 7 4
A attach() 0 8 4
B head() 2 16 11
C body() 0 34 8
A build() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Envelope 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 Envelope, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Email\Envelope
5
 *
6
 * Wraps and compile a MIME Email envelope.
7
 *
8
 * @package core
9
 * @author [email protected]
10
 * @copyright Caffeina srl - 2016 - http://caffeina.com
11
 */
12
13
namespace Email;
14
15
class Envelope {
16
17
  protected  $uid,
18
             $to,
19
             $from,
20
             $cc,
21
             $bcc,
22
             $replyTo,
23
             $subject,
24
             $message,
25
             $contentType = 'text/html; charset="utf-8"',
26
             $attachments,
27
             $compiled_head,
28
             $compiled_body;
29
30
  public function __construct($email=null){
31
    if ($email) {
32
      $email = (object)$email;
33
      if(isset($email->to))           $this->to($email->to);
34
      if(isset($email->from))         $this->from($email->from);
35
      if(isset($email->cc))           $this->cc($email->cc);
36
      if(isset($email->bcc))          $this->bcc($email->bcc);
37
      if(isset($email->replyTo))      $this->replyTo($email->replyTo);
38
      if(isset($email->subject))      $this->subject($email->subject);
39
      if(isset($email->message))      $this->message($email->message);
40
      if(isset($email->attachments))  $this->attach($email->attachments);
41
    }
42
    $this->uid  = '_CORE_'.md5(uniqid(time()));
43
44
  }
45
46
  protected function add_emails(&$pool, $emails, $append=true){
47
    $this->compiled_head = null;
48
    foreach ((array)$emails as $values) {
49
      foreach(preg_split('/\s*,\s*/',$values) as $value) {
50
        if(strpos($value,'<')!==false){
51
          $value   = str_replace('>','',$value);
52
          $parts   = explode('<',$value,2);
53
          $name    = trim(current($parts));
54
          $email   = trim(end($parts));
55
          $address = "$name <{$email}>";
56
        } else {
57
          $address = $value;
58
        }
59
        if ($append) $pool[] = $address; else $pool = $address;
60
      }
61
    }
62
  }
63
64
  public function from($value=null){
65 View Code Duplication
    if ($value!==null && $value) {
66
      $this->add_emails($this->from, $value, false);
67
    } else if ($value===false) $this->from = false;
68
    return $this->from;
69
  }
70
71
  public function to($value=null){
72 View Code Duplication
    if ($value!==null && $value) {
73
      $this->add_emails($this->to, $value);
74
    } else if ($value===false) $this->to = [];
75
    return $this->to;
76
  }
77
78
  public function cc($value=null){
79 View Code Duplication
    if ($value!==null && $value) {
80
      $this->add_emails($this->cc, $value);
81
    } else if ($value===false) $this->cc = [];
82
    return $this->cc;
83
  }
84
85
  public function bcc($value=null){
86 View Code Duplication
    if ($value!==null && $value) {
87
      $this->add_emails($this->bcc, $value);
88
    } else if ($value===false) $this->bcc = [];
89
    return $this->bcc;
90
  }
91
92
  public function replyTo($value=null){
93 View Code Duplication
    if ($value!==null && $value) {
94
      $this->add_emails($this->replyTo, $value, false);
95
    } else if ($value===false) $this->replyTo = false;
96
    return $this->replyTo;
97
  }
98
99
  public function subject($value=null){
100
    if ($value!==null && $value) {
101
      $this->compiled_head = null;
102
      $this->subject = $value;
103
    } else if ($value===false) $this->subject = false;
104
    return $this->subject;
105
  }
106
107 View Code Duplication
  public function contentType($value=null){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
108
    if ($value!==null && $value) {
109
      $this->compiled_body = null;
110
      $this->contentType = $value;
111
    } else if ($value===false) $this->contentType = false;
0 ignored issues
show
Documentation Bug introduced by
The property $contentType was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
112
    return $this->contentType;
113
  }
114
115 View Code Duplication
  public function message($value=null){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
116
    if ($value!==null && $value) {
117
      $this->compiled_body = null;
118
      $this->message = $value;
119
    } else if ($value===false) $this->message = false;
120
    return $this->message;
121
  }
122
123
  public function attach($file){
124
    $this->compiled_body = null;
125
    if (isset($file->content) || isset($file['content'])) {
126
      $this->attachments[] = $file;
127
    } else foreach ((array)$file as $curfile) {
128
      $this->attachments[] = $curfile;
129
    }
130
  }
131
132
  public function head($recompile=false){
133
    if ($recompile || null === $this->compiled_head){
134
      $head   = [];
135
      $head[] = "Subject: {$this->subject}";
136
      if($this->from)                        $head[] = "From: {$this->from}";
137
      if(is_array($this->to)  && $this->to)  $head[] = "To: "  . implode(', ',$this->to);
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->to of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
138 View Code Duplication
      if(is_array($this->cc)  && $this->cc)  $head[] = "Cc: "  . implode(', ',$this->cc);
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cc of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
139 View Code Duplication
      if(is_array($this->bcc) && $this->bcc) $head[] = "Bcc: " . implode(', ',$this->bcc);
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->bcc of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
140
      if($this->replyTo)                     $head[] = "Reply-To: {$this->replyTo}";
141
      $head[] = 'MIME-Version: 1.0';
142
      $head[] = "Content-Type: multipart/mixed; boundary=\"{$this->uid}\"";
143
144
      $this->compiled_head = implode("\r\n", $head);
145
    }
146
    return $this->compiled_head;
147
  }
148
149
  public function body($recompile=false){
150
    if ($recompile || null === $this->compiled_body){
151
      $body[] = "--{$this->uid}";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$body was never initialized. Although not strictly required by PHP, it is generally a good practice to add $body = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
152
      $body[] = "Content-Type: {$this->contentType}";
153
      $body[] = "Content-Transfer-Encoding: quoted-printable";
154
      $body[] = '';
155
      $body[] = quoted_printable_encode($this->message);
156
      $body[] = '';
157
158
      if ($this->attachments) foreach ((array)$this->attachments as $file) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->attachments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
159
160
        if (is_string($file)) {
161
          $name = basename($file);
162
          $data = file_get_contents($file);
163
        } else {
164
          $name = isset($file['name'])    ? $file['name']    : 'untitled';
165
          $data = isset($file['content']) ? $file['content'] : '';
166
        }
167
168
        $body[] = "--{$this->uid}";
169
        $body[] = "Content-Type: application/octet-stream; name=\"{$name}\"";
170
        $body[] = "Content-Transfer-Encoding: base64";
171
        $body[] = "Content-Disposition: attachment; filename=\"{$name}\"";
172
        $body[] = '';
173
        $body[] = chunk_split(base64_encode($data));
174
        $body[] = '';
175
      }
176
177
      $body[] = "--{$this->uid}--";
178
179
      $this->compiled_body = implode("\r\n", $body);
180
    }
181
    return $this->compiled_body;
182
  }
183
184
  public function build(){
185
    return $this->head() . "\r\n" . $this->body();
186
  }
187
188
}
189