Passed
Pull Request — master (#1)
by
unknown
05:29
created

Parser::parse()   C

Complexity

Conditions 13
Paths 19

Size

Total Lines 79

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 44
CRAP Score 13

Importance

Changes 0
Metric Value
dl 0
loc 79
ccs 44
cts 44
cp 1
rs 5.7515
c 0
b 0
f 0
cc 13
nc 19
nop 1
crap 13

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
declare(strict_types=1);
4
5
namespace Lamoda\GS1Parser\Parser;
6
7
use Lamoda\GS1Parser\Barcode;
8
use Lamoda\GS1Parser\Exception\InvalidBarcodeException;
9
10
/**
11
 * Performs barcode parsing according to
12
 * https://www.gs1.org/sites/default/files/docs/barcodes/GS1_General_Specifications.pdf
13
 */
14
final class Parser implements ParserInterface
15
{
16
    private const FIXED_LENGTH_AIS = [
17
        '00' => 20,
18
        '01' => 16,
19
        '02' => 16,
20
        '03' => 16,
21
        '04' => 18,
22
        '11' => 8,
23
        '12' => 8,
24
        '13' => 8,
25
        '14' => 8,
26
        '15' => 8,
27
        '16' => 8,
28
        '17' => 8,
29
        '18' => 8,
30
        '19' => 8,
31
        '20' => 4,
32
        '31' => 10,
33
        '32' => 10,
34
        '33' => 10,
35
        '34' => 10,
36
        '35' => 10,
37
        '36' => 10,
38
        '41' => 16,
39
    ];
40
    private const FIXED_AI_LENGTH = 2;
41
42
    /**
43
     * @var ParserConfig
44
     */
45
    private $config;
46
47 17
    public function __construct(ParserConfig $config)
48
    {
49 17
        $this->config = $config;
50 17
    }
51
52 17
    public function parse(string $data): Barcode
53
    {
54 17
        $data = trim($data);
55
56 17
        if ($data === '') {
57 1
            throw InvalidBarcodeException::becauseBarcodeIsEmpty();
58
        }
59
60 16
        [$fnc1Prefix, $codeType] = $this->fetchFNC1Prefix($data);
61
62 16
        if ($fnc1Prefix === null && $this->config->isFnc1SequenceRequired()) {
63 1
            throw InvalidBarcodeException::becauseFNC1SequenceIsNotFound();
64
        }
65
66 15
        $codeOffset = strlen((string)$fnc1Prefix);
67 15
        $dataLength = strlen($data);
68
69 15
        if ($dataLength <= $codeOffset) {
70 1
            throw InvalidBarcodeException::becauseNoDataPresent();
71
        }
72
73 14
        $position = $codeOffset;
74 14
        $foundAIs = [];
75 14
        $buffer = [];
76 14
        while ($position < $dataLength) {
77 14
            [$ai, $length] = $this->fetchFixedAI($data, $position, $dataLength);
78 14
            $value = null;
0 ignored issues
show
Unused Code introduced by
$value 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...
79
80 14
            if ($ai !== null) {
81 13
                if ($position + $length > $dataLength) {
82 1
                    throw InvalidBarcodeException::becauseNotEnoughDataFoAI(
83 1
                        $ai,
84 1
                        $length,
85 1
                        $dataLength - $position
86
                    );
87
                }
88
89 12
                $isKnownAI = in_array($ai, $this->config->getKnownAIs(), true);
90
91 12
                if ($isKnownAI) {
92 3
                    $value = substr($data, $position + self::FIXED_AI_LENGTH, $length - self::FIXED_AI_LENGTH);
93
                } else {
94 9
                    $ai = null;
95 9
                    $value = substr($data, $position, $length);
96
                }
97
98 12
                if (strpos($value, $this->config->getGroupSeparator()) !== false) {
99 1
                    throw InvalidBarcodeException::becauseGroupSeparatorWasNotExpected($value);
100
                }
101
102 11
                $position += $length;
103
            } else {
104 12
                [$ai, $aiLength] = $this->fetchKnownAI($data, $position);
105
106 12
                $groupSeparatorPosition = strpos($data, $this->config->getGroupSeparator(), $position);
107 12
                if ($groupSeparatorPosition !== false) {
108 6
                    $length = $groupSeparatorPosition - $position;
109
                } else {
110 9
                    $length = $dataLength - $position;
111
                }
112
113 12
                if ($ai) {
114 3
                    $value = substr($data, $position + $aiLength, $length - $aiLength);
115
                } else {
116 9
                    $value = substr($data, $position, $length);
117
                }
118
119 12
                $position += $length + strlen($this->config->getGroupSeparator());
120
            }
121
122 12
            if ($ai) {
123 3
                $foundAIs[$ai] = $value;
124
            } else {
125 9
                $buffer[] = $value;
126
            }
127
        }
128
129 12
        return new Barcode($data, $codeType, $foundAIs, $buffer, (string)$fnc1Prefix);
130
    }
131
132 16
    private function fetchFNC1Prefix(string $data): array
133
    {
134 16
        foreach ($this->config->getFnc1PrefixMap() as $prefix => $codeType) {
135 16
            if (substr_compare($data, $prefix, 0, strlen($prefix), true) === 0) {
136 16
                return [$prefix, $codeType];
137
            }
138
        }
139
140 5
        return [null, Barcode::TYPE_UNKNOWN];
141
    }
142
143 14
    private function fetchFixedAI(string $data, int $position, int $dataLength): array
144
    {
145 14
        if ($dataLength - $position < self::FIXED_AI_LENGTH) {
146 1
            return [null, null];
147
        }
148
149 13
        $ai = substr($data, $position, self::FIXED_AI_LENGTH);
150
151 13
        $length = self::FIXED_LENGTH_AIS[$ai] ?? null;
152
153 13
        if ($length === null) {
154 11
            return [null, null];
155
        }
156
157 13
        return [$ai, $length];
158
    }
159
160 12
    private function fetchKnownAI(string $data, int $position): array
161
    {
162 12
        foreach ($this->config->getKnownAIs() as $ai) {
163 3
            $aiLength = strlen($ai);
164 3
            if (substr_compare($data, $ai, $position, $aiLength, true) === 0) {
165 3
                return [substr($data, $position, $aiLength), $aiLength];
166
            }
167
        }
168
169 9
        return [null, null];
170
    }
171
}