Parser   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 105
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 2
dl 0
loc 105
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B read() 0 41 7
A block() 0 26 5
1
<?php
2
3
namespace NFePHP\ECF\Common;
4
5
use ForceUTF8\Encoding;
6
use NFePHP\Common\Strings;
7
8
class Parser
9
{
10
11
    public $error = [];
12
    protected $blocks;
13
    protected $info = [];
14
15
    /**
16
     * Constructor
17
     * @param string $version
18
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
19
     */
20
    public function __construct($version = '310')
21
    {
22
        $structurefile = __DIR__ . "/../../storage/structure_ECF_{$version}.txt";
23
        $structure = file_get_contents($structurefile);
24
        $this->blocks = $this->block($structure, true);
25
    }
26
27
    /**
28
     * Read ECF content file and return as array
29
     *
30
     * @param string $contentfile
31
     *
32
     * @return array
33
     *
34
     * @throws Exception
35
     */
36
    public function read($contentfile)
37
    {
38
        //cleaning
39
        $contentfile = str_replace('__', '_', $contentfile);
40
        $contentfile = str_replace(['| ', ' |'], '|', $contentfile);
41
        $contentfile = str_replace(['- ', ' -'], '-', $contentfile);
42
        $contentfile = str_replace('\r', '', $contentfile);
43
        $contentfile = strtoupper($contentfile);
44
        $contentfile = Encoding::fixUTF8($contentfile);
45
        $contentfile = Strings::squashCharacters($contentfile);
46
47
        $datas = $this->block($contentfile);
48
        $i = 1;
49
        foreach ($datas as $data) {
50
            foreach ($data as $key => $d) {
51
                $node = $this->blocks[$key];
52
                $vars = [];
53
                if (empty($d)) {
54
                    continue;
55
                }
56
                if (count($node) !== count($d)) {
57
                    $this->error[] = "Erro de conteúdo da chave $key";
58
                }
59
                foreach ($d as $n => $value) {
60
                    $name = $node[$n];
61
                    $value = str_replace(',', '.', $value);
62
                    $value = str_replace(["\r","\t","\n"], "", $value);
63
                    //$value = preg_replace('/(?:\s\s+)/', ' ', $value);
64
                    $value = preg_replace("/[^a-zA-Z0-9 @,-_.;:\/]/", "", $value);
65
                    $vars[$name] = trim($value);
66
                }
67
            }
68
            if (substr($key, 1, 2) === '99') {
0 ignored issues
show
Bug introduced by
The variable $key seems to be defined by a foreach iteration on line 50. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
69
                $i++;
70
                continue;
71
            }
72
            $this->info[$i] = [$key => $vars];
0 ignored issues
show
Bug introduced by
The variable $vars does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
73
            $i++;
74
        }
75
        return $this->info;
76
    }
77
78
    /**
79
     * Build block
80
     *
81
     * @param string $fields
82
     * @param bool $unique
83
     *
84
     * @return array
85
     */
86
    protected function block($fields, $unique = false)
87
    {
88
        $elements = explode("\n", $fields);
89
        $block = [];
90
        foreach ($elements as $element) {
91
            if (empty($element)) {
92
                continue;
93
            }
94
            $arr = explode('|', $element);
95
            $n = count($arr);
96
            $fields = array_slice($arr, 1, $n - 2);
97
            $key = (string) $fields[0];
98
            if (substr($key, 0, 1) === '9') {
99
                continue;
100
            }
101
            array_splice($fields, 0, 1);
102
            if ($unique) {
103
                $block[$key] = $fields;
104
            } else {
105
                $block[] = [
106
                    $key => $fields
107
                ];
108
            }
109
        }
110
        return $block;
111
    }
112
}
113