Passed
Push — master ( 66516d...d151be )
by
unknown
55s queued 10s
created

Tools::signCTe()   B

Complexity

Conditions 10
Paths 32

Size

Total Lines 58

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
dl 0
loc 58
ccs 0
cts 50
cp 0
rs 7.0496
c 0
b 0
f 0
cc 10
nc 32
nop 1
crap 110

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace NFePHP\CTe\Common;
4
5
/**
6
 * Class base responsible for communication with SEFAZ
7
 *
8
 * @category  NFePHP
9
 * @package   NFePHP\CTe\Common\Tools
10
 * @copyright NFePHP Copyright (c) 2008-2017
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-nfe for the canonical source repository
16
 */
17
18
use DOMDocument;
19
use InvalidArgumentException;
20
use NFePHP\Common\Certificate;
21
use NFePHP\Common\Signer;
22
use NFePHP\Common\Soap\SoapCurl;
23
use NFePHP\Common\Soap\SoapInterface;
24
use NFePHP\Common\Strings;
25
use NFePHP\Common\TimeZoneByUF;
26
use NFePHP\Common\UFList;
27
use NFePHP\Common\Validator;
28
use NFePHP\CTe\Factories\Contingency;
29
use NFePHP\CTe\Factories\ContingencyCTe;
30
use NFePHP\CTe\Factories\Header;
31
use NFePHP\CTe\Factories\QRCode;
32
use RuntimeException;
33
34
class Tools
35
{
36
    /**
37
     * config class
38
     * @var \stdClass
39
     */
40
    public $config;
41
    /**
42
     * Path to storage folder
43
     * @var string
44
     */
45
    public $pathwsfiles = '';
46
    /**
47
     * Path to schemes folder
48
     * @var string
49
     */
50
    public $pathschemes = '';
51
    /**
52
     * ambiente
53
     * @var string
54
     */
55
    public $ambiente = 'homologacao';
56
    /**
57
     * Environment
58
     * @var int
59
     */
60
    public $tpAmb = 2;
61
    /**
62
     * contingency class
63
     * @var Contingency
64
     */
65
    public $contingency;
66
    /**
67
     * soap class
68
     * @var SoapInterface
69
     */
70
    public $soap;
71
    /**
72
     * Application version
73
     * @var string
74
     */
75
    public $verAplic = '';
76
    /**
77
     * last soap request
78
     * @var string
79
     */
80
    public $lastRequest = '';
81
    /**
82
     * last soap response
83
     * @var string
84
     */
85
    public $lastResponse = '';
86
    /**
87
     * certificate class
88
     * @var Certificate
89
     */
90
    protected $certificate;
91
    /**
92
     * Sign algorithm from OPENSSL
93
     * @var int
94
     */
95
    protected $algorithm = OPENSSL_ALGO_SHA1;
96
    /**
97
     * Canonical conversion options
98
     * @var array
99
     */
100
    protected $canonical = [true, false, null, null];
101
    /**
102
     * Model of CTe 57 or 67
103
     * @var int
104
     */
105
    protected $modelo = 57;
106
    /**
107
     * Version of layout
108
     * @var string
109
     */
110
    protected $versao = '3.00';
111
    /**
112
     * urlPortal
113
     * Instância do WebService
114
     *
115
     * @var string
116
     */
117
    protected $urlPortal = 'http://www.portalfiscal.inf.br/cte';
118
    /**
119
     * urlcUF
120
     * @var string
121
     */
122
    protected $urlcUF = '';
123
    /**
124
     * urlVersion
125
     * @var string
126
     */
127
    protected $urlVersion = '';
128
    /**
129
     * urlService
130
     * @var string
131
     */
132
    protected $urlService = '';
133
    /**
134
     * @var string
135
     */
136
    protected $urlMethod = '';
137
    /**
138
     * @var string
139
     */
140
    protected $urlOperation = '';
141
    /**
142
     * @var string
143
     */
144
    protected $urlNamespace = '';
145
    /**
146
     * @var string
147
     */
148
    protected $urlAction = '';
149
    /**
150
     * @var \SOAPHeader
151
     */
152
    protected $objHeader;
153
    /**
154
     * @var string
155
     */
156
    protected $urlHeader = '';
157
    /**
158
     * @var array
159
     */
160
    protected $soapnamespaces = [
161
        'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
162
        'xmlns:xsd' => "http://www.w3.org/2001/XMLSchema",
163
        'xmlns:soap' => "http://www.w3.org/2003/05/soap-envelope"
164
    ];
165
    /**
166
     * @var array
167
     */
168
    protected $availableVersions = [
169
        '3.00' => 'PL_CTe_300a'
170
    ];
171
172
    /**
173
     * Constructor
174
     * load configurations,
175
     * load Digital Certificate,
176
     * map all paths,
177
     * set timezone and
178
     * and instanciate Contingency::class
179
     * @param string $configJson content of config in json format
180
     * @param Certificate $certificate
181
     */
182
    public function __construct($configJson, Certificate $certificate)
183
    {
184
        $this->config = json_decode($configJson);
185
        $this->pathwsfiles = realpath(
186
            __DIR__ . '/../../storage'
187
        ) . '/';
188
        $this->version($this->config->versao);
189
        $this->setEnvironmentTimeZone($this->config->siglaUF);
190
        $this->certificate = $certificate;
191
        $this->setEnvironment($this->config->tpAmb);
192
        $this->contingency = new Contingency();
193
    }
194
195
    /**
196
     * Sets environment time zone
197
     * @param string $acronym (ou seja a sigla do estado)
198
     * @return void
199
     */
200
    public function setEnvironmentTimeZone($acronym)
201
    {
202
        date_default_timezone_set(TimeZoneByUF::get($acronym));
203
    }
204
205
    /**
206
     * Set application version
207
     * @param string $ver
208
     */
209
    public function setVerAplic($ver)
210
    {
211
        $this->verAplic = $ver;
212
    }
213
214
    /**
215
     * Load Soap Class
216
     * Soap Class may be \NFePHP\Common\Soap\SoapNative
217
     * or \NFePHP\Common\Soap\SoapCurl
218
     * @param SoapInterface $soap
219
     * @return void
220
     */
221
    public function loadSoapClass(SoapInterface $soap)
222
    {
223
        $this->soap = $soap;
224
        $this->soap->loadCertificate($this->certificate);
225
    }
226
227
    /**
228
     * Set OPENSSL Algorithm using OPENSSL constants
229
     * @param int $algorithm
230
     * @return void
231
     */
232
    public function setSignAlgorithm($algorithm = OPENSSL_ALGO_SHA1)
233
    {
234
        $this->algorithm = $algorithm;
235
    }
236
237
    /**
238
     * Set or get model of document CTe = 57 or CTeOS = 67
239
     * @param int $model
240
     * @return int modelo class parameter
241
     */
242
    public function model($model = null)
243
    {
244
        if ($model == 57 || $model == 67) {
245
            $this->modelo = $model;
246
        }
247
        return $this->modelo;
248
    }
249
250
    /**
251
     * Set or get parameter layout version
252
     * @param string $version
253
     * @return string
254
     * @throws InvalidArgumentException
255
     */
256
    public function version($version = '')
257
    {
258
        if (!empty($version)) {
259
            if (!array_key_exists($version, $this->availableVersions)) {
260
                throw new \InvalidArgumentException('Essa versão de layout não está disponível');
261
            }
262
            $this->versao = $version;
263
            $this->config->schemes = $this->availableVersions[$version];
264
            $this->pathschemes = realpath(
265
                __DIR__ . '/../../schemes/' . $this->config->schemes
266
            ) . '/';
267
        }
268
        return $this->versao;
269
    }
270
271
    /**
272
     * Recover cUF number from state acronym
273
     * @param string $acronym Sigla do estado
274
     * @return int number cUF
275
     */
276
    public function getcUF($acronym)
277
    {
278
        return UFlist::getCodeByUF($acronym);
279
    }
280
281
    /**
282
     * Recover state acronym from cUF number
283
     * @param int $cUF
284
     * @return string acronym sigla
285
     */
286
    public function getAcronym($cUF)
287
    {
288
        return UFlist::getUFByCode($cUF);
289
    }
290
291
    /**
292
     * Validate cUF from the key content and returns the state acronym
293
     * @param string $chave
294
     * @return string
295
     * @throws InvalidArgumentException
296
     */
297
    public function validKeyByUF($chave)
298
    {
299
        $uf = $this->config->siglaUF;
300
        if ($uf != UFList::getUFByCode(substr($chave, 0, 2))) {
301
            throw new \InvalidArgumentException(
302
                "A chave do CTe indicado [$chave] não pertence a [$uf]."
303
            );
304
        }
305
        return $uf;
306
    }
307
308
    /**
309
     * Sign CTe
310
     * @param  string $xml CTe xml content
311
     * @return string singed CTe xml
312
     * @throws RuntimeException
313
     */
314
    public function signCTe($xml)
315
    {
316
        //remove all invalid strings
317
        $xml = Strings::clearXmlString($xml);
318
        $signed = Signer::sign(
319
            $this->certificate,
320
            $xml,
321
            'infCte',
322
            'Id',
323
            $this->algorithm,
324
            $this->canonical
325
        );
326
        $dom = new DOMDocument('1.0', 'UTF-8');
327
        $dom->preserveWhiteSpace = false;
328
        $dom->formatOutput = false;
329
        $dom->loadXML($signed);
330
        //exception will be throw if CTe is not valid
331
        $modelo = $dom->getElementsByTagName('mod')->item(0)->nodeValue;
332
        $method = 'cte';
333
        if ($modelo == 67) {
334
            $method = 'cteOS';
335
        }
336
        $isInfCTeSupl = !empty($dom->getElementsByTagName('infCTeSupl')->item(0));
337
        if (!$isInfCTeSupl) {
338
            $signed = $this->addQRCode($dom);
339
        }
340
        $this->isValid($this->versao, $signed, $method);
341
        $modal = (int) $dom->getElementsByTagName('modal')->item(0)->nodeValue;
342
        if ($modelo != 67) {
343
            switch ($modal) {
344
                case 1:
345
                    //Rodoviário
346
                    $this->isValid($this->versao, $this->getModalXML($dom, 'rodo'), $method . 'ModalRodoviario');
0 ignored issues
show
Documentation introduced by
$dom 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...
347
                    break;
348
                case 2:
349
                    //Aéreo
350
                    $this->isValid($this->versao, $this->getModalXML($dom, 'aereo'), $method . 'ModalAereo');
0 ignored issues
show
Documentation introduced by
$dom 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...
351
                    break;
352
                case 3:
353
                    //Aquaviário
354
                    $this->isValid($this->versao, $this->getModalXML($dom, 'aquav'), $method . 'ModalAquaviario');
0 ignored issues
show
Documentation introduced by
$dom 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...
355
                    break;
356
                case 4:
357
                    //Ferroviário
358
                    $this->isValid($this->versao, $this->getModalXML($dom, 'ferrov'), $method . 'ModalFerroviario');
0 ignored issues
show
Documentation introduced by
$dom 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...
359
                    break;
360
                case 5:
361
                    //Dutoviário
362
                    $this->isValid($this->versao, $this->getModalXML($dom, 'duto'), $method . 'ModalDutoviario');
0 ignored issues
show
Documentation introduced by
$dom 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...
363
                    break;
364
                case 6:
365
                    //Multimodal
366
                    $this->isValid($this->versao, $this->getModalXML($dom, 'multimodal'), $method . 'MultiModal');
0 ignored issues
show
Documentation introduced by
$dom 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...
367
                    break;
368
            }
369
        }
370
        return $signed;
371
    }
372
373
    /**
374
     * @todo
375
     * Retorna o xml do modal especifico
376
     * @param string $Dom CTe xml content
0 ignored issues
show
Bug introduced by
There is no parameter named $Dom. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
377
     * @param string $xml CTe xml content
0 ignored issues
show
Bug introduced by
There is no parameter named $xml. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
378
     * @return string
379
     */
380
    public function getModalXML($dom, $modal)
381
    {
382
        $modal = $dom->getElementsByTagName($modal)->item(0);
0 ignored issues
show
Bug introduced by
The method getElementsByTagName cannot be called on $dom (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
383
        $modal->setAttribute("xmlns", "http://www.portalfiscal.inf.br/cte");
384
        return $dom->saveXML($modal);
0 ignored issues
show
Bug introduced by
The method saveXML cannot be called on $dom (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
385
    }
386
387
    /**
388
     * @todo
389
     * Corret NFe fields when in contingency mode is set
390
     * @param string $xml CTe xml content
391
     * @return string
392
     */
393
    protected function correctCTeForContingencyMode($xml)
394
    {
395
        if ($this->contingency->type == '') {
396
            return $xml;
397
        }
398
        $xml = ContingencyCTe::adjust($xml, $this->contingency);
399
        return $this->signCTe($xml);
400
    }
401
402
    /**
403
     * Performs xml validation with its respective
404
     * XSD structure definition document
405
     * NOTE: if dont exists the XSD file will return true
406
     * @param string $version layout version
407
     * @param string $body
408
     * @param string $method
409
     * @return boolean
410
     */
411
    protected function isValid($version, $body, $method)
412
    {
413
        $schema = $this->pathschemes . $method . "_v$version.xsd";
414
        if (!is_file($schema)) {
415
            return true;
416
        }
417
        return Validator::isValid(
418
            $body,
419
            $schema
420
        );
421
    }
422
423
    /**
424
     * Verifies the existence of the service
425
     * @param string $service
426
     * @throws RuntimeException
427
     */
428
    protected function checkContingencyForWebServices($service)
0 ignored issues
show
Unused Code introduced by
The parameter $service 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...
429
    {
430
        $permit = [
431
            57 => ['SVSP', 'SVRS'],
432
            67 => ['SVSP', 'SVRS']
433
        ];
434
435
        $type = $this->contingency->type;
436
        $mod = $this->modelo;
437
        if (!empty($type)) {
438
            if (array_search($type, $permit[$mod]) === false) {
439
                throw new RuntimeException(
440
                    "Esse modo de contingência [$type] não é aceito "
441
                        . "para o modelo [$mod]"
442
                );
443
            }
444
        }
445
    }
446
447
    /**
448
     * Alter environment from "homologacao" to "producao" and vice-versa
449
     * @param int $tpAmb
450
     * @return void
451
     */
452
    public function setEnvironment($tpAmb = 2)
453
    {
454
        if (!empty($tpAmb) && ($tpAmb == 1 || $tpAmb == 2)) {
455
            $this->tpAmb = $tpAmb;
456
            $this->ambiente = ($tpAmb == 1) ? 'producao' : 'homologacao';
457
        }
458
    }
459
460
    /**
461
     * Set option for canonical transformation see C14n
462
     * @param array $opt
463
     * @return array
464
     */
465
    public function canonicalOptions($opt = [true, false, null, null])
466
    {
467
        if (!empty($opt) && is_array($opt)) {
468
            $this->canonical = $opt;
469
        }
470
        return $this->canonical;
471
    }
472
473
    /**
474
     * Assembles all the necessary parameters for soap communication
475
     * @param string $service
476
     * @param string $uf
477
     * @param string $tpAmb
478
     * @param bool $ignoreContingency
479
     * @return void
480
     */
481
    protected function servico(
482
        $service,
483
        $uf,
484
        $tpAmb,
485
        $ignoreContingency = false
486
    ) {
487
        $ambiente = $tpAmb == 1 ? "producao" : "homologacao";
488
        $webs = new Webservices($this->getXmlUrlPath());
489
        $sigla = $uf;
490
        if (!$ignoreContingency) {
491
            $contType = $this->contingency->type;
492
            if (
493
                !empty($contType)
494
                && ($contType == 'SVRS' || $contType == 'SVSP')
495
            ) {
496
                $sigla = $contType;
497
            }
498
        }
499
        $stdServ = $webs->get($sigla, $ambiente, $this->modelo);
500
        if ($stdServ === false) {
501
            throw new \RuntimeException(
502
                "Nenhum serviço foi localizado para esta unidade "
503
                    . "da federação [$sigla], com o modelo [$this->modelo]."
504
            );
505
        }
506
        if (empty($stdServ->$service->url)) {
507
            throw new \RuntimeException(
508
                "Este serviço [$service] não está disponivel para esta "
509
                    . "unidade da federação [$uf] ou para este modelo de Nota ["
510
                    . $this->modelo
511
                    . "]."
512
            );
513
        }
514
        //recuperação do cUF
515
        $this->urlcUF = $this->getcUF($uf);
0 ignored issues
show
Documentation Bug introduced by
The property $urlcUF was declared of type string, but $this->getcUF($uf) is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
516
        if ($this->urlcUF > 91) {
517
            //foi solicitado dado de SVRS ou SVSP
518
            $this->urlcUF = $this->getcUF($this->config->siglaUF);
0 ignored issues
show
Documentation Bug introduced by
The property $urlcUF was declared of type string, but $this->getcUF($this->config->siglaUF) is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
519
        }
520
        //recuperação da versão
521
        $this->urlVersion = $stdServ->$service->version;
522
        //recuperação da url do serviço
523
        $this->urlService = $stdServ->$service->url;
524
        //recuperação do método
525
        $this->urlMethod = $stdServ->$service->method;
526
        //recuperação da operação
527
        $this->urlOperation = $stdServ->$service->operation;
528
        //montagem do namespace do serviço
529
        $this->urlNamespace = sprintf(
530
            "%s/wsdl/%s",
531
            $this->urlPortal,
532
            $this->urlOperation
533
        );
534
        //montagem do cabeçalho da comunicação SOAP
535
        $this->urlHeader = Header::get(
536
            $this->urlNamespace,
537
            $this->urlcUF,
538
            $this->urlVersion
539
        );
540
        $this->urlAction = "\""
541
            . $this->urlNamespace
542
            . "/"
543
            . $this->urlMethod
544
            . "\"";
545
        //montagem do SOAP Header
546
        $this->objHeader = new \SOAPHeader(
547
            $this->urlNamespace,
548
            'cteCabecMsg',
549
            ['cUF' => $this->urlcUF, 'versaoDados' => $this->urlVersion]
550
        );
551
    }
552
553
    /**
554
     * Send request message to webservice
555
     * @param array $parameters
556
     * @param string $request
557
     * @return string
558
     */
559
    protected function sendRequest($request, array $parameters = [])
560
    {
561
        $this->checkSoap();
562
        return (string) $this->soap->send(
563
            $this->urlService,
564
            $this->urlMethod,
565
            $this->urlAction,
566
            SOAP_1_2,
567
            $parameters,
568
            $this->soapnamespaces,
569
            $request,
570
            $this->objHeader
571
        );
572
    }
573
574
    /**
575
     * Recover path to xml data base with list of soap services
576
     * @return string
577
     */
578
    protected function getXmlUrlPath()
579
    {
580
        $file = $this->pathwsfiles
581
            . DIRECTORY_SEPARATOR
582
            . "wscte_" . $this->versao . "_mod57.xml";
583
        if (!file_exists($file)) {
584
            return '';
585
        }
586
        return file_get_contents($file);
587
    }
588
589
    /**
590
     * Add QRCode Tag to signed XML from a NFCe
591
     * @param DOMDocument $dom
592
     * @return string
593
     */
594
    protected function addQRCode(DOMDocument $dom)
595
    {
596
        $signed = QRCode::putQRTag(
597
            $dom
598
        );
599
        return Strings::clearXmlString($signed);
600
    }
601
602
    /**
603
     * Verify if SOAP class is loaded, if not, force load SoapCurl
604
     */
605
    protected function checkSoap()
606
    {
607
        if (empty($this->soap)) {
608
            $this->soap = new SoapCurl($this->certificate);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \NFePHP\Common\Soap\...url($this->certificate) of type object<NFePHP\Common\Soap\SoapCurl> is incompatible with the declared type object<NFePHP\Common\Soap\SoapInterface> of property $soap.

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...
609
        }
610
    }
611
}
612