Passed
Push — master ( c1d1cf...f48ccd )
by Francimar
03:58
created

Envio   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 382
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 80.81%

Importance

Changes 0
Metric Value
wmc 51
lcom 1
cbo 4
dl 0
loc 382
ccs 139
cts 172
cp 0.8081
rs 8.3206
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getServico() 0 11 4
A setServico() 0 5 1
A getAmbiente() 0 13 4
A setAmbiente() 0 13 3
A getModelo() 0 13 4
A setModelo() 0 13 3
A getEmissao() 0 13 4
A setEmissao() 0 13 3
A getConteudo() 0 4 1
A setConteudo() 0 5 1
A getVersao() 0 8 3
A getServiceInfo() 0 17 2
A toArray() 0 10 1
C fromArray() 0 34 8
A getNodeHeader() 0 13 1
A getNode() 0 23 3
B envia() 0 25 4

How to fix   Complexity   

Complex Class

Complex classes like Envio 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 Envio, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * MIT License
4
 *
5
 * Copyright (c) 2016 MZ Desenvolvimento de Sistemas LTDA
6
 *
7
 * @author Francimar Alves <[email protected]>
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy
10
 * of this software and associated documentation files (the "Software"), to deal
11
 * in the Software without restriction, including without limitation the rights
12
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 * copies of the Software, and to permit persons to whom the Software is
14
 * furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in all
17
 * copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
 * SOFTWARE.
26
 *
27
 */
28
namespace NFe\Task;
29
30
use NFe\Core\Nota;
31
use NFe\Core\SEFAZ;
32
use NFe\Common\Node;
33
use NFe\Common\Util;
34
use NFe\Common\CurlSoap;
35
36
/**
37
 * Envia requisições para os servidores da SEFAZ
38
 */
39
class Envio
0 ignored issues
show
Complexity introduced by
This class has a complexity of 51 which exceeds the configured maximum of 50.

The class complexity is the sum of the complexity of all methods. A very high value is usually an indication that your class does not follow the single reponsibility principle and does more than one job.

Some resources for further reading:

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

Loading history...
40
{
41
42
    /**
43
     * Tipo de serviço a ser executado
44
     */
45
    const SERVICO_INUTILIZACAO = 'inutilizacao';
46
    const SERVICO_PROTOCOLO = 'protocolo';
47
    const SERVICO_STATUS = 'status';
48
    const SERVICO_CADASTRO = 'cadastro';
49
    const SERVICO_AUTORIZACAO = 'autorizacao';
50
    const SERVICO_RETORNO = 'retorno';
51
    const SERVICO_RECEPCAO = 'recepcao';
52
    const SERVICO_CONFIRMACAO = 'confirmacao';
53
    const SERVICO_EVENTO = 'evento';
54
    const SERVICO_DESTINADAS = 'destinadas';
55
    const SERVICO_DOWNLOAD = 'download';
56
    const SERVICO_DISTRIBUICAO = 'distribuicao';
57
58
    /**
59
     * Tipo de serviço a ser executado
60
     */
61
    private $servico;
62
    /**
63
     * Identificação do Ambiente:
64
     * 1 - Produção
65
     * 2 - Homologação
66
     */
67
    private $ambiente;
68
    /**
69
     * Código do modelo do Documento Fiscal. 55 = NF-e; 65 = NFC-e.
70
     */
71
    private $modelo;
72
    /**
73
     * Forma de emissão da NF-e
74
     */
75
    private $emissao;
76
    /**
77
     * Conteudo a ser enviado
78
     */
79
    private $conteudo;
80
81
    /**
82
     * Constroi uma instância de Envio vazia
83
     * @param  array $envio Array contendo dados do Envio
84
     */
85 21
    public function __construct($envio = array())
86
    {
87 21
        $this->fromArray($envio);
88 21
    }
89
90
    /**
91
     * Tipo de serviço a ser executado
92
     * @param boolean $normalize informa se o servico deve estar no formato do XML
93
     * @return mixed servico do Envio
94
     */
95 20
    public function getServico($normalize = false)
96
    {
97 20
        if (!$normalize) {
98 20
            return $this->servico;
99
        }
100 19
        $url = $this->getServiceInfo();
101 18
        if (is_array($url) && isset($url['servico'])) {
102 17
            return Nota::PORTAL.'/wsdl/'.$url['servico'];
103
        }
104 1
        throw new \Exception('A ação do serviço "'.$this->getServico().'" não foi configurada', 404);
105
    }
106
107
    /**
108
     * Altera o valor do Servico para o informado no parâmetro
109
     * @param mixed $servico novo valor para Servico
110
     * @return Envio A própria instância da classe
111
     */
112 21
    public function setServico($servico)
113
    {
114 21
        $this->servico = $servico;
115 21
        return $this;
116
    }
117
118
    /**
119
     * Identificação do Ambiente:
120
     * 1 - Produção
121
     * 2 - Homologação
122
     * @param boolean $normalize informa se o ambiente deve estar no formato do XML
123
     * @return mixed ambiente do Envio
124
     */
125 20
    public function getAmbiente($normalize = false)
126
    {
127 20
        if (!$normalize) {
128 20
            return $this->ambiente;
129
        }
130
        switch ($this->ambiente) {
131
            case Nota::AMBIENTE_PRODUCAO:
132
                return '1';
133
            case Nota::AMBIENTE_HOMOLOGACAO:
134
                return '2';
135
        }
136
        return $this->ambiente;
137
    }
138
139
    /**
140
     * Altera o valor do Ambiente para o informado no parâmetro
141
     * @param mixed $ambiente novo valor para Ambiente
142
     * @return Envio A própria instância da classe
143
     */
144 21
    public function setAmbiente($ambiente)
145
    {
146
        switch ($ambiente) {
147 21
            case '1':
148
                $ambiente = Nota::AMBIENTE_PRODUCAO;
149
                break;
150 21
            case '2':
151
                $ambiente = Nota::AMBIENTE_HOMOLOGACAO;
152
                break;
153
        }
154 21
        $this->ambiente = $ambiente;
155 21
        return $this;
156
    }
157
158
    /**
159
     * Código do modelo do Documento Fiscal. 55 = NF-e; 65 = NFC-e.
160
     * @param boolean $normalize informa se o modelo deve estar no formato do XML
161
     * @return mixed modelo do Envio
162
     */
163 20
    public function getModelo($normalize = false)
164
    {
165 20
        if (!$normalize) {
166 20
            return $this->modelo;
167
        }
168
        switch ($this->modelo) {
169
            case Nota::MODELO_NFE:
170
                return '55';
171
            case Nota::MODELO_NFCE:
172
                return '65';
173
        }
174
        return $this->modelo;
175
    }
176
177
    /**
178
     * Altera o valor do Modelo para o informado no parâmetro
179
     * @param mixed $modelo novo valor para Modelo
180
     * @return Envio A própria instância da classe
181
     */
182 21
    public function setModelo($modelo)
183
    {
184
        switch ($modelo) {
185 21
            case '55':
186
                $modelo = Nota::MODELO_NFE;
187
                break;
188 21
            case '65':
189
                $modelo = Nota::MODELO_NFCE;
190
                break;
191
        }
192 21
        $this->modelo = $modelo;
193 21
        return $this;
194
    }
195
196
    /**
197
     * Forma de emissão da NF-e
198
     * @param boolean $normalize informa se o emissao deve estar no formato do XML
199
     * @return mixed emissao do Envio
200
     */
201 20
    public function getEmissao($normalize = false)
202
    {
203 20
        if (!$normalize) {
204 20
            return $this->emissao;
205
        }
206
        switch ($this->emissao) {
207
            case Nota::EMISSAO_NORMAL:
208
                return '1';
209
            case Nota::EMISSAO_CONTINGENCIA:
210
                return '9';
211
        }
212
        return $this->emissao;
213
    }
214
215
    /**
216
     * Altera o valor do Emissao para o informado no parâmetro
217
     * @param mixed $emissao novo valor para Emissao
218
     * @return Envio A própria instância da classe
219
     */
220 21
    public function setEmissao($emissao)
221
    {
222
        switch ($emissao) {
223 21
            case '1':
224
                $emissao = Nota::EMISSAO_NORMAL;
225
                break;
226 21
            case '9':
227
                $emissao = Nota::EMISSAO_CONTINGENCIA;
228
                break;
229
        }
230 21
        $this->emissao = $emissao;
231 21
        return $this;
232
    }
233
234
    /**
235
     * Conteudo a ser enviado
236
     * @return mixed conteudo do Envio
237
     */
238 18
    public function getConteudo()
239
    {
240 18
        return $this->conteudo;
241
    }
242
243
    /**
244
     * Altera o valor do Conteudo para o informado no parâmetro
245
     * @param mixed $conteudo novo valor para Conteudo
246
     * @return Envio A própria instância da classe
247
     */
248 21
    public function setConteudo($conteudo)
249
    {
250 21
        $this->conteudo = $conteudo;
251 21
        return $this;
252
    }
253
254
    /**
255
     * Obtém a versão do serviço a ser utilizado
256
     * @return string Versão do serviço
257
     */
258 17
    public function getVersao()
259
    {
260 17
        $url = $this->getServiceInfo();
261 17
        if (is_array($url) && isset($url['versao'])) {
262 3
            return $url['versao'];
263
        }
264 14
        return Nota::VERSAO;
265
    }
266
267
    /**
268
     * Devolve um array com as informações de serviço (URL, Versão, Serviço)
269
     * @return array Informações de serviço
270
     */
271 20
    private function getServiceInfo()
272
    {
273 20
        $config = SEFAZ::getInstance()->getConfiguracao();
274 20
        $db = $config->getBanco();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $db. 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...
275 20
        $estado = $config->getEmitente()->getEndereco()->getMunicipio()->getEstado();
276 20
        $info = $db->getInformacaoServico(
277 20
            $this->getEmissao(),
278 20
            $estado->getUF(),
279 20
            $this->getModelo(),
280 20
            $this->getAmbiente()
281 20
        );
282 20
        if (!isset($info[$this->getServico()])) {
283 1
            throw new \Exception('O serviço "'.$this->getServico().
284 1
                '" não está disponível para o estado "'.$estado->getUF().'"', 404);
285
        }
286 19
        return $info[$this->getServico()];
287
    }
288
289
    /**
290
     * Converte a instância da classe para um array de campos com valores
291
     * @return array Array contendo todos os campos e valores da instância
292
     */
293 1
    public function toArray($recursive = false)
0 ignored issues
show
Unused Code introduced by
The parameter $recursive 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...
294
    {
295 1
        $envio = array();
296 1
        $envio['servico'] = $this->getServico();
297 1
        $envio['ambiente'] = $this->getAmbiente();
298 1
        $envio['modelo'] = $this->getModelo();
299 1
        $envio['emissao'] = $this->getEmissao();
300 1
        $envio['conteudo'] = $this->getConteudo();
301 1
        return $envio;
302
    }
303
304
    /**
305
     * Atribui os valores do array para a instância atual
306
     * @param mixed $envio Array ou instância de Envio, para copiar os valores
307
     * @return Envio A própria instância da classe
308
     */
309 21
    public function fromArray($envio = array())
310
    {
311 21
        if ($envio instanceof Envio) {
312 1
            $envio = $envio->toArray();
313 21
        } elseif (!is_array($envio)) {
314 1
            return $this;
315
        }
316 21
        if (isset($envio['servico'])) {
317 1
            $this->setServico($envio['servico']);
318 1
        } else {
319 21
            $this->setServico(null);
320
        }
321 21
        if (isset($envio['ambiente'])) {
322 1
            $this->setAmbiente($envio['ambiente']);
323 1
        } else {
324 21
            $this->setAmbiente(null);
325
        }
326 21
        if (isset($envio['modelo'])) {
327 1
            $this->setModelo($envio['modelo']);
328 1
        } else {
329 21
            $this->setModelo(null);
330
        }
331 21
        if (isset($envio['emissao'])) {
332 1
            $this->setEmissao($envio['emissao']);
333 1
        } else {
334 21
            $this->setEmissao(null);
335
        }
336 21
        if (isset($envio['conteudo'])) {
337 1
            $this->setConteudo($envio['conteudo']);
338 1
        } else {
339 21
            $this->setConteudo(null);
340
        }
341 21
        return $this;
342
    }
343
344
    /**
345
     * Obtém o nó do cabeçalho da requisição SOAP
346
     * @return DOMDocument Cabeçalho para adicionar na requisição
347
     */
348 17
    private function getNodeHeader()
349
    {
350 17
        $config = SEFAZ::getInstance()->getConfiguracao();
351 17
        $estado = $config->getEmitente()->getEndereco()->getMunicipio()->getEstado();
352 17
        $estado->checkCodigos();
353 17
        $doh = new \DOMDocument('1.0', 'UTF-8');
354 17
        $element = $doh->createElement('nfeCabecMsg');
355 17
        $element->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', $this->getServico(true));
356 17
        Util::appendNode($element, 'cUF', $estado->getCodigo(true));
357 17
        Util::appendNode($element, 'versaoDados', $this->getVersao());
358 17
        $doh->appendChild($element);
359 17
        return $doh;
360
    }
361
362
    /**
363
     * Cria um nó XML do envio de acordo com o leiaute da NFe
364
     * @param  string $name Nome do nó que será criado
365
     * @return DOMElement   Nó que contém todos os campos da classe
366
     */
367 17
    public function getNode($name = null)
368
    {
369 17
        $dom = new \DOMDocument('1.0', 'UTF-8');
370 17
        $element = $dom->createElement(is_null($name)?'nfeDadosMsg':$name);
371 17
        $element->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', $this->getServico(true));
372
        // Corrige xmlns:default
373
        // $data = $dom->importNode($this->getConteudo()->documentElement, true);
374
        // $element->appendChild($data);
375 17
        Util::appendNode($element, 'Conteudo', 0);
376
377 17
        $dom->appendChild($element);
378
379
        // Corrige xmlns:default
380
        // return $dom;
381 17
        if ($this->getConteudo() instanceof \DOMDocument) {
382 11
            $xml = $this->getConteudo()->saveXML($this->getConteudo()->documentElement);
383 11
        } else {
384 6
            $xml = $this->getConteudo();
385
        }
386 17
        $xml = str_replace('<Conteudo>0</Conteudo>', $xml, $dom->saveXML($dom->documentElement));
387 17
        $dom->loadXML($xml);
388 17
        return $dom;
389
    }
390
391
    /**
392
     * Envia o conteúdo para o serviço da SEFAZ informado
393
     * @return DOMDocument Documento XML da resposta da SEFAZ
394
     */
395 18
    public function envia()
396
    {
397 18
        $config = SEFAZ::getInstance()->getConfiguracao();
398 18
        $url = $this->getServiceInfo();
399 18
        if (is_array($url)) {
400 18
            $url = $url['url'];
401 18
        }
402 18
        if ($config->isOffline()) {
403 1
            throw new \NFe\Exception\NetworkException('Operação offline, sem conexão com a internet', 7);
404
        }
405 17
        $soap = new CurlSoap();
406 17
        $soap->setConnectTimeout(intval($config->getTempoLimite()));
407 17
        $soap->setTimeout(ceil($config->getTempoLimite() * 1.5));
408 17
        $soap->setCertificate($config->getArquivoChavePublica());
409 17
        $soap->setPrivateKey($config->getArquivoChavePrivada());
410 17
        $doh = $this->getNodeHeader();
411 17
        $dob = $this->getNode();
412
        try {
413 17
            $resp = $soap->send($url, $dob, $doh);
0 ignored issues
show
Documentation introduced by
$doh is of type object<DOMDocument>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
414 16
            return $resp;
415 1
        } catch (\NFe\Exception\NetworkException $e) {
416 1
            $config->setOffline(time());
417 1
            throw $e;
418
        }
419
    }
420
}
421