Completed
Push — master ( 0c8fdc...7123ab )
by Roberto
03:03
created

Mail::renderTemplate()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 34
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 34
c 0
b 0
f 0
ccs 0
cts 34
cp 0
rs 8.8571
cc 1
eloc 30
nc 1
nop 8
crap 2

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace NFePHP\Mail;
4
5
/**
6
 * Class for sending emails related to SPED services
7
 *
8
 * @category  NFePHP
9
 * @package   NFePHP\Mail\Mail
10
 * @copyright NFePHP Copyright (c) 2016
11
 * @license   http://www.gnu.org/licenses/lgpl.txt LGPLv3+
12
 * @license   https://opensource.org/licenses/MIT MIT
13
 * @license   http://www.gnu.org/licenses/gpl.txt GPLv3+
14
 * @author    Roberto L. Machado <linux.rlm at gmail dot com>
15
 * @link      http://github.com/nfephp-org/sped-mail for the canonical source repository
16
 */
17
18
use stdClass;
19
use PHPMailer;
20
use NFePHP\Mail\Base;
21
use DOMDocument;
22
use InvalidArgumentException;
23
use RuntimeException;
24
25
class Mail extends Base
26
{
27
    /**
28
     * config
29
     * @var stdClass
30
     */
31
    protected $config;
32
    /**
33
     * template user-defined
34
     * @var string
35
     */
36
    protected $template;
37
    /**
38
     * Type from xml document NFe, CTe or CCe
39
     * @var string
40
     */
41
    protected $type;
42
    /**
43
     * Addresses to send mail
44
     * This array should be repeated fields removed
45
     * @var array
46
     */
47
    protected $addresses;
48
    /**
49
     * Fields from xml
50
     * @var stdClass
51
     */
52
    protected $fields;
53
    /**
54
     * Html Body mail message
55
     * @var string
56
     */
57
    protected $body;
58
    /**
59
     * Subject for email
60
     * @var string
61
     */
62
    protected $subject;
63
    /**
64
     * PHPMailer class
65
     * @var \PHPMailer
66
     */
67
    protected $mail;
68
    /**
69
     * Xml content
70
     * @var string
71
     */
72
    protected $xml;
73
    /**
74
     * PDF content
75
     * @var string
76
     */
77
    protected $pdf;
78
    
79
    /**
80
     * Constructor
81
     * @param \stdClass $config
82
     */
83
    public function __construct(stdClass $config, PHPMailer $mailer = null)
84
    {
85
        $this->mail = $mailer;
86
        if (is_null($mailer)) {
87
            $this->mail = new \PHPMailer();
88
        }
89
        $this->config = $config;
90
        $this->loadService($config);
91
        $this->fields = new stdClass();
92
        $this->fields->destinatario = '';
93
        $this->fields->data = '';
94
        $this->fields->numero = '';
95
        $this->fields->valor = 0;
96
        $this->fields->chave = '';
97
        $this->fields->data = '';
98
        $this->fields->correcao = '';
99
        $this->fields->conduso = '';
100
    }
101
    
102
    /**
103
     * Load parameters to PHPMailer class
104
     * @param stdClass $config
105
     */
106
    private function loadService(stdClass $config)
107
    {
108
        $this->mail->CharSet = 'UTF-8';
109
        $this->mail->isSMTP();
110
        $this->mail->Host = $config->host;
111
        $this->mail->SMTPAuth = true;
112
        $this->mail->Username = $config->user;
113
        $this->mail->Password = $config->password;
114
        $this->mail->SMTPSecure = $config->secure;
115
        $this->mail->Port = $config->port;
116
        $this->mail->setFrom($config->from, $config->fantasy);
117
        $this->mail->addReplyTo($config->replyTo, $config->replyName);
118
    }
119
    
120
    /**
121
     * Sets a template for body mail
122
     * If no template is passed, it will be used a standard template
123
     * see Base::class
124
     * @param string $htmlTemplate
125
     */
126
    public function setTemplate($htmlTemplate)
127
    {
128
        if ($htmlTemplate != '') {
129
            $this->template = $htmlTemplate;
130
        }
131
    }
132
    
133
    /**
134
     * Load the documents to send
135
     * XML document is required, but PDF is not
136
     * @param string $xml content or path NFe, CTe or CCe in XML
137
     * @param string $pdf content or path document from NFe, CTe or CCe
138
     */
139
    public function loadDocuments($xml, $pdf = '')
140
    {
141
        $this->xml = $xml;
142
        $this->pdf = $pdf;
143
        if (is_file($xml)) {
144
            $this->xml = file_get_contents($xml);
145
        }
146
        if (is_file($pdf)) {
147
            $this->pdf = file_get_contents($pdf);
148
        }
149
        //get xml data
150
        $this->getXmlData($this->xml);
151
    }
152
    
153
    /**
154
     * Search xml for data
155
     * @param string $xml
156
     * @throws InvalidArgumentException
157
     */
158
    private function getXmlData($xml)
159
    {
160
        $dom = new DOMDocument('1.0', 'UTF-8');
161
        $dom->preserveWhiteSpace = false;
162
        $dom->loadXML($xml);
163
        $root = $dom->documentElement;
164
        $name = $root->tagName;
165
        $destinatario = '';
0 ignored issues
show
Unused Code introduced by
$destinatario 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...
166
        $data = '';
0 ignored issues
show
Unused Code introduced by
$data 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...
167
        $numero = '';
0 ignored issues
show
Unused Code introduced by
$numero 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...
168
        $valor = 0;
0 ignored issues
show
Unused Code introduced by
$valor 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...
169
        $chave = '';
0 ignored issues
show
Unused Code introduced by
$chave 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...
170
        $correcao = '';
0 ignored issues
show
Unused Code introduced by
$correcao 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...
171
        $conduso = '';
0 ignored issues
show
Unused Code introduced by
$conduso 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...
172
        switch ($name) {
173
            case 'nfeProc':
174
            case 'NFe':
175
                $type = 'NFe';
176
                $this->fields->destinatario = $dom->getElementsByTagName('dest')->item(0)
177
                    ->getElementsByTagName('xNome')->item(0)->nodeValue;
178
                $this->fields->data = $dom->getElementsByTagName('ide')->item(0)
179
                    ->getElementsByTagName('dhEmi')->item(0)->nodeValue;
180
                $this->fields->numero = $dom->getElementsByTagName('ide')->item(0)
181
                     ->getElementsByTagName('nNF')->item(0)->nodeValue;
182
                $this->fields->valor = $dom->getElementsByTagName('vNF')->item(0)->nodeValue;
183
                $this->subject = "NFe n. ".$this->fields->numero." - ".$this->config->fantasy;
184
                break;
185
            case 'cteProc':
186
            case 'CTe':
187
                $type = 'CTe';
188
                $this->fields->destinatario = $dom->getElementsByTagName('dest')->item(0)
189
                    ->getElementsByTagName('xNome')->item(0)->nodeValue;
190
                $this->fields->data = $dom->getElementsByTagName('ide')->item(0)
191
                    ->getElementsByTagName('dhEmi')->item(0)->nodeValue;
192
                $this->fields->numero = $dom->getElementsByTagName('ide')->item(0)
193
                    ->getElementsByTagName('nCT')->item(0)->nodeValue;
194
                $this->fields->valor = $dom->getElementsByTagName('vRec')->item(0)->nodeValue;
195
                $this->subject = "CTe n. ".$this->fields->numero." - ".$this->config->fantasy;
196
                break;
197
            case 'procEventoNFe':
198
            case 'procEventoCTe':
199
                $type = 'CCe';
200
                $this->fields->chave = $dom->getElementsByTagName('chNFe')->item(0)->nodeValue;
201
                $this->fields->data = $dom->getElementsByTagName('dhEvento')->item(0)->nodeValue;
202
                $this->fields->correcao = $dom->getElementsByTagName('xCorrecao')->item(0)->nodeValue;
203
                $this->fields->conduso = $dom->getElementsByTagName('xCondUso')->item(0)->nodeValue;
204
                if (empty($this->fields->chave)) {
205
                    $this->fields->chave = $dom->getElementsByTagName('chCTe')->item(0)->nodeValue;
206
                }
207
                $this->subject = "Carta de Correção ". $this->config->fantasy;
208
                break;
209
            default:
210
                $type = '';
211
        }
212
        //get email adresses from xml, if exists
213
        //may have one address in <dest><email>
214
        $email = !empty($dom->getElementsByTagName('email')->item(0)->nodeValue) ?
215
            $dom->getElementsByTagName('email')->item(0)->nodeValue : '';
216
        if (! empty($mail)) {
0 ignored issues
show
Bug introduced by
The variable $mail seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
217
            $this->addresses[] = $email;
218
        }
219
        //may have others in <obsCont xCampo="email"><xTexto>[email protected]</xTexto>
220
        $obs = $dom->getElementsByTagName('obsCont');
221
        foreach ($obs as $ob) {
222
            if (strtoupper($ob->getAttribute('xCampo')) === 'EMAIL') {
223
                $this->addresses[] = $ob->getElementsByTagName('xTexto')->item(0)->nodeValue;
224
            }
225
        }
226
        //xml may be a NFe or a CTe or a CCe nothing else
227
        if ($type != 'NFe' && $type != 'CTe' && $type != 'CCe') {
228
            $msg = "Você deve passar apenas uma NFe ou um CTe ou um CCe. "
229
                    . "Esse documento não foi reconhecido.";
230
            throw new InvalidArgumentException($msg);
231
        }
232
        $this->type = $type;
233
    }
234
    
235
    /**
236
     * Render a template with valid data
237
     * @param string $template
238
     * @param string $destinatario
239
     * @param string $data
240
     * @param string $numero
241
     * @param string $valor
242
     * @param string $chave
243
     * @param string $correcao
244
     * @param string $conduso
245
     * @return string
246
     */
247
    private function renderTemplate(
248
        $template,
249
        $destinatario = '',
250
        $data = '',
251
        $numero = '',
252
        $valor = 0,
253
        $chave = '',
254
        $correcao = '',
255
        $conduso = ''
256
    ) {
257
        $dt = new \DateTime(str_replace('T', ' ', $data));
258
        $search = array(
259
            '{destinatario}',
260
            '{data}',
261
            '{numero}',
262
            '{valor}',
263
            '{emitente}',
264
            '{chave}',
265
            '{correcao}',
266
            '{conduso}'
267
        );
268
        $replace = array(
269
          $destinatario,
270
          $dt->format('d/m/Y'),
271
          $numero,
272
          number_format($valor, 2, ',', '.'),
273
          $this->config->fantasy,
274
          $chave,
275
          $correcao,
276
          $conduso
277
        );
278
        $template = str_replace($search, $replace, $template);
279
        return $template;
280
    }
281
    
282
    /**
283
     * Set all addresses including those that exists in the xml document
284
     * Send email only to listed addresses ignoring all email in xml
285
     * @param array $addresses
286
     */
287
    private function setAddresses(array $addresses = [])
288
    {
289
        if (!empty($addresses)) {
290
            $this->addresses = $addresses;
291
        }
292
    }
293
    
294
    /**
295
     * Send mail
296
     * If no parameter was passed, only the email address contained in
297
     * the xml will be used
298
     * @param array $addresses
299
     * @return boolean
300
     * @throws RuntimeException
301
     */
302
    public function send(array $addresses = [])
303
    {
304
        $this->setAddresses($addresses);
305
        //This resulted array should be repeated fields removed
306
        $this->addresses = array_unique($this->addresses);
307
        foreach ($this->addresses as $address) {
308
            $this->mail->addAddress($address);
309
        }
310
        //depending on the document a different template should be loaded
311
        //and having data patterns appropriately substituted
312
        $template = $this->templates[$this->type];
313
        if (! empty($this->template)) {
314
            $template = $this->template;
315
        }
316
        $this->body = $this->renderTemplate(
317
            $template,
318
            $this->fields->destinatario,
319
            $this->fields->data,
320
            $this->fields->numero,
321
            $this->fields->valor,
322
            $this->fields->chave,
323
            $this->fields->correcao,
324
            $this->fields->conduso
325
        );
326
        $this->mail->isHTML(true);
327
        $this->mail->Subject = $this->subject;
328
        $this->mail->Body = $this->body;
329
        $this->attach();
330
        if (!$this->mail->send()) {
331
            $msg = 'A menssagem não pode ser enviada. Error: ' . $mail->ErrorInfo;
0 ignored issues
show
Bug introduced by
The variable $mail does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
332
            throw new RuntimeException($msg);
333
        }
334
        $this->mail->ClearAllRecipients();
335
        $this->mail->ClearAttachments();
336
        return true;
337
    }
338
    
339
    /**
340
     * Attach all documents to message
341
     */
342
    private function attach()
343
    {
344
        $this->mail->addStringAttachment(
345
            $this->xml,
346
            $this->type . '.xml'
347
        );
348
        if (! empty($this->pdf)) {
349
            $this->mail->addStringAttachment(
350
                $this->xml,
351
                $this->type . '.pdf'
352
            );
353
        }
354
    }
355
    
356
    /**
357
     * Configure and send documents
358
     * @param stdClass $config
359
     * @param type $xml
360
     * @param type $pdf
361
     * @param array $addresses
362
     * @param type $htmltemplate
363
     * @param PHPMailer $mailer
364
     * @return \static
365
     */
366
    public static function sendMail(
367
        stdClass $config,
368
        $xml,
369
        $pdf = '',
370
        array $addresses = [],
371
        $htmltemplate = '',
372
        PHPMailer $mailer = null
373
    ) {
374
        $mail = new static($config, $mailer);
375
        $mail->loadDocuments($xml, $pdf);
376
        $mail->setTemplate($htmltemplate);
377
        $mail->send($addresses);
378
        return $mail;
379
    }
380
}
381