Completed
Push — master ( 3d6456...22dadb )
by Roberto
06:51 queued 03:34
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 DOMDocument;
20
use DateTime;
21
use InvalidArgumentException;
22
use RuntimeException;
23
use NFePHP\Mail\Base;
24
use PHPMailer;
25
use Html2Text\Html2Text;
26
27
class Mail extends Base
28
{
29
    /**
30
     * config
31
     * @var stdClass
32
     */
33
    protected $config;
34
    /**
35
     * template user-defined
36
     * @var string
37
     */
38
    protected $template;
39
    /**
40
     * Type from xml document NFe, CTe or CCe
41
     * @var string
42
     */
43
    protected $type;
44
    /**
45
     * Addresses to send mail
46
     * This array should be repeated fields removed
47
     * @var array
48
     */
49
    protected $addresses;
50
    /**
51
     * Fields from xml
52
     * @var stdClass
53
     */
54
    protected $fields;
55
    /**
56
     * Html Body mail message
57
     * @var string
58
     */
59
    protected $body;
60
    /**
61
     * Subject for email
62
     * @var string
63
     */
64
    protected $subject;
65
    /**
66
     * PHPMailer class
67
     * @var \PHPMailer
68
     */
69
    protected $mail;
70
    /**
71
     * Xml content
72
     * @var string
73
     */
74
    protected $xml;
75
    /**
76
     * PDF content
77
     * @var string
78
     */
79
    protected $pdf;
80
    
81
    /**
82
     * Constructor
83
     * @param \stdClass $config
84
     */
85
    public function __construct(stdClass $config, PHPMailer $mailer = null)
86
    {
87
        $this->mail = $mailer;
88
        if (is_null($mailer)) {
89
            $this->mail = new PHPMailer();
90
        }
91
        $this->config = $config;
92
        $this->loadService($config);
93
        $this->fields = new stdClass();
94
        $this->fields->destinatario = '';
95
        $this->fields->data = '';
96
        $this->fields->numero = '';
97
        $this->fields->valor = 0;
98
        $this->fields->chave = '';
99
        $this->fields->data = '';
100
        $this->fields->correcao = '';
101
        $this->fields->conduso = '';
102
    }
103
    
104
    /**
105
     * Load parameters to PHPMailer class
106
     * @param stdClass $config
107
     */
108
    protected function loadService(stdClass $config)
109
    {
110
        $this->mail->CharSet = 'UTF-8';
111
        $this->mail->isSMTP();
112
        $this->mail->Host = $config->host;
113
        $this->mail->SMTPAuth = true;
114
        $this->mail->Username = $config->user;
115
        $this->mail->Password = $config->password;
116
        $this->mail->SMTPSecure = $config->secure;
117
        $this->mail->Port = $config->port;
118
        $this->mail->setFrom($config->from, $config->fantasy);
119
        $this->mail->addReplyTo($config->replyTo, $config->replyName);
120
    }
121
    
122
    /**
123
     * Sets a template for body mail
124
     * If no template is passed, it will be used a standard template
125
     * see Base::class
126
     * @param string $htmlTemplate
127
     */
128
    public function setTemplate($htmlTemplate)
129
    {
130
        if ($htmlTemplate != '') {
131
            $this->template = $htmlTemplate;
132
        }
133
    }
134
    
135
    /**
136
     * Load the documents to send
137
     * XML document is required, but PDF is not
138
     * @param string $xml content or path NFe, CTe or CCe in XML
139
     * @param string $pdf content or path document from NFe, CTe or CCe
140
     */
141
    public function loadDocuments($xml, $pdf = '')
142
    {
143
        $this->xml = $xml;
144
        $this->pdf = $pdf;
145
        if (is_file($xml)) {
146
            $this->xml = file_get_contents($xml);
147
        }
148
        if (is_file($pdf)) {
149
            $this->pdf = file_get_contents($pdf);
150
        }
151
        //get xml data
152
        $this->getXmlData($this->xml);
153
    }
154
    
155
    /**
156
     * Search xml for data
157
     * @param string $xml
158
     * @throws InvalidArgumentException
159
     */
160
    protected function getXmlData($xml)
161
    {
162
        $dom = new DOMDocument('1.0', 'UTF-8');
163
        $dom->preserveWhiteSpace = false;
164
        $dom->loadXML($xml);
165
        $root = $dom->documentElement;
166
        $name = $root->tagName;
167
        switch ($name) {
168
            case 'nfeProc':
169
            case 'NFe':
170
                $type = 'NFe';
171
                $this->fields->destinatario = $dom->getElementsByTagName('dest')->item(0)
172
                    ->getElementsByTagName('xNome')->item(0)->nodeValue;
173
                $this->fields->data = $dom->getElementsByTagName('ide')->item(0)
174
                    ->getElementsByTagName('dhEmi')->item(0)->nodeValue;
175
                $this->fields->numero = $dom->getElementsByTagName('ide')->item(0)
176
                     ->getElementsByTagName('nNF')->item(0)->nodeValue;
177
                $this->fields->valor = $dom->getElementsByTagName('vNF')->item(0)->nodeValue;
178
                $this->subject = "NFe n. ".$this->fields->numero." - ".$this->config->fantasy;
179
                break;
180
            case 'cteProc':
181
            case 'CTe':
182
                $type = 'CTe';
183
                $this->fields->destinatario = $dom->getElementsByTagName('dest')->item(0)
184
                    ->getElementsByTagName('xNome')->item(0)->nodeValue;
185
                $this->fields->data = $dom->getElementsByTagName('ide')->item(0)
186
                    ->getElementsByTagName('dhEmi')->item(0)->nodeValue;
187
                $this->fields->numero = $dom->getElementsByTagName('ide')->item(0)
188
                    ->getElementsByTagName('nCT')->item(0)->nodeValue;
189
                $this->fields->valor = $dom->getElementsByTagName('vRec')->item(0)->nodeValue;
190
                $this->subject = "CTe n. ".$this->fields->numero." - ".$this->config->fantasy;
191
                break;
192
            case 'procEventoNFe':
193
            case 'procEventoCTe':
194
                $type = 'CCe';
195
                $this->fields->chave = $dom->getElementsByTagName('chNFe')->item(0)->nodeValue;
196
                $this->fields->data = $dom->getElementsByTagName('dhEvento')->item(0)->nodeValue;
197
                $this->fields->correcao = $dom->getElementsByTagName('xCorrecao')->item(0)->nodeValue;
198
                $this->fields->conduso = $dom->getElementsByTagName('xCondUso')->item(0)->nodeValue;
199
                if (empty($this->fields->chave)) {
200
                    $this->fields->chave = $dom->getElementsByTagName('chCTe')->item(0)->nodeValue;
201
                }
202
                $this->subject = "Carta de Correção ". $this->config->fantasy;
203
                break;
204
            default:
205
                $type = '';
206
        }
207
        //get email adresses from xml, if exists
208
        //may have one address in <dest><email>
209
        $email = !empty($dom->getElementsByTagName('email')->item(0)->nodeValue) ?
210
            $dom->getElementsByTagName('email')->item(0)->nodeValue : '';
211
        if (! empty($email)) {
212
            $this->addresses[] = $email;
213
        }
214
        //may have others in <obsCont xCampo="email"><xTexto>[email protected]</xTexto>
215
        $obs = $dom->getElementsByTagName('obsCont');
216
        foreach ($obs as $ob) {
217
            if (strtoupper($ob->getAttribute('xCampo')) === 'EMAIL') {
218
                $this->addresses[] = $ob->getElementsByTagName('xTexto')->item(0)->nodeValue;
219
            }
220
        }
221
        //xml may be a NFe or a CTe or a CCe nothing else
222
        if ($type != 'NFe' && $type != 'CTe' && $type != 'CCe') {
223
            $msg = "Você deve passar apenas uma NFe ou um CTe ou um CCe. "
224
                    . "Esse documento não foi reconhecido.";
225
            throw new InvalidArgumentException($msg);
226
        }
227
        $this->type = $type;
228
    }
229
    
230
    /**
231
     * Render a template with valid data
232
     * @param string $template
233
     * @param string $destinatario
234
     * @param string $data
235
     * @param string $numero
236
     * @param string $valor
237
     * @param string $chave
238
     * @param string $correcao
239
     * @param string $conduso
240
     * @return string
241
     */
242
    protected function renderTemplate(
243
        $template,
244
        $destinatario = '',
245
        $data = '',
246
        $numero = '',
247
        $valor = 0,
248
        $chave = '',
249
        $correcao = '',
250
        $conduso = ''
251
    ) {
252
        $dt = new \DateTime(str_replace('T', ' ', $data));
253
        $search = array(
254
            '{destinatario}',
255
            '{data}',
256
            '{numero}',
257
            '{valor}',
258
            '{emitente}',
259
            '{chave}',
260
            '{correcao}',
261
            '{conduso}'
262
        );
263
        $replace = array(
264
          $destinatario,
265
          $dt->format('d/m/Y'),
266
          $numero,
267
          number_format($valor, 2, ',', '.'),
268
          $this->config->fantasy,
269
          $chave,
270
          $correcao,
271
          $conduso
272
        );
273
        $template = str_replace($search, $replace, $template);
274
        return $template;
275
    }
276
    
277
    /**
278
     * Set all addresses including those that exists in the xml document
279
     * Send email only to listed addresses ignoring all email addresses in xml
280
     * @param array $addresses
281
     */
282
    protected function setAddresses(array $addresses = [])
283
    {
284
        if (!empty($addresses)) {
285
            $this->addresses = $addresses;
286
        }
287
        $this->removeInvalidAdresses();
288
    }
289
    
290
    /**
291
     * Send mail
292
     * If no parameter was passed, only the email address contained in
293
     * the xml will be used
294
     * @param array $addresses
295
     * @return boolean
296
     * @throws RuntimeException
297
     */
298
    public function send(array $addresses = [])
299
    {
300
        $this->setAddresses($addresses);
301
        if (empty($this->addresses)) {
302
            $msg = 'Não foram passados endereços de email validos !!';
303
            throw new RuntimeException($msg);
304
        }
305
        foreach ($this->addresses as $address) {
306
            $this->mail->addAddress($address);
307
        }
308
        $body = $this->render();
309
        $this->mail->isHTML(true);
310
        $this->mail->Subject = $this->subject;
311
        $this->mail->Body = $body;
312
        $this->mail->AltBody = Html2Text::convert($body);
313
        $this->attach();
314
        if (!$this->mail->send()) {
315
            $msg = 'A mensagem não pode ser enviada. Mail Error: ' . $this->mail->ErrorInfo;
316
            throw new RuntimeException($msg);
317
        }
318
        $this->mail->ClearAllRecipients();
319
        $this->mail->ClearAttachments();
320
        return true;
321
    }
322
    
323
    /**
324
     * Remove all invalid addresses
325
     */
326
    protected function removeInvalidAdresses()
327
    {
328
        //This resulted array should be repeated fields removed
329
        //and all not valid strings, and also trim and strtolower strings
330
        $this->addresses = array_unique($this->addresses);
331
        $this->addresses = array_map(array($this, 'clearAddressString'), $this->addresses);
332
        $this->addresses = array_filter($this->addresses, array($this, 'checkEmailAddress'));
333
    }
334
    
335
    /**
336
     * Build Message
337
     * @return string
338
     */
339
    protected function render()
340
    {
341
        //depending on the document a different template should be loaded
342
        //and having data patterns appropriately substituted
343
        $template = $this->templates[$this->type];
344
        if (! empty($this->template)) {
345
            $template = $this->template;
346
        }
347
        return $this->renderTemplate(
348
            $template,
349
            $this->fields->destinatario,
350
            $this->fields->data,
351
            $this->fields->numero,
352
            $this->fields->valor,
353
            $this->fields->chave,
354
            $this->fields->correcao,
355
            $this->fields->conduso
356
        );
357
    }
358
    
359
    /**
360
     * Attach all documents to message
361
     */
362
    protected function attach()
363
    {
364
        $this->mail->addStringAttachment(
365
            $this->xml,
366
            $this->type . '.xml'
367
        );
368
        if (! empty($this->pdf)) {
369
            $this->mail->addStringAttachment(
370
                $this->xml,
371
                $this->type . '.pdf'
372
            );
373
        }
374
    }
375
    
376
    /**
377
     * Configure and send documents
378
     * @param stdClass $config
379
     * @param type $xml
380
     * @param type $pdf
381
     * @param array $addresses
382
     * @param type $htmltemplate
383
     * @param PHPMailer $mailer
384
     * @return \static
385
     */
386
    public static function sendMail(
387
        stdClass $config,
388
        $xml,
389
        $pdf = '',
390
        array $addresses = [],
391
        $htmltemplate = '',
392
        PHPMailer $mailer = null
393
    ) {
394
        $mail = new static($config, $mailer);
395
        $mail->loadDocuments($xml, $pdf);
396
        $mail->setTemplate($htmltemplate);
397
        $mail->send($addresses);
398
        return $mail;
399
    }
400
}
401