Swift_Message   D
last analyzed

Complexity

Total Complexity 171

Size/Duplication

Total Lines 786
Duplicated Lines 18.45 %

Coupling/Cohesion

Components 2
Dependencies 7

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 145
loc 786
rs 4.4444
wmc 171
lcom 2
cbo 7

43 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 10 47 8
A setReference() 0 5 2
A getReference() 0 5 2
A getLevel() 0 4 1
A setId() 0 4 1
A generateId() 0 12 3
A getId() 0 4 2
A setReturnPath() 0 5 2
A getReturnPath() 0 13 4
A setFrom() 0 5 2
A getFrom() 0 4 2
B setTo() 12 12 5
A getTo() 0 9 3
B setReplyTo() 12 12 5
A getReplyTo() 0 9 3
B setCc() 12 12 5
A getCc() 9 9 3
B setBcc() 12 12 5
A getBcc() 9 9 3
A setSubject() 0 4 1
A getSubject() 0 4 1
A setDate() 0 4 1
A getDate() 0 4 1
A setCharset() 1 5 4
A getCharset() 0 11 2
A setFlowed() 0 6 2
A isFlowed() 9 9 3
A setPriority() 0 10 3
A requestReadReceipt() 0 16 3
A wantsReadReceipt() 0 4 1
A getPriority() 0 5 2
A setBody() 0 4 1
A getBody() 0 4 1
A setMimeWarning() 0 4 1
A getMimeWarning() 0 4 1
B attach() 10 28 6
B detach() 12 28 5
A fixContentType() 0 6 4
D moveBranchIn() 0 30 9
C postAttachFixStructure() 7 39 15
D moveBranchOut() 0 27 9
C postDetachFixStructure() 20 50 21
C preBuild() 10 34 13

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

1
<?php
2
3
/**
4
 * Swift Mailer Message Component
5
 * Composes MIME 1.0 messages meeting various RFC standards
6
 * Deals with attachments, embedded images, multipart bodies, forwarded messages...
7
 * Please read the LICENSE file
8
 * @copyright Chris Corbyn <[email protected]>
9
 * @author Chris Corbyn <[email protected]>
10
 * @package Swift_Message
11
 * @license GNU Lesser General Public License
12
 */
13
14
require_once dirname(__FILE__) . "/ClassLoader.php";
15
Swift_ClassLoader::load("Swift_Address");
16
Swift_ClassLoader::load("Swift_Message_Mime");
17
Swift_ClassLoader::load("Swift_Message_Image");
18
Swift_ClassLoader::load("Swift_Message_Part");
19
20
21
/**
22
 * Swift Message class
23
 * @package Swift_Message
24
 * @author Chris Corbyn <[email protected]>
25
 */
26
class Swift_Message extends Swift_Message_Mime
27
{
28
  /**
29
   * Constant from a high priority message (pretty meaningless)
30
   */
31
  const PRIORITY_HIGH = 1;
32
  /**
33
   * Constant for a low priority message
34
   */
35
  const PRIORITY_LOW = 5;
36
  /**
37
   * Constant for a normal priority message
38
   */
39
  const PRIORITY_NORMAL = 3;
40
  /**
41
   * The MIME warning for client not supporting multipart content
42
   * @var string
43
   */
44
  protected $mimeWarning = null;
45
  /**
46
   * The version of the library (Swift) if known.
47
   * @var string
48
   */
49
  protected $libVersion = "";
50
  /**
51
   * A container for references to other objects.
52
   * This is used in some very complex logic when sub-parts get shifted around.
53
   * @var array
54
   */
55
  protected $references = array(
56
    "parent" => array("alternative" => null, "mixed" => null, "related" => null),
57
    "alternative" => array(),
58
    "mixed" => array(),
59
    "related" => array()
60
  );
61
  
62
  /**
63
   * Ctor.
64
   * @param string Message subject
65
   * @param string Body
66
   * @param string Content-type
67
   * @param string Encoding
68
   * @param string Charset
69
   * @param string $encoding
0 ignored issues
show
Documentation introduced by
Should the type for parameter $encoding not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
70
   * @param string $charset
0 ignored issues
show
Documentation introduced by
Should the type for parameter $charset not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
71
   */
72
  public function __construct($subject="", $body=null, $type="text/plain", $encoding=null, $charset=null)
73
  {
74
    parent::__construct();
75
    if (function_exists("date_default_timezone_set") && function_exists("date_default_timezone_get"))
76
    {
77
      date_default_timezone_set(@date_default_timezone_get());
78
    }
79
    $this->setReturnPath(null);
80
    $this->setTo("");
81
    $this->setFrom("");
82
    $this->setCc(null);
83
    $this->setBcc(null);
84
    $this->setReplyTo(null);
85
    $this->setSubject($subject);
86
    $this->setDate(time());
87
    if (defined("Swift::VERSION"))
88
    {
89
      $this->libVersion = Swift::VERSION;
90
      $this->headers->set("X-LibVersion", $this->libVersion);
91
    }
92
    $this->headers->set("MIME-Version", "1.0");
93
    $this->setContentType($type);	
94
    $this->setCharset($charset);
95
    $this->setFlowed(true);
96
    $this->setEncoding($encoding);
97
    
98
    foreach (array_keys($this->references["parent"]) as $key)
99
    {
100
      $this->setReference("parent", $key, $this);
101
    }
102
    
103
    $this->setMimeWarning(
104
    "This is a message in multipart MIME format.  Your mail client should not be displaying this. " .
105
    "Consider upgrading your mail client to view this message correctly."
106
    );
107
    
108 View Code Duplication
    if ($body !== null)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
109
    {
110
      $this->setData($body);
111
      if ($charset === null)
112
      {
113
        Swift_ClassLoader::load("Swift_Message_Encoder");
114
        if (Swift_Message_Encoder::instance()->isUTF8($body)) $this->setCharset("utf-8");
115
        else $this->setCharset("iso-8859-1");
116
      }
117
    }
118
  }
119
  /**
120
   * Sets a reference so when nodes are nested, operations can be redirected.
121
   * This really should be refactored to use just one array rather than dynamic variables.
122
   * @param string Key 1
123
   * @param string Key 2
124
   * @param Object Reference
125
   * @param string $where
126
   */
127
  protected function setReference($where, $key, $ref)
128
  {
129
    if ($ref === $this) $this->references[$where][$key] = false;
130
    else $this->references[$where][$key] = $ref;
131
  }
132
  /**
133
   * Get a reference to an object (for complex reasons).
134
   * @param string Key 1
135
   * @param string Key 2
136
   * @param string $where
137
   * @return Object
138
   */
139
  protected function getReference($where, $key)
140
  {
141
    if (!$this->references[$where][$key]) return $this;
142
    else return $this->references[$where][$key];
143
  }
144
  /**
145
   * Get the level in the MIME hierarchy at which this section should appear.
146
   * @return string
147
   */
148
  public function getLevel()
149
  {
150
    return Swift_Message_Mime::LEVEL_TOP;
151
  }
152
  /**
153
   * Set the message id literally.
154
   * Unless you know what you are doing you should be using generateId() rather than this method,
155
   * otherwise you may break compliancy with RFC 2822.
156
   * @param string The message ID string.
157
   * @param null|string $id
158
   */
159
  public function setId($id)
160
  {
161
    $this->headers->set("Message-ID", $id);
162
  }
163
  /**
164
   * Create a RFC 2822 compliant message id, optionally based upon $idstring.
165
   * The message ID includes information about the current time, the server and some random characters.
166
   * @param string An optional string the base the ID on
167
   * @return string The generated message ID, including the <> quotes.
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
168
   * @author Cristian Rodriguez <[email protected]>
169
   */
170
  public function generateId($idstring=null)
0 ignored issues
show
Coding Style introduced by
generateId uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
171
  {
172
    $midparams =  array(
173
      "utctime" => gmstrftime("%Y%m%d%H%M%S"),
174
      "pid" => getmypid(),
175
      "randint" => mt_rand(),
176
      "customstr" => (preg_match("/^(?<!\\.)[a-z0-9\\.]+(?!\\.)\$/iD", $idstring) ? $idstring : "swift") ,
177
      "hostname" => (isset($_SERVER["SERVER_NAME"]) ? $_SERVER["SERVER_NAME"] : php_uname("n")),
178
    );
179
    $this->setId(vsprintf("<%s.%d.%d.%s@%s>", $midparams));
180
    return $this->getId();
181
  }
182
  /**
183
   * Get the generated message ID for this message, including the <> quotes.
184
   * If generated automatically, or using generateId() this method returns a RFC2822 compliant Message-ID.
185
   * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
186
   * @author Cristian Rodriguez <[email protected]>
187
   */
188
  public function getId()
189
  {
190
    return $this->headers->has("Message-ID") ? $this->headers->get("Message-ID") : null;
191
  }
192
  /**
193
   * Set the address in the Return-Path: header
194
   * @param string The bounce-detect address
195
   */
196
  public function setReturnPath($address)
197
  {
198
    if ($address instanceof Swift_Address) $address = $address->build(true);
199
    $this->headers->set("Return-Path", $address);
200
  }
201
  /**
202
   * Return the address used in the Return-Path: header
203
   * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
204
   * @param boolean Return the address for SMTP command
205
   */
206
  public function getReturnPath($smtp=false)
207
  {
208
    if ($this->headers->has("Return-Path"))
209
    {
210
      if (!$smtp) return $this->headers->get("Return-Path");
211
      else
212
      {
213
        $path = $this->headers->get("Return-Path");
214
        if (strpos($path, ">") > strpos($path, "<")) return substr($path, ($start = strpos($path, "<")), ($start + strrpos($path, ">") + 1));
215
        else return "<" . $path . ">";
216
      }
217
    }
218
  }
219
  /**
220
   * Set the address in the From: header
221
   * @param string The address to set as From
222
   */
223
  public function setFrom($from)
224
  {
225
    if ($from instanceof Swift_Address) $from = $from->build();
226
    $this->headers->set("From", $from);
227
  }
228
  /**
229
   * Get the address used in the From: header
230
   * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
231
   */
232
  public function getFrom()
233
  {
234
    if ($this->headers->has("From")) return $this->headers->get("From");
235
  }
236
  /**
237
   * Set the list of recipients in the To: header
238
   * @param mixed An array or a string
239
   */
240 View Code Duplication
  public function setTo($to)
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...
Comprehensibility introduced by
Avoid variables with short names like $to. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
241
  {
242
    if ($to)
243
    {
244
      if (!is_array($to)) $to = array($to);
245
      foreach ($to as $key => $value)
246
      {
247
        if ($value instanceof Swift_Address) $to[$key] = $value->build();
248
      }
249
    }
250
    $this->headers->set("To", $to);
251
  }
252
  /**
253
   * Return the list of recipients in the To: header
254
   * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
255
   */
256
  public function getTo()
257
  {
258
    if ($this->headers->has("To"))
259
    {
260
      $to = $this->headers->get("To");
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $to. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
261
      if ($to == "") return array();
262
      else return (array) $to;
263
    }
264
  }
265
  /**
266
   * Set the list of recipients in the Reply-To: header
267
   * @param mixed An array or a string
268
   */
269 View Code Duplication
  public function setReplyTo($replyto)
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...
270
  {
271
    if ($replyto)
272
    {
273
      if (!is_array($replyto)) $replyto = array($replyto);
274
      foreach ($replyto as $key => $value)
275
      {
276
        if ($value instanceof Swift_Address) $replyto[$key] = $value->build();
277
      }
278
    }
279
    $this->headers->set("Reply-To", $replyto);
280
  }
281
  /**
282
   * Return the list of recipients in the Reply-To: header
283
   * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
284
   */
285
  public function getReplyTo()
286
  {
287
    if ($this->headers->has("Reply-To"))
288
    {
289
      $reply_to = $this->headers->get("Reply-To");
290
      if ($reply_to == "") return array();
291
      else return (array) $reply_to;
292
    }
293
  }
294
  /**
295
   * Set the list of recipients in the Cc: header
296
   * @param mixed An array or a string
297
   */
298 View Code Duplication
  public function setCc($cc)
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...
Comprehensibility introduced by
Avoid variables with short names like $cc. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
299
  {
300
    if ($cc)
301
    {
302
      if (!is_array($cc)) $cc = array($cc);
303
      foreach ($cc as $key => $value)
304
      {
305
        if ($value instanceof Swift_Address) $cc[$key] = $value->build();
306
      }
307
    }
308
    $this->headers->set("Cc", $cc);
309
  }
310
  /**
311
   * Return the list of recipients in the Cc: header
312
   * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
313
   */
314 View Code Duplication
  public function getCc()
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...
315
  {
316
    if ($this->headers->has("Cc"))
317
    {
318
      $cc = $this->headers->get("Cc");
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $cc. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
319
      if ($cc == "") return array();
320
      else return (array) $cc;
321
    }
322
  }
323
  /**
324
   * Set the list of recipients in the Bcc: header
325
   * @param mixed An array or a string
326
   */
327 View Code Duplication
  public function setBcc($bcc)
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...
328
  {
329
    if ($bcc)
330
    {
331
      if (!is_array($bcc)) $bcc = array($bcc);
332
      foreach ($bcc as $key => $value)
333
      {
334
        if ($value instanceof Swift_Address) $bcc[$key] = $value->build();
335
      }
336
    }
337
    $this->headers->set("Bcc", $bcc);
338
  }
339
  /**
340
   * Return the list of recipients in the Bcc: header
341
   * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
342
   */
343 View Code Duplication
  public function getBcc()
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...
344
  {
345
    if ($this->headers->has("Bcc"))
346
    {
347
      $bcc = $this->headers->get("Bcc");
348
      if ($bcc == "") return array();
349
      else return (array) $bcc;
350
    }
351
  }
352
  /**
353
   * Set the subject in the headers
354
   * @param string The subject of the email
355
   */
356
  public function setSubject($subject)
357
  {
358
    $this->headers->set("Subject", $subject);
359
  }
360
  /**
361
   * Get the current subject used in the headers
362
   * @return string
363
   */
364
  public function getSubject()
365
  {
366
    return $this->headers->get("Subject");
367
  }
368
  /**
369
   * Set the date in the headers in RFC 2822 format
370
   * @param int The time as a UNIX timestamp
371
   * @param integer $date
372
   */
373
  public function setDate($date)
374
  {
375
    $this->headers->set("Date", date("r", $date));
376
  }
377
  /**
378
   * Get the date as it looks in the headers
379
   * @return integer
380
   */
381
  public function getDate()
382
  {
383
    return strtotime($this->headers->get("Date"));
384
  }
385
  /**
386
   * Set the charset of the document
387
   * @param string The charset used
388
   */
389
  public function setCharset($charset)
390
  {
391
    $this->headers->setAttribute("Content-Type", "charset", $charset);
392 View Code Duplication
    if (($this->getEncoding() == "7bit") && (strtolower($charset) == "utf-8" || strtolower($charset) == "utf8")) $this->setEncoding("8bit");
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
393
  }
394
  /**
395
   * Get the charset used in the document
396
   * Returns null if none is set
397
   * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
398
   */
399
  public function getCharset()
400
  {
401
    if ($this->headers->hasAttribute("Content-Type", "charset"))
402
    {
403
      return $this->headers->getAttribute("Content-Type", "charset");
404
    }
405
    else
406
    {
407
      return null;
408
    }
409
  }
410
  /**
411
   * Set the "format" attribute to flowed
412
   * @param boolean On or Off
413
   */
414
  public function setFlowed($flowed=true)
415
  {
416
    $value = null;
417
    if ($flowed) $value = "flowed";
418
    $this->headers->setAttribute("Content-Type", "format", $value);
419
  }
420
  /**
421
   * Check if the message format is set as flowed
422
   * @return boolean
423
   */
424 View Code Duplication
  public function isFlowed()
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...
425
  {
426
    if ($this->headers->hasAttribute("Content-Type", "format")
0 ignored issues
show
Coding Style introduced by
The if-else statement can be simplified to return $this->headers->h... 'format') == 'flowed';.
Loading history...
427
      && $this->headers->getAttribute("Content-Type", "format") == "flowed")
428
    {
429
      return true;
430
    }
431
    else return false;
432
  }
433
  /**
434
   * Set the message prioirty in the mail client (don't rely on this)
435
   * @param int The priority as a value between 1 (high) and 5 (low)
436
   */
437
  public function setPriority($priority)
438
  {
439
    $priority = (int) $priority;
440
    if ($priority > self::PRIORITY_LOW) $priority = self::PRIORITY_LOW;
441
    if ($priority < self::PRIORITY_HIGH) $priority = self::PRIORITY_HIGH;
442
    $label = array(1 => "High", 2 => "High", 3 => "Normal", 4 => "Low", 5 => "Low");
443
    $this->headers->set("X-Priority", $priority);
444
    $this->headers->set("X-MSMail-Priority", $label[$priority]);
445
    $this->headers->set("X-MimeOLE", "Produced by SwiftMailer " . $this->libVersion);
446
  }
447
  /**
448
   * Request that the client send back a read-receipt (don't rely on this!)
449
   * @param string Request address
450
   */
451
  public function requestReadReceipt($request)
452
  {
453
    if ($request instanceof Swift_Address) $request = $request->build();
454
    if (!$request)
455
    {
456
      $this->headers->set("Disposition-Notification-To", null);
457
      $this->headers->set("X-Confirm-Reading-To", null);
458
      $this->headers->set("Return-Receipt-To", null);
459
    }
460
    else
461
    {
462
      $this->headers->set("Disposition-Notification-To", $request);
463
      $this->headers->set("X-Confirm-Reading-To", $request);
464
      $this->headers->set("Return-Receipt-To", $request);
465
    }
466
  }
467
  /**
468
   * Check if a read receipt has been requested for this message
469
   * @return boolean
470
   */
471
  public function wantsReadReceipt()
472
  {
473
    return $this->headers->has("Disposition-Notification-To");
474
  }
475
  /**
476
   * Get the current message priority
477
   * Returns NULL if none set
478
   * @return string|null
479
   */
480
  public function getPriority()
481
  {
482
    if ($this->headers->has("X-Priority")) return $this->headers->get("X-Priority");
483
    else return null;
484
  }
485
  /**
486
   * Alias for setData()
487
   * @param mixed Body
488
   */
489
  public function setBody($body)
490
  {
491
    $this->setData($body);
492
  }
493
  /**
494
   * Alias for getData()
495
   * @return string The document body
496
   */
497
  public function getBody()
498
  {
499
    return $this->getData();
500
  }
501
  /**
502
   * Set the MIME warning message which is displayed to old clients
503
   * @var string The full warning message (in 7bit ascii)
504
   */
505
  public function setMimeWarning($text)
506
  {
507
    $this->mimeWarning = (string) $text;
508
  }
509
  /**
510
   * Get the MIME warning which is displayed to old clients
511
   * @return string
512
   */
513
  public function getMimeWarning()
514
  {
515
    return $this->mimeWarning;
516
  }
517
  /**
518
   * Attach a mime part or an attachment of some sort
519
   * Any descendant of Swift_Message_Mime can be added safely (including other Swift_Message objects for mail forwarding!!)
520
   * @param Swift_Message_Mime The document to attach
521
   * @param string An identifier to use (one is returned otherwise)
522
   * @return string The identifier for the part
523
   */
524
  public function attach(Swift_Message_Mime $child, $id=null)
525
  {
526
    try {
527
      switch ($child->getLevel())
528
      {
529 View Code Duplication
        case Swift_Message_Mime::LEVEL_ALTERNATIVE:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
530
          $sign = (strtolower($child->getContentType()) == "text/plain") ? -1 : 1;
531
          $id = $this->getReference("parent", "alternative")->addChild($child, $id, $sign);
532
          $this->setReference("alternative", $id, $child);
533
          break;
534 View Code Duplication
        case Swift_Message_Mime::LEVEL_RELATED:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
535
          $id = "cid:" . $child->getContentId();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Swift_Message_Mime as the method getContentId() does only exist in the following sub-classes of Swift_Message_Mime: Swift_Message_EmbeddedFile, Swift_Message_Image. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
536
          $id = $this->getReference("parent", "related")->addChild($child, $id, 1);
537
          $this->setReference("related", $id, $child);
538
          break;
539
        case Swift_Message_Mime::LEVEL_MIXED: default:
540
          $id = $this->getReference("parent", "mixed")->addChild($child, $id, 1);
541
          $this->setReference("mixed", $id, $child);
542
          break;
543
      }
544
      $this->postAttachFixStructure();
545
      $this->fixContentType();
546
      return $id;
547
    } catch (Swift_Message_MimeException $e) {
548
      throw new Swift_Message_MimeException("Something went wrong whilst trying to move some MIME parts during an attach(). " .
549
        "The MIME component threw an exception:<br />" . $e->getMessage());
550
    }
551
  }
552
  /**
553
   * Remove a nested MIME part
554
   * @param string The ID of the attached part
555
   * @throws Swift_Message_MimeException If no such part exists
556
   */
557
  public function detach($id)
558
  {
559
    try {
560
      switch (true)
561
      {
562 View Code Duplication
        case array_key_exists($id, $this->references["alternative"]):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
563
          $this->getReference("parent", "alternative")->removeChild($id);
564
          unset($this->references["alternative"][$id]);
565
          break;
566 View Code Duplication
        case array_key_exists($id, $this->references["related"]):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
567
          $this->getReference("parent", "related")->removeChild($id);
568
          unset($this->references["related"][$id]);
569
          break;
570 View Code Duplication
        case array_key_exists($id, $this->references["mixed"]):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
571
          $this->getReference("parent", "mixed")->removeChild($id);
572
          unset($this->references["mixed"][$id]);
573
          break;
574
        default:
575
          throw new Swift_Message_MimeException("Unable to detach part identified by ID '" . $id . "' since it's not registered.");
576
          break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
577
      }
578
      $this->postDetachFixStructure();
579
      $this->fixContentType();
580
    } catch (Swift_Message_MimeException $e) {
581
      throw new Swift_Message_MimeException("Something went wrong whilst trying to move some MIME parts during a detach(). " .
582
        "The MIME component threw an exception:<br />" . $e->getMessage());
583
    }
584
  }
585
  /**
586
   * Sets the correct content type header by looking at what types of data we have set
587
   */
588
  protected function fixContentType()
589
  {
590
    if (!empty($this->references["mixed"])) $this->setContentType("multipart/mixed");
591
    elseif (!empty($this->references["related"])) $this->setContentType("multipart/related");
592
    elseif (!empty($this->references["alternative"])) $this->setContentType("multipart/alternative");
593
  }
594
  /**
595
   * Move a branch of the tree, containing all it's MIME parts onto another branch
596
   * @param string The content type on the branch itself
597
   * @param string The content type which may exist in the branch's parent
598
   * @param array The array containing all the nodes presently
599
   * @param string The location of the branch now
600
   * @param string The location of the branch after moving
601
   * @param string The key to identify the branch by in it's new location
602
   * @param string $type
603
   * @param string|null $nested_type
604
   * @param string $old_branch
605
   * @param string $new_branch
606
   * @param string $tag
607
   */
608
  protected function moveBranchIn($type, $nested_type, $from, $old_branch, $new_branch, $tag)
609
  {
610
    $new = new Swift_Message_Part();
611
    $new->setContentType($type);
612
    $this->getReference("parent", $new_branch)->addChild($new, $tag, -1);
613
    
614
    switch ($new_branch)
615
    {
616
      case "related": $this->setReference("related", $tag, $new);//relatedRefs[$tag] = $new;
617
        break;
618
      case "mixed": $this->setReference("mixed", $tag, $new);//mixedRefs[$tag] = $new;
619
        break;
620
    }
621
    
622
    foreach ($from as $id => $ref)
623
    {
624
      if (!$ref) $ref = $this;
625
      $sign = (strtolower($ref->getContentType()) == "text/plain"
626
        || strtolower($ref->getContentType()) == $nested_type) ? -1 : 1;
627
      switch ($new_branch)
628
      {
629
        case "related": $this->getReference("related", $tag)->addChild($ref, $id, $sign);
630
          break;
631
        case "mixed": $this->getReference("mixed", $tag)->addChild($ref, $id, $sign);
632
          break;
633
      }
634
      $this->getReference("parent", $old_branch)->removeChild($id);
635
    }
636
    $this->setReference("parent", $old_branch, $new); //parentRefs[$old_branch] = $new;
637
  }
638
  /**
639
   * Analyzes the mixing of MIME types in a mulitpart message an re-arranges if needed
640
   * It looks complicated and long winded but the concept is pretty simple, even if putting it
641
   * in code does me make want to cry!
642
   */
643
  protected function postAttachFixStructure()
644
  {
645
    switch (true)
646
    {
647
      case (!empty($this->references["mixed"]) && !empty($this->references["related"]) && !empty($this->references["alternative"])):
648
        if (!isset($this->references["related"]["_alternative"]))
649
        {
650
          $this->moveBranchIn(
651
            "multipart/alternative", "multipart/alternative", $this->references["alternative"], "alternative", "related", "_alternative");
652
        }
653
        if (!isset($this->references["mixed"]["_related"]))
654
        {
655
          $this->moveBranchIn(
656
            "multipart/related", "multipart/alternative", $this->references["related"], "related", "mixed", "_related");
657
        }
658
        break;
659
      case (!empty($this->references["mixed"]) && !empty($this->references["related"])):
660
        if (!isset($this->references["mixed"]["_related"]))
661
        {
662
          $this->moveBranchIn(
663
            "multipart/related", "multipart/related", $this->references["related"], "related", "mixed", "_related");
664
        }
665
        break;
666 View Code Duplication
      case (!empty($this->references["mixed"]) && !empty($this->references["alternative"])):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
667
        if (!isset($this->references["mixed"]["_alternative"]))
668
        {
669
          $this->moveBranchIn(
670
            "multipart/alternative", null, $this->references["alternative"], "alternative", "mixed", "_alternative");
671
        }
672
        break;
673
      case (!empty($this->references["related"]) && !empty($this->references["alternative"])):
674
        if (!isset($this->references["related"]["_alternative"]))
675
        {
676
          $this->moveBranchIn(
677
            "multipart/alternative", "multipart/alternative", $this->references["alternative"], "alternative", "related", "_alternative");
678
        }
679
        break;
680
    }
681
  }
682
  /**
683
   * Move a branch further toward the top of the tree
684
   * @param array The array containing MIME parts from the old branch
685
   * @param string The name of the old branch
686
   * @param string The name of the new branch
687
   * @param string The key of the branch being moved
688
   * @param string $old_branch
689
   * @param string $new_branch
690
   * @param string $tag
691
   */
692
  protected function moveBranchOut($from, $old_branch, $new_branch, $tag)
693
  {
694
    foreach ($from as $id => $ref)
695
    {
696
      if (!$ref) $ref = $this;
697
      $sign = (strtolower($ref->getContentType()) == "text/html"
698
        || strtolower($ref->getContentType()) == "multipart/alternative") ? -1 : 1;
699
      $this->getReference("parent", $new_branch)->addChild($ref, $id, $sign);
700
      switch ($new_branch)
701
      {
702
        case "related": $this->getReference("related", $tag)->removeChild($id);
703
          break;
704
        case "mixed": $this->getReference("parent", $old_branch)->removeChild($id);
705
          break;
706
      }
707
    }
708
    $this->getReference("parent", $new_branch)->removeChild($tag);
709
    $mixed = $this->getReference("parent", $new_branch);//parentRefs[$new_branch];
710
    $this->setReference("parent", $old_branch, $mixed);//parentRefs[$old_branch] = $mixed;
711
    switch ($new_branch)
712
    {
713
      case "related": unset($this->references["related"][$tag]);
714
        break;
715
      case "mixed": unset($this->references["mixed"][$tag]);
716
        break;
717
    }
718
  }
719
  /**
720
   * Analyzes the mixing of MIME types in a mulitpart message an re-arranges if needed
721
   * It looks complicated and long winded but the concept is pretty simple, even if putting it
722
   * in code does me make want to cry!
723
   */
724
  protected function postDetachFixStructure()
725
  {
726
    switch (true)
727
    {
728
      case (!empty($this->references["mixed"]) && !empty($this->references["related"]) && !empty($this->references["alternative"])):
729
        if (array_keys($this->references["related"]) == array("_alternative"))
730
        {
731
          $alt = $this->getReference("parent", "related")->getChild("_alternative");
732
          $this->getReference("parent", "mixed")->addChild($alt, "_alternative", -1);
733
          $this->setReference("mixed", "_alternative", $alt);//mixedRefs["_alternative"] = $alt;
734
          $this->getReference("parent", "related")->removeChild("_alternative");
735
          unset($this->references["related"]["_alternative"]);
736
          $this->getReference("parent", "mixed")->removeChild("_related");
737
          unset($this->references["mixed"]["_related"]);
738
        }
739 View Code Duplication
        if (array_keys($this->references["mixed"]) == array("_related"))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
740
        {
741
          $this->moveBranchOut($this->references["related"], "related", "mixed", "_related");
742
        }
743
        break;
744
      case (!empty($this->references["mixed"]) && !empty($this->references["related"])):
745 View Code Duplication
        if (array_keys($this->references["mixed"]) == array("_related"))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
746
        {
747
          $this->moveBranchOut($this->references["related"], "related", "mixed", "_related");
748
        }
749
        if (isset($this->references["related"]["_alternative"]))
750
        {
751
          $this->detach("_alternative");
752
        }
753
        break;
754 View Code Duplication
      case (!empty($this->references["mixed"]) && !empty($this->references["alternative"])):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
755
        if (array_keys($this->references["mixed"]) == array("_alternative"))
756
        {
757
          $this->moveBranchOut($this->references["alternative"], "alternative", "mixed", "_alternative");
758
        }
759
        break;
760 View Code Duplication
      case (!empty($this->references["related"]) && !empty($this->references["alternative"])):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
761
        if (array_keys($this->references["related"]) == array("_alternative"))
762
        {
763
          $this->moveBranchOut($this->references["alternative"], "alternative", "related", "_alternative");
764
        }
765
        break;
766
      case (!empty($this->references["mixed"])):
767
        if (isset($this->references["mixed"]["_related"])) $this->detach("_related");
768
      case (!empty($this->references["related"])):
769
        if (isset($this->references["related"]["_alternative"]) || isset($this->references["mixed"]["_alternative"]))
770
          $this->detach("_alternative");
771
        break;
772
    }
773
  }
774
  /**
775
   * Execute needed logic prior to compilation
776
   */
777
  public function preBuild()
778
  {
779
    $data = $this->getData();
780
    if (!($enc = $this->getEncoding()))
781
    {
782
      $this->setEncoding("8bit");
783
    }
784
    if ($this->getCharset() === null && !$this->numChildren())
785
    {
786
      Swift_ClassLoader::load("Swift_Message_Encoder");
787 View Code Duplication
      if (is_string($data) && Swift_Message_Encoder::instance()->isUTF8($data))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
788
      {
789
        $this->setCharset("utf-8");
790
      }
791
      elseif(is_string($data) && Swift_Message_Encoder::instance()->is7BitAscii($data))
792
      {
793
        $this->setCharset("us-ascii");
794
        if (!$enc) $this->setEncoding("7bit");
0 ignored issues
show
Bug Best Practice introduced by
The expression $enc of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
795
      }
796
      else $this->setCharset("iso-8859-1");
797
    }
798
    elseif ($this->numChildren())
799
    {
800
      if (!$this->getData())
801
      {
802
        $this->setData($this->getMimeWarning());
803
        $this->setLineWrap(76);
804
      }
805
      
806
      if ($this->getCharset() !== null) $this->setCharset(null);
807
      if ($this->isFlowed()) $this->setFlowed(false);
808
      $this->setEncoding("7bit");
809
    }
810
  }
811
}
812