TypeParser::parseStringPart()   D
last analyzed

Complexity

Conditions 23
Paths 10

Size

Total Lines 74
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 44
CRAP Score 23

Importance

Changes 0
Metric Value
cc 23
eloc 48
nc 10
nop 3
dl 0
loc 74
rs 4.1666
c 0
b 0
f 0
ccs 44
cts 44
cp 1
crap 23

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 declare(strict_types=1);
2
3
namespace FileEye\MimeMap;
4
5
/**
6
 * Class for parsing RFC 2045 Content-Type Header Fields.
7
 */
8
class TypeParser
9
{
10
    /**
11
     * Parse a mime-type and set the class variables.
12
     *
13
     * @param string $type_string
14
     *   MIME type string to parse.
15
     * @param Type $type
16
     *   The Type object to receive the components.
17
     *
18
     * @throws MalformedTypeException when $type_string is malformed.
19
     */
20 69
    public static function parse(string $type_string, Type $type): void
21
    {
22
        // Media and SubType are separated by a slash '/'.
23 69
        $media = static::parseStringPart($type_string, 0, '/');
24 68
        if (!$media['string']) {
25 2
            throw new MalformedTypeException('Media type not found');
26
        }
27 66
        if (!$media['delimiter_matched']) {
28 1
            throw new MalformedTypeException('Slash \'/\' to separate media type and subtype not found');
29
        }
30 65
        $type->setMedia(strtolower((string) $media['string']));
31 65
        if ($media['comment'] !== null) {
0 ignored issues
show
introduced by
The condition $media['comment'] !== null is always false.
Loading history...
32 2
            $type->setMediaComment($media['comment']);
33
        }
34
35
        // SubType and Parameters are separated by semicolons ';'.
36 65
        $sub = static::parseStringPart($type_string, $media['end_offset'] + 1, ';');
37 64
        if (!$sub['string']) {
38 1
            throw new MalformedTypeException('Media subtype not found');
39
        }
40 63
        $type->setSubType(strtolower((string) $sub['string']));
41 63
        if ($sub['comment'] !== null) {
0 ignored issues
show
introduced by
The condition $sub['comment'] !== null is always false.
Loading history...
42 5
            $type->setSubTypeComment($sub['comment']);
43
        }
44
45
        // Loops through the parameter.
46 63
        while ($sub['delimiter_matched']) {
47 27
            $sub = static::parseStringPart($type_string, $sub['end_offset'] + 1, ';');
48 27
            $tmp = explode('=', $sub['string'], 2);
49 27
            $p_name = trim($tmp[0]);
50 27
            $p_val = trim($tmp[1]);
51 27
            $p_val = str_replace('\\"', '"', $p_val);
52 27
            $type->addParameter($p_name, $p_val, $sub['comment']);
53
        }
54
    }
55
56
    /**
57
     * Parses a part of the content MIME type string.
58
     *
59
     * Splits string and comment until a delimiter is found.
60
     *
61
     * @param string $string
62
     *   Input string.
63
     * @param int $offset
64
     *   Offset to start parsing from.
65
     * @param string $delimiter
66
     *   Stop parsing when delimiter found.
67
     *
68
     * @return array{'string': string, 'comment': string|null, 'delimiter_matched': bool, 'end_offset': int}
69
     *   An array with the following keys:
70
     *   'string' - the uncommented part of $string
71
     *   'comment' - the comment part of $string
72
     *   'delimiter_matched' - true if a $delimiter stopped the parsing, false
73
     *                         otherwise
74
     *   'end_offset' - the last position parsed in $string.
75
     */
76 101
    public static function parseStringPart(string $string, int $offset, string $delimiter): array
77
    {
78 101
        $inquote   = false;
79 101
        $escaped   = false;
80 101
        $incomment = 0;
81 101
        $newstring = '';
82 101
        $comment = '';
83
84 101
        for ($n = $offset; $n < strlen($string); $n++) {
85 99
            if ($string[$n] === $delimiter && !$escaped && !$inquote && $incomment === 0) {
86 95
                break;
87
            }
88
89 97
            if ($escaped) {
90 4
                if ($incomment == 0) {
91 2
                    $newstring .= $string[$n];
92
                } else {
93 2
                    $comment .= $string[$n];
94
                }
95 4
                $escaped = false;
96 4
                continue;
97
            }
98
99 97
            if ($string[$n] == '\\') {
100 4
                if ($incomment > 0) {
101 2
                    $comment .= $string[$n];
102
                }
103 4
                $escaped = true;
104 4
                continue;
105
            }
106
107 97
            if (!$inquote && $incomment > 0 && $string[$n] == ')') {
108 23
                $incomment--;
109 23
                if ($incomment == 0) {
110 19
                    $comment .= ' ';
111
                }
112 23
                continue;
113
            }
114
115 97
            if (!$inquote && $string[$n] == '(') {
116 23
                $incomment++;
117 23
                continue;
118
            }
119
120 97
            if ($string[$n] == '"') {
121 10
                if ($incomment > 0) {
122 1
                    $comment .= $string[$n];
123
                } else {
124 9
                    if ($inquote) {
125 9
                        $inquote = false;
126
                    } else {
127 9
                        $inquote = true;
128
                    }
129
                }
130 10
                continue;
131
            }
132
133 97
            if ($incomment == 0) {
134 97
                $newstring .= $string[$n];
135 97
                continue;
136
            }
137
138 23
            $comment .= $string[$n];
139
        }
140
141 101
        if ($incomment > 0) {
142 4
            throw new MalformedTypeException('Comment closing bracket missing: ' . $comment);
143
        }
144
145
        return [
146 99
          'string' => trim($newstring),
147 99
          'comment' => empty($comment) ? null : trim($comment),
0 ignored issues
show
introduced by
The condition empty($comment) is always true.
Loading history...
148 99
          'delimiter_matched' => isset($string[$n]) ? ($string[$n] === $delimiter) : false,
149
          'end_offset' => $n,
150
        ];
151
    }
152
}
153