EasySwift   F
last analyzed

Complexity

Total Complexity 131

Size/Duplication

Total Lines 921
Duplicated Lines 10.75 %

Coupling/Cohesion

Components 1
Dependencies 18

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 99
loc 921
rs 1.0434
wmc 131
lcom 1
cbo 18

60 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 2
A setError() 0 4 1
A getErrors() 0 4 1
A getLastError() 0 4 1
A flushErrors() 0 5 1
A autoFlush() 0 4 1
A setMaxLogSize() 0 5 1
A useLogging() 0 6 2
A useAutoLineResizing() 0 4 1
A getTransactions() 0 4 1
A dumpLog() 0 5 1
A useExactCopy() 0 4 1
A newMessage() 0 7 2
A flushParts() 15 15 3
A flushAttachments() 15 15 3
A flushHeaders() 0 4 1
A newRecipientList() 0 5 2
A hasFailed() 0 4 1
A isConnected() 0 4 2
A connect() 14 14 3
A handshake() 0 4 1
A close() 13 13 3
A command() 0 12 3
A loadPlugin() 0 7 2
A getPlugin() 0 9 2
A removePlugin() 0 9 2
A loadAuthenticator() 0 8 2
A authenticate() 0 14 3
B stringToAddress() 0 22 4
A setHeaderEncoding() 0 11 4
A setReturnPath() 0 4 1
A requestReadReceipt() 0 4 1
A setPriority() 0 4 1
A getReturnPath() 0 8 2
A setReplyTo() 0 4 1
A getReplyTo() 0 8 2
A addTo() 0 4 1
A getToAddresses() 0 4 1
A flushTo() 0 4 1
A addCc() 0 4 1
A getCcAddresses() 0 4 1
A flushCc() 0 4 1
A addBcc() 0 4 1
A getBccAddresses() 0 4 1
A flushBcc() 0 4 1
C addRecipients() 0 38 8
A flush() 0 5 1
A getFailedRecipients() 0 5 1
A setMimeWarning() 0 4 1
A getMimeWarning() 0 4 1
A setCharset() 0 10 2
A getCharset() 0 4 1
A addPart() 0 21 4
B addAttachment() 0 25 5
C addImage() 14 38 7
C embedFile() 28 38 7
B addHeaders() 0 32 6
A setHeader() 0 4 1
A setHeaderAttribute() 0 5 2
D send() 0 27 10

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

1
<?php
2
3
/**
4
 * EasySwift: Swift Mailer Facade
5
 * Please read the LICENSE file
6
 * @author Chris Corbyn <[email protected]>
7
 * @package EasySwift
8
 * @version 1.0.3
9
 * @license GNU Lesser General Public License
10
 */
11
12
require_once dirname(__FILE__) . "/Swift/ClassLoader.php";
13
Swift_ClassLoader::load("Swift");
14
Swift_ClassLoader::load("Swift_Connection_SMTP");
15
Swift_ClassLoader::load("Swift_Connection_Sendmail");
16
17
//Some constants for backwards compatibility with v2 code
18
if (!defined("SWIFT_TLS")) define("SWIFT_TLS", Swift_Connection_SMTP::ENC_TLS);
19
if (!defined("SWIFT_SSL")) define("SWIFT_SSL", Swift_Connection_SMTP::ENC_SSL);
20
if (!defined("SWIFT_OPEN")) define("SWIFT_OPEN", Swift_Connection_SMTP::ENC_OFF);
21
if (!defined("SWIFT_SECURE_PORT")) define("SWIFT_SECURE_PORT", Swift_Connection_SMTP::PORT_SECURE);
22
if (!defined("SWIFT_DEFAULT_PORT")) define("SWIFT_DEFAULT_PORT", Swift_Connection_SMTP::PORT_DEFAULT);
23
24
/**
25
 * EasySwift: Facade for Swift Mailer Version 3.
26
 * Provides (most of) the API from older versions of Swift, wrapped around the new version 3 API.
27
 * Due to the popularity of the new API, EasySwift will not be around indefinitely.
28
 * @package EasySwift
29
 * @author Chris Corbyn <[email protected]>
30
 * @deprecated
31
 */
32
class EasySwift
33
{
34
  /**
35
   * The instance of Swift this class wrappers
36
   * @var Swift
37
   */
38
  public $swift = null;
39
  /**
40
   * This value becomes set to true when Swift fails
41
   * @var boolean
42
   */
43
  public $failed = false;
44
  /**
45
   * The number of loaded plugins
46
   * @var int
47
   */
48
  protected $pluginCount = 0;
49
  /**
50
   * An instance of Swift_Message
51
   * @var Swift_Message
52
   */
53
  public $message = null;
54
  /**
55
   * An address list to send to (Cc, Bcc, To..)
56
   * @var Swift_RecipientList
57
   */
58
  public $recipients = null;
59
  /**
60
   * If all recipients should get the same copy of the message, including headers
61
   * This is already implied if any Cc or Bcc recipients are set
62
   * @var boolean
63
   */
64
  protected $exactCopy = false;
65
  /**
66
   * If EasySwift should get rid of the message and recipients once it's done sending
67
   * @var boolean
68
   */
69
  protected $autoFlush = true;
70
  /**
71
   * A list of the IDs of all parts added to the message
72
   * @var array
73
   */
74
  protected $partIds = array();
75
  /**
76
   * A list of all the IDs of the attachments add to the message
77
   * @var array
78
   */
79
  protected $attachmentIds = array();
80
  /**
81
   * The last response received from the server
82
   * @var string
83
   */
84
  public $lastResponse = "";
85
  /**
86
   * The 3 digit code in the last response received from the server
87
   * @var int
88
   */
89
  public $responseCode = 0;
90
  /**
91
   * The list of errors handled at runtime
92
   * @var array
93
   */
94
  public $errors = array();
95
  /**
96
   * The last error received
97
   * @var string
98
   */
99
  public $lastError = null;
100
  
101
  /**
102
   * Constructor
103
   * @param Swift_Connection The connection to use
104
   * @param string The domain name of this server (not the SMTP server)
105
   */
106
  public function __construct(Swift_Connection $connection, $domain=null)
107
  {
108
    try {
109
      $this->swift = new Swift($connection, $domain, Swift::ENABLE_LOGGING);
110
      Swift_ClassLoader::load("Swift_Plugin_EasySwiftResponseTracker");
111
      $this->swift->attachPlugin(new Swift_Plugin_EasySwiftResponseTracker($this), "_ResponseTracker");
112
    } catch (Swift_ConnectionException $e) {
113
      $this->failed = true;
114
      $this->setError("The connection failed to start.  An exception was thrown:<br />" . $e->getMessage());
115
    }
116
    $this->newMessage();
117
    $this->newRecipientList();
118
  }
119
  /**
120
   * Set an error message
121
   * @param string Error message
122
   * @param string $msg
123
   */
124
  public function setError($msg)
125
  {
126
    $this->errors[] = ($this->lastError = $msg);
127
  }
128
  /**
129
   * Get the full list of errors
130
   * @return array
131
   */
132
  public function getErrors()
133
  {
134
    return $this->errors;
135
  }
136
  /**
137
   * Get the last error that occured
138
   * @return string
139
   */
140
  public function getLastError()
141
  {
142
    return $this->lastError;
143
  }
144
  /**
145
   * Clear the current list of errors
146
   */
147
  public function flushErrors()
148
  {
149
    $this->errors = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $errors.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
150
    $this->errors = array();
151
  }
152
  /**
153
   * Turn automatic flsuhing on or off.
154
   * This in ON by deault.  It removes the message and all parts after sending.
155
   * @param boolean
156
   */
157
  public function autoFlush($flush=true)
158
  {
159
    $this->autoFlush = $flush;
160
  }
161
  /**
162
   * Set the maximum size of the log
163
   * @param int
164
   */
165
  public function setMaxLogSize($size)
166
  {
167
    $log = Swift_LogContainer::getLog();
168
    $log->setMaxSize($size);
169
  }
170
  /**
171
   * Turn logging on or off (saves memory)
172
   * @param boolean
173
   */
174
  public function useLogging($use=true)
175
  {
176
    $log = Swift_LogContainer::getLog();
177
    if ($use) $log->setLogLevel(Swift_Log::LOG_NETWORK);
178
    else $log->setLogLevel(Swift_Log::LOG_NOTHING);
179
  }
180
  /**
181
   * Enable line resizing (on 1000 by default)
182
   * @param int The number of characters allowed on a line
183
   */
184
  public function useAutoLineResizing($size=1000)
185
  {
186
    $this->message->setLineWrap($size);
187
  }
188
  /**
189
   * Dump the log contents
190
   * @deprecated
191
   */
192
  public function getTransactions()
193
  {
194
    return $this->dumpLog();
195
  }
196
  /**
197
   * Dump the contents of the log to the browser
198
   * The log contains some &lt; and &gt; characters so you may need to view source
199
   * Note that this method dumps data to the browser, it does NOT return anything.
200
   */
201
  public function dumpLog()
202
  {
203
    $log = Swift_LogContainer::getLog();
204
    $log->dump();
205
  }
206
  /**
207
   * This method should be called if you do not wish to send messages in batch mode (i.e. if all recipients should see each others' addresses)
208
   * @param boolean If this mode should be used
209
   */
210
  public function useExactCopy($bool=true)
211
  {
212
    $this->exactCopy = $bool;
213
  }
214
  /**
215
   * Reset the current message and start a fresh one
216
   */
217
  public function newMessage($msg=false)
218
  {
219
    if (!$msg) $msg = new Swift_Message();
220
    $this->message = $msg;
0 ignored issues
show
Documentation Bug introduced by
It seems like $msg can also be of type boolean. However, the property $message is declared as type object<Swift_Message>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
221
    $this->partIds = array();
222
    $this->attachmentIds = array();
223
  }
224
  /**
225
   * Clear out all message parts
226
   * @return boolean
227
   */
228 View Code Duplication
  public function flushParts()
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...
229
  {
230
    $success = true;
231
    foreach ($this->partIds as $id)
232
    {
233
      try {
234
        $this->message->detach($id);
235
      } catch (Swift_Message_MimeException $e) {
236
        $success = false;
237
        $this->setError("A MIME part failed to detach due to the error:<br />" . $e->getMessage());
238
      }
239
    }
240
    $this->partIds = array();
241
    return $success;
242
  }
243
  /**
244
   * Clear out all attachments
245
   * @return boolean
246
   */
247 View Code Duplication
  public function flushAttachments()
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...
248
  {
249
    $success = true;
250
    foreach ($this->attachmentIds as $id)
251
    {
252
      try {
253
        $this->message->detach($id);
254
      } catch (Swift_Message_MimeException $e) {
255
        $success = false;
256
        $this->setError("An attachment failed to detach due to the error:<br />" . $e->getMessage());
257
      }
258
    }
259
    $this->attachmentIds = array();
260
    return $success;
261
  }
262
  /**
263
   * Clear out all message headers
264
   * @deprecated
265
   */
266
  public function flushHeaders()
267
  {
268
    $this->newMessage();
269
  }
270
  /**
271
   * Reset the current list of recipients and start a new one
272
   */
273
  public function newRecipientList($list=false)
274
  {
275
    if (!$list) $list = new Swift_RecipientList();
276
    $this->recipients = $list;
0 ignored issues
show
Documentation Bug introduced by
It seems like $list can also be of type boolean. However, the property $recipients is declared as type object<Swift_RecipientList>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
277
  }
278
  /**
279
   * Check if Swift has failed or not
280
   * This facade stops processing if so
281
   * @return boolean
282
   */
283
  public function hasFailed()
284
  {
285
    return $this->failed;
286
  }
287
  /**
288
   * Check if the current connection is open or not
289
   * @return boolean
290
   */
291
  public function isConnected()
292
  {
293
    return (($this->swift !== null) && $this->swift->connection->isAlive());
294
  }
295
  /**
296
   * Connect to the MTA if not already connected
297
   */
298 View Code Duplication
  public function connect()
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...
299
  {
300
    if (!$this->isConnected())
301
    {
302
      try {
303
        $this->swift->connect();
304
        return true;
305
      } catch (Swift_ConnectionException $e) {
306
        $this->failed = true;
307
        $this->setError("Swift failed to run the connection process:<br />" . $e->getMessage());
308
      }
309
    }
310
    return false;
311
  }
312
  /**
313
   * Perform the SMTP greeting process (don't do this unless you understand why you're doing it)
314
   */
315
  public function handshake()
316
  {
317
    $this->swift->handshake();
0 ignored issues
show
Bug introduced by
The method handshake() cannot be called from this context as it is declared protected in class Swift.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
Bug introduced by
The call to handshake() misses a required argument $greeting.

This check looks for function calls that miss required arguments.

Loading history...
318
  }
319
  /**
320
   * Close the connection to the MTA
321
   * @return boolean
322
   */
323 View Code Duplication
  public function close()
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...
324
  {
325
    if ($this->isConnected())
326
    {
327
      try {
328
        $this->swift->disconnect();
329
        return true;
330
      } catch (Swift_ConnectionException $e) {
331
        $this->setError("Disconnect failed:<br />" . $e->getMessage());
332
      }
333
    }
334
    return false;
335
  }
336
  /**
337
   * Send a command to Swift and get a response
338
   * @param string The command to send (leave of CRLF)
339
   * @return string
340
   */
341
  public function command($command)
342
  {
343
    if (substr($command, -2) == "\r\n") $command = substr($command, 0, -2);
344
    
345
    try {
346
      $rs = $this->swift->command($command);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $rs. 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...
347
      return $rs->getString();
348
    } catch (Swift_ConnectionException $e) {
349
      $this->setError("Command failed:<br />" . $e->getMessage());
350
      return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by EasySwift::command of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
351
    }
352
  }
353
  /**
354
   * Add a new plugin to respond to events
355
   * @param Swift_Events_Listener The plugin to load
356
   * @param string The ID to identify the plugin by if needed
357
   * @return string The ID of the plugin
358
   */
359
  public function loadPlugin(Swift_Events_Listener $plugin, $name=null)
360
  {
361
    $this->pluginCount++;
362
    if (!$name) $name = "p" . $this->pluginCount;
363
    $this->swift->attachPlugin($plugin, $name);
364
    return $name;
365
  }
366
  /**
367
   * Get a reference to the plugin identified by $name
368
   * @param string the ID of the plugin
369
   * @return Swift_Event_Listener|null
370
   */
371
  public function getPlugin($name)
372
  {
373
    try {
374
      $plugin = $this->swift->getPlugin($name);
375
      return $plugin;
376
    } catch (Exception $e) {
377
      return null;
378
    }
379
  }
380
  /**
381
   * Remove the plugin identified by $name
382
   * @param string The ID of the plugin
383
   * @return boolean
384
   */
385
  public function removePlugin($name)
386
  {
387
    try {
388
      $this->swift->removePlugin($name);
389
      return true;
390
    } catch (Exception $e) {
391
      return false;
392
    }
393
  }
394
  /**
395
   * Load in a new authentication mechanism for SMTP
396
   * This needn't be called since Swift will locate any available in Swift/Authenticator/*.php
397
   * @param Swift_Authenticator The authentication mechanism to load
398
   * @throws Exception If the wrong connection is used
399
   */
400
  public function loadAuthenticator(Swift_Authenticator $auth)
401
  {
402
    if (method_exists($this->swift->connection, "attachAuthenticator"))
403
    {
404
      $this->swift->connection->attachAuthenticator($auth);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Swift_Connection as the method attachAuthenticator() does only exist in the following implementations of said interface: Swift_Connection_SMTP.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
405
    }
406
    else throw new Exception("SMTP authentication cannot be used with connection class '" . get_class($this->connection) . "'. Swift_Connection_SMTP is needed");
0 ignored issues
show
Bug introduced by
The property connection does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
407
  }
408
  /**
409
   * Authenticate with SMTP authentication
410
   * @param string The SMTP username
411
   * @param string The SMTP password
412
   * @return boolean
413
   * @throws Exception If the wrong connection is used
414
   */
415
  public function authenticate($username, $password)
416
  {
417
    if (method_exists($this->swift->connection, "runAuthenticators"))
418
    {
419
      try {
420
        $this->swift->connection->runAuthenticators($username, $password, $this->swift);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Swift_Connection as the method runAuthenticators() does only exist in the following implementations of said interface: Swift_Connection_SMTP.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
421
        return true;
422
      } catch (Swift_ConnectionException $e) {
423
        $this->setError("Authentication failed:<br />" . $e->getMessage());
424
        return false;
425
      }
426
    }
427
    else throw new Exception("SMTP authentication cannot be used with connection class '" . get_class($this->connection) . "'. Swift_Connection_SMTP is needed");
428
  }
429
  /**
430
   * Turn a string representation of an email address into a Swift_Address object
431
   * @paramm string The email address
432
   * @param string $string
433
   * @return Swift_Address
434
   */
435
  public function stringToAddress($string)
436
  {
437
    $name = null;
438
    $address = null;
0 ignored issues
show
Unused Code introduced by
$address is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
439
    // Foo Bar <foo@bar>
440
    // or: "Foo Bar" <foo@bar>
441
    // or: <foo@bar>
442
    Swift_ClassLoader::load("Swift_Message_Encoder");
443
    if (preg_match("/^\\s*(\"?)(.*?)\\1 *<(" . Swift_Message_Encoder::CHEAP_ADDRESS_RE . ")>\\s*\$/", $string, $matches))
444
    {
445
      if (!empty($matches[2])) $name = $matches[2];
446
      $address = $matches[3];
447
    }
448
    elseif (preg_match("/^\\s*" . Swift_Message_Encoder::CHEAP_ADDRESS_RE . "\\s*\$/", $string))
449
    {
450
      $address = trim($string);
451
    }
452
    else return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by EasySwift::stringToAddress of type Swift_Address.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
453
    
454
    $swift_address = new Swift_Address($address, $name);
455
    return $swift_address;
456
  }
457
  /**
458
   * Set the encoding used in the message header
459
   * The encoding can be one of Q (quoted-printable) or B (base64)
460
   * @param string The encoding to use
461
   */
462
  public function setHeaderEncoding($mode="B")
463
  {
464
    switch (strtoupper($mode))
465
    {
466
      case "Q": case "QP": case "QUOTED-PRINTABLE":
467
        $this->message->headers->setEncoding("Q");
468
        break;
469
      default:
470
        $this->message->headers->setEncoding("B");
471
    }
472
  }
473
  /**
474
   * Set the return path address (where bounces go to)
475
   * @param mixed The address as a string or Swift_Address
476
   */
477
  public function setReturnPath($address)
478
  {
479
    return $this->message->setReturnPath($address);
480
  }
481
  /**
482
   * Request for a read recipient to be sent to the reply-to address
483
   * @param boolean
484
   */
485
  public function requestReadReceipt($request=true)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
486
  {
487
    //$this->message->requestReadReceipt(true);
488
  }
489
  /**
490
   * Set the message priority
491
   * This is an integer between 1 (high) and 5 (low)
492
   * @param int The level of priority to use
493
   */
494
  public function setPriority($priority)
495
  {
496
    $this->message->setPriority($priority);
497
  }
498
  /**
499
   * Get the return-path address as a string
500
   * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null|false?

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...
501
   */
502
  public function getReturnPath()
503
  {
504
    try {
505
      return $this->message->getReturnPath();
506
    } catch (Swift_Message_MimeException $e) {
507
      return false;
508
    }
509
  }
510
  /**
511
   * Set the reply-to header
512
   * @param mixed The address replies come to. String, or Swift_Address, or an array of either.
513
   */
514
  public function setReplyTo($address)
515
  {
516
    return $this->message->setReplyTo($address);
517
  }
518
  /**
519
   * Get the reply-to address(es) as an array of strings
520
   * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null|false? 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...
521
   */
522
  public function getReplyTo()
523
  {
524
    try {
525
      return $this->message->getReplyTo();
526
    } catch (Swift_Message_MimeException $e) {
527
      return false;
528
    }
529
  }
530
  /**
531
   * Add To: recipients to the email
532
   * @param mixed To address(es)
533
   * @return boolean
534
   */
535
  public function addTo($address)
536
  {
537
    return $this->addRecipients($address, "To");
538
  }
539
  /**
540
   * Get an array of To addresses
541
   * This currently returns an array of Swift_Address objects and may be simplified to an array of strings in later versions
542
   * @return array
543
   */
544
  public function getToAddresses()
545
  {
546
    return $this->recipients->getTo();
547
  }
548
  /**
549
   * Clear out all To: recipients
550
   */
551
  public function flushTo()
552
  {
553
    $this->recipients->flushTo();
554
  }
555
  /**
556
   * Add Cc: recipients to the email
557
   * @param mixed Cc address(es)
558
   * @return boolean
559
   */
560
  public function addCc($address)
561
  {
562
    return $this->addRecipients($address, "Cc");
563
  }
564
  /**
565
   * Get an array of Cc addresses
566
   * This currently returns an array of Swift_Address objects and may be simplified to an array of strings in later versions
567
   * @return array
568
   */
569
  public function getCcAddresses()
570
  {
571
    return $this->recipients->getCc();
572
  }
573
  /**
574
   * Clear out all Cc: recipients
575
   */
576
  public function flushCc()
577
  {
578
    $this->recipients->flushCc();
579
  }
580
  /**
581
   * Add Bcc: recipients to the email
582
   * @param mixed Bcc address(es)
583
   * @return boolean
584
   */
585
  public function addBcc($address)
586
  {
587
    return $this->addRecipients($address, "Bcc");
588
  }
589
  /**
590
   * Get an array of Bcc addresses
591
   * This currently returns an array of Swift_Address objects and may be simplified to an array of strings in later versions
592
   * @return array
593
   */
594
  public function getBccAddresses()
595
  {
596
    return $this->recipients->getBcc();
597
  }
598
  /**
599
   * Clear out all Bcc: recipients
600
   */
601
  public function flushBcc()
602
  {
603
    $this->recipients->flushBcc();
604
  }
605
  /**
606
   * Add recipients to the email
607
   * @param mixed Address(es)
608
   * @param string Recipient type (To, Cc, Bcc)
609
   * @param string $type
610
   * @return boolean
611
   */
612
  protected function addRecipients($address, $type)
613
  {
614
    if (!in_array($type, array("To", "Cc", "Bcc"))) return false;
615
    $method = "add" . $type;
616
    
617
    if ($address instanceof Swift_Address)
618
    {
619
      $this->recipients->$method($address);
620
      return true;
621
    }
622
    else
623
    {
624
      $added = 0;
625
      foreach ((array)$address as $addr)
626
      {
627
        if (is_array($addr))
628
        {
629
          $addr = array_values($addr);
630
          if (count($addr) >= 2)
631
          {
632
            $this->recipients->$method($addr[0], $addr[1]);
633
            $added++;
634
            continue;
635
          }
636
          elseif (count($addr) == 1) $addr = $addr[0];
637
          else continue;
638
        }
639
        
640
        if (is_string($addr))
641
        {
642
          $addr = $this->stringToAddress($addr);
643
          $this->recipients->$method($addr);
644
          $added++;
645
        }
646
      }
647
      return ($added > 0);
648
    }
649
  }
650
  /**
651
   * Flush message, recipients and headers
652
   */
653
  public function flush()
654
  {
655
    $this->newMessage();
656
    $this->newRecipientList();
657
  }
658
  /**
659
   * Get a list of any addresses which have failed since instantiation
660
   * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<integer|string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
661
   */
662
  public function getFailedRecipients()
663
  {
664
    $log = Swift_LogContainer::getLog();
665
    return $log->getFailedRecipients();
666
  }
667
  /**
668
   * Set the multipart MIME warning message (only seen by old clients)
669
   * @param string The message to show
670
   */
671
  public function setMimeWarning($text)
672
  {
673
    $this->message->setMimeWarning($text);
674
  }
675
  /**
676
   * Get the currently set MIME warning (seen by old clients)
677
   * @return string
678
   */
679
  public function getMimeWarning()
680
  {
681
    return $this->message->getMimeWarning();
682
  }
683
  /**
684
   * Set the charset of the charset to use in the message
685
   * @param string The charset (e.g. utf-8, iso-8859-1 etc)
686
   * @return boolean
687
   */
688
  public function setCharset($charset)
689
  {
690
    try {
691
      $this->message->setCharset($charset);
692
      return true;
693
    } catch (Swift_Message_MimeException $e) {
694
      $this->setError("Unable to set the message charset:<br />" . $e->getMessage());
695
      return false;
696
    }
697
  }
698
  /**
699
   * Get the charset of the charset to use in the message
700
   * @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...
701
   */
702
  public function getCharset()
703
  {
704
    return $this->message->getCharset();
705
  }
706
  /**
707
   * Add a new MIME part to the message
708
   * @param mixed The part to add.  If this is a string it's used as the body.  If it's an instance of Swift_Message_Part it's used as the entire part
709
   * @param string Content-type, default text/plain
710
   * @param string The encoding used (default is to let Swift decide)
711
   * @param string The charset to use (default is to let swift decide)
712
   */
713
  public function addPart($body, $type="text/plain", $encoding=null, $charset=null)
714
  {
715
    if ($body instanceof Swift_Message_Mime)
716
    {
717
      try {
718
        $this->partIds[] = $this->message->attach($body);
719
      } catch (Swift_Message_MimeException $e) {
720
        $this->setError("A MIME part failed to attach:<br />" . $e->getMessage());
721
        return false;
722
      }
723
    }
724
    else
725
    {
726
      try {
727
        $this->partIds[] = $this->message->attach(new Swift_Message_Part($body, $type, $encoding, $charset));
728
      } catch (Swift_Message_MimeException $e) {
729
        $this->setError("A MIME part failed to attach:<br />" . $e->getMessage());
730
        return false;
731
      }
732
    }
733
  }
734
  /**
735
   * Add a new attachment to the message
736
   * @param mixed The attachment to add.  If this is a string it's used as the file contents.  If it's an instance of Swift_Message_Attachment it's used as the entire part.  If it's an instance of Swift_File it's used as the contents.
737
   * @param string Filename, optional
738
   * @param string Content-type. Default application/octet-stream
739
   * @param string The encoding used (default is base64)
740
   * @return boolean
741
   */
742
  public function addAttachment($data, $filename=null, $type="application/octet-stream", $encoding=null)
743
  {
744
    if ($data instanceof Swift_Message_Mime)
745
    {
746
      try {
747
        $this->attachmentIds[] = $this->message->attach($data);
748
      } catch (Swift_Message_MimeException $e) {
749
        $this->setError("An attachment failed to attach:<br />" . $e->getMessage());
750
        return false;
751
      }
752
    }
753
    else
754
    {
755
      try {
756
        $this->attachmentIds[] = $this->message->attach(new Swift_Message_Attachment($data, $filename, $type, $encoding));
757
      } catch (Swift_Message_MimeException $e) {
758
        $this->setError("An attachment failed to attach<br />" . $e->getMessage());
759
        return false;
760
      } catch (Swift_FileException $e) {
761
        $this->setError("An attachment failed to attach:<br />" . $e->getMessage());
762
        return false;
763
      }
764
    }
765
    return true;
766
  }
767
  /**
768
   * Embed an image into the message and get the src attribute for HTML
769
   * Returns FALSE on failure
770
   * @param mixed The path to the image, a Swift_Message_Image object or a Swift_File object
771
   * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|false?

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...
772
   */
773
  public function addImage($input)
774
  {
775
    $ret = false;
776
    if ($input instanceof Swift_Message_Image)
777
    {
778
      $ret = $this->message->attach($input);
779
      $this->attachmentIds[] = $ret;
780
      return $ret;
781
    }
782 View Code Duplication
    elseif ($input instanceof Swift_File)
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...
783
    {
784
      try {
785
        $ret = $this->message->attach(new Swift_Message_Image($input));
786
        $this->attachmentIds[] = $ret;
787
        return $ret;
788
      } catch (Swift_Message_MimeException $e) {
789
        $this->setError("An attachment failed to attach:<br />" . $e->getMessage());
790
        return false;
791
      } catch (Swift_FileException $e) {
792
        $this->setError("An attachment failed to attach:<br />" . $e->getMessage());
793
        return false;
794
      }
795
    }
796
    else
797
    {
798
      try {
799
        $ret = $this->message->attach(new Swift_Message_Image(new Swift_File($input)));
800
        $this->attachmentIds[] = $ret;
801
        return $ret;
802
      } catch (Swift_Message_MimeException $e) {
803
        $this->setError("An attachment failed to attach:<br />" . $e->getMessage());
804
        return false;
805
      } catch (Swift_FileException $e) {
806
        $this->setError("An attachment failed to attach:<br />" . $e->getMessage());
807
        return false;
808
      }
809
    }
810
  }
811
  /**
812
   * Embed an inline file into the message, such as a Image or MIDI file
813
   * @param mixed The file contents, Swift_File object or Swift_Message_EmbeddedFile object
814
   * @param string The content-type of the file, optional
815
   * @param string The filename to use, optional
816
   * @param string the Content-ID to use, optional
817
   * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|false?

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...
818
   */
819
  public function embedFile($data, $type="application/octet-stream", $filename=null, $cid=null)
820
  {
821
    $ret = false;
822
    if ($data instanceof Swift_Message_EmbeddedFile)
823
    {
824
      $ret = $this->message->attach($data);
825
      $this->attachmentIds[] = $ret;
826
      return $ret;
827
    }
828 View Code Duplication
    elseif ($data instanceof Swift_File)
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...
829
    {
830
      try {
831
        $ret = $this->message->attach(new Swift_Message_EmbeddedFile($data, $filename, $type, $cid));
832
        $this->attachmentIds[] = $ret;
833
        return $ret;
834
      } catch (Swift_Message_MimeException $e) {
835
        $this->setError("An attachment failed to attach:<br />" . $e->getMessage());
836
        return false;
837
      } catch (Swift_FileException $e) {
838
        $this->setError("An attachment failed to attach:<br />" . $e->getMessage());
839
        return false;
840
      }
841
    }
842 View Code Duplication
    else
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...
843
    {
844
      try {
845
        $ret = $this->message->attach(new Swift_Message_EmbeddedFile($data, $filename, $type, $cid));
846
        $this->attachmentIds[] = $ret;
847
        return $ret;
848
      } catch (Swift_Message_MimeException $e) {
849
        $this->setError("An attachment failed to attach:<br />" . $e->getMessage());
850
        return false;
851
      } catch (Swift_FileException $e) {
852
        $this->setError("An attachment failed to attach:<br />" . $e->getMessage());
853
        return false;
854
      }
855
    }
856
  }
857
  /**
858
   * Add headers to the message
859
   * @param string The message headers to append, separated by CRLF
860
   * @deprecated
861
   */
862
  public function addHeaders($string)
863
  {
864
    //Split at the line ending only if it's not followed by LWSP (as in, a full header)
865
    $headers = preg_split("~\r?\n(?![ \t])~", $string);
866
    foreach ($headers as $header)
867
    {
868
      if (empty($header)) continue;
869
      //Get the bit before the colon
870
      $header_name = substr($header, 0, ($c_pos = strpos($header, ": ")));
871
      // ... and trim it away
872
      $header = substr($header, $c_pos+2);
873
      //Try splitting at "; " for attributes
874
      $attribute_pairs = preg_split("~\\s*;\\s+~", $header);
875
      //The value would always be right after the colon
876
      $header_value = $attribute_pairs[0];
877
      $this->message->headers->set($header_name, $header_value);
878
      unset($attribute_pairs[0]);
879
      foreach ($attribute_pairs as $pair)
880
      {
881
        //Now try finding the attribute name, and it's value (removing quotes)
882
        if (preg_match("~^(.*?)=(\"?)(.*?)\\2\\s*\$~", $pair, $matches))
883
        {
884
          try {
885
            $this->message->headers->setAttribute($header_name, $matches[1], $matches[3]);
886
          } catch (Swift_Message_MimeException $e) {
887
            $this->setError("There was a problem parsing or setting a header attribute:<br />" . $e->getMessage());
888
            //Ignored... it's EasySwift... C'mon ;)
889
          }
890
        }
891
      }
892
    }
893
  }
894
  /**
895
   * Set a header in the message
896
   * @param string The name of the header
897
   * @param string The value of the header (without attributes)
898
   * @see {addHeaderAttribute}
899
   */
900
  public function setHeader($name, $value)
901
  {
902
    $this->message->headers->set($name, $value);
903
  }
904
  /**
905
   * Set an attribute in the message headers
906
   * For example charset in Content-Type: text/html; charset=utf-8 set by $swift->setHeaderAttribute("Content-Type", "charset", "utf-8")
907
   * @param string The name of the header
908
   * @param string The name of the attribute
909
   * @param string The value of the attribute
910
   */
911
  public function setHeaderAttribute($name, $attribute, $value)
912
  {
913
    if ($this->message->headers->has($name))
914
      $this->message->headers->setAttribute($name, $attribute, $value);
915
  }
916
  /**
917
   * Send an email to a number of recipients
918
   * Returns the number of successful recipients, or FALSE on failure
919
   * @param mixed The recipients to send to.  One of string, array, 2-dimensional array or Swift_Address
920
   * @param mixed The address to send from. string or Swift_Address
921
   * @param string The message subject
922
   * @param string The message body, optional
923
   * @return int
0 ignored issues
show
Documentation introduced by
Should the return type not be false|integer?

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...
924
   */
925
  public function send($recipients, $from, $subject, $body=null)
926
  {
927
    $this->addTo($recipients);
928
    
929
    $sender = false;
930
    if (is_string($from)) $sender = $this->stringToAddress($from);
931
    elseif ($from instanceof Swift_Address) $sender = $from;
932
    if (!$sender) return false;
933
    
934
    $this->message->setSubject($subject);
935
    if ($body) $this->message->setBody($body);
936
    try {
937
      if (!$this->exactCopy && !$this->recipients->getCc() && !$this->recipients->getBcc())
938
      {
939
        $sent = $this->swift->batchSend($this->message, $this->recipients, $sender);
940
      }
941
      else
942
      {
943
        $sent = $this->swift->send($this->message, $this->recipients, $sender);
944
      }
945
      if ($this->autoFlush) $this->flush();
946
      return $sent;
947
    } catch (Swift_ConnectionException $e) {
948
      $this->setError("Sending failed:<br />" . $e->getMessage());
949
      return false;
950
    }
951
  }
952
}
953