Completed
Push — master ( fff1f6...c33617 )
by Francis
02:57 queued 53s
created

PhpDocGenerator   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 273
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 41
eloc 95
c 1
b 0
f 0
dl 0
loc 273
rs 9.1199

19 Methods

Rating   Name   Duplication   Size   Complexity  
A addDescriptionLine() 0 3 1
A addVarLine() 0 3 1
A configure() 0 4 1
A addLine() 0 7 2
A addEmptyLine() 0 3 1
A buildTypedLinePrefix() 0 7 2
A addReturnLine() 0 3 1
A getWrapOn() 0 3 1
A addParamLine() 0 6 1
A hasSingleVarLine() 0 5 3
A buildTypedLines() 0 13 2
A addThrowsLine() 0 3 1
A buildLines() 0 21 4
A wrapLines() 0 17 4
A generate() 0 18 4
A buildLinesFromSingleLine() 0 25 5
A getPossibleTypesFromTypeNames() 0 20 5
A setWrapOn() 0 3 1
A orderLines() 0 7 1

How to fix   Complexity   

Complex Class

Complex classes like PhpDocGenerator 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.

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 PhpDocGenerator, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Prometee\SwaggerClientGenerator\Base\Generator\PhpDoc;
6
7
class PhpDocGenerator implements PhpDocGeneratorInterface
8
{
9
    /** @var array */
10
    protected $lines = [];
11
    /** @var int */
12
    protected $wrapOn = 100;
13
14
    /**
15
     * {@inheritDoc}
16
     */
17
    public function configure(array $lines = [], int $wrapOn = 100)
18
    {
19
        $this->lines = $lines;
20
        $this->wrapOn = $wrapOn;
21
    }
22
23
    /**
24
     * {@inheritDoc}
25
     */
26
    public function addLine(string $line, string $type = ''): void
27
    {
28
        if (!isset($this->lines[$type])) {
29
            $this->lines[$type] = [];
30
        }
31
32
        $this->lines[$type][] = $line;
33
    }
34
35
    /**
36
     * {@inheritDoc}
37
     */
38
    public function addDescriptionLine(string $line): void
39
    {
40
        $this->addLine($line, static::TYPE_DESCRIPTION);
41
    }
42
43
    /**
44
     * {@inheritDoc}
45
     */
46
    public function addEmptyLine(): void
47
    {
48
        $this->addDescriptionLine('');
49
    }
50
51
    /**
52
     * {@inheritDoc}
53
     */
54
    public function addVarLine(?string $line): void
55
    {
56
        $this->addLine($line, static::TYPE_VAR);
0 ignored issues
show
Bug introduced by
It seems like $line can also be of type null; however, parameter $line of Prometee\SwaggerClientGe...DocGenerator::addLine() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

56
        $this->addLine(/** @scrutinizer ignore-type */ $line, static::TYPE_VAR);
Loading history...
57
    }
58
59
    /**
60
     * {@inheritDoc}
61
     */
62
    public function addParamLine(string $name, string $type = '', string $description = ''): void
63
    {
64
        $line = sprintf('%s %s %s', $type, $name, $description);
65
        $this->addLine(
66
            trim($line),
67
            static::TYPE_PARAM
68
        );
69
    }
70
71
    /**
72
     * {@inheritDoc}
73
     */
74
    public function addReturnLine(string $line): void
75
    {
76
        $this->addLine($line, static::TYPE_RETURN);
77
    }
78
79
    /**
80
     * {@inheritDoc}
81
     */
82
    public function addThrowsLine(string $line): void
83
    {
84
        $this->addLine($line, static::TYPE_THROWS);
85
    }
86
87
    /**
88
     * {@inheritDoc}
89
     */
90
    public function hasSingleVarLine(): bool
91
    {
92
        return isset($this->lines[static::TYPE_VAR])
93
            && count($this->lines) === 1
94
            && count($this->lines[static::TYPE_VAR]) === 1;
95
    }
96
97
    /**
98
     * {@inheritDoc}
99
     */
100
    public function generate(string $indent = null): ?string
101
    {
102
        $phpdocLines = $this->buildLines();
103
104
        if (empty($phpdocLines)) {
105
            return null;
106
        }
107
108
        if ($this->hasSingleVarLine()) {
109
            return sprintf('%1$s/** %3$s */%2$s', $indent, "\n", $phpdocLines[0]);
110
        }
111
112
        $lines = [];
113
        foreach ($phpdocLines as $phpdocLine) {
114
            $lines[] = sprintf('%s * %s', $indent,$phpdocLine);
115
        }
116
117
        return sprintf('%1$s/**%2$s%3$s%2$s%1$s */%2$s', $indent, "\n", implode("\n", $lines));
118
    }
119
120
    /**
121
     * {@inheritDoc}
122
     */
123
    public function buildLines(): array
124
    {
125
        $phpdocLines = [];
126
        $previousType = null;
127
128
        $this->orderLines();
129
130
        foreach ($this->lines as $type => $lines) {
131
            if ($previousType === null) {
132
                $previousType = $type;
133
            }
134
            if ($previousType !== $type) {
135
                $phpdocLines[] = '';
136
                $previousType = $type;
137
            }
138
            $phpdocLines = array_merge(
139
                $phpdocLines,
140
                $this->buildTypedLines($type, $lines)
141
            );
142
        }
143
        return $phpdocLines;
144
    }
145
146
    /**
147
     * {@inheritDoc}
148
     */
149
    public function buildTypedLines(string $type, array $lines): array
150
    {
151
        $phpdocLines = [];
152
        $linePrefix = $this->buildTypedLinePrefix($type);
153
154
        foreach ($lines as $line) {
155
            $phpdocLines = array_merge(
156
                $phpdocLines,
157
                $this->buildLinesFromSingleLine($linePrefix, $line)
158
            );
159
        }
160
161
        return $phpdocLines;
162
    }
163
164
    /**
165
     * {@inheritDoc}
166
     */
167
    public function buildTypedLinePrefix(string $type): string
168
    {
169
        if ($type === static::TYPE_DESCRIPTION) {
170
            return '';
171
        }
172
173
        return sprintf('@%s ', $type);
174
    }
175
176
    /**
177
     * {@inheritDoc}
178
     */
179
    public function buildLinesFromSingleLine(string $linePrefix, string $line): array
180
    {
181
        $lines = [];
182
        $linePrefixLength = strlen($linePrefix);
183
        $blankSubLinePrefix = str_repeat(' ', $linePrefixLength);
184
        $explodedLines = explode("\n", $line);
185
186
        foreach ($explodedLines as $i=>$explodedLine) {
187
            $wrapOn = $this->wrapOn;
188
            if ($i === 0) {
189
                $wrapOn -= $linePrefixLength;
190
            }
191
192
            $lines = array_merge(
193
                $lines,
194
                $this->wrapLines($explodedLine, $wrapOn)
195
            );
196
        }
197
198
        foreach ($lines as $i=>$line) {
199
            $subLinePrefix = $i === 0 ? $linePrefix : $blankSubLinePrefix;
200
            $lines[$i] = $subLinePrefix . $line;
201
        }
202
203
        return $lines;
204
    }
205
206
    /**
207
     * {@inheritDoc}
208
     */
209
    public function wrapLines(string $line, ?int $wrapOn = null): array
210
    {
211
        $wrapOn = $wrapOn ?? $this->wrapOn;
212
        $lines = [];
213
        $currentLine = '';
214
215
        foreach (explode(' ', $line) as $word) {
216
            if (iconv_strlen($currentLine . ' ' . $word) > $wrapOn) {
217
                $lines[] = $currentLine;
218
                $currentLine = $word;
219
            } else {
220
                $currentLine .= (!empty($currentLine) ? ' ' : '') . $word;
221
            }
222
        }
223
        $lines[] = $currentLine;
224
225
        return $lines;
226
    }
227
228
    /**
229
     * {@inheritDoc}
230
     */
231
    public static function getPossibleTypesFromTypeNames(array $types = []): string
232
    {
233
        if (empty($types)) {
234
            return '';
235
        }
236
        $typesFound = [];
237
238
        foreach ($types as $type) {
239
            if ($type === null) {
240
                continue;
241
            }
242
            if (preg_match('#^\?#', $type)) {
243
                $typesFound[] = 'null';
244
            }
245
            $typesFound[] = ltrim($type, '?');
246
        }
247
248
        $typesFound = array_unique($typesFound);
249
250
        return implode('|', $typesFound);
251
    }
252
253
    /**
254
     * {@inheritDoc}
255
     */
256
    public function orderLines(): void
257
    {
258
        uksort($this->lines, function ($k1, $k2) {
259
            $o1 = array_search($k1, static::LINE_TYPE_ORDER);
260
            $o2 = array_search($k2, static::LINE_TYPE_ORDER);
261
262
            return $o1 - $o2;
263
        });
264
    }
265
266
    /**
267
     * {@inheritDoc}
268
     */
269
    public function setWrapOn(int $wrapOn): void
270
    {
271
        $this->wrapOn = $wrapOn;
272
    }
273
274
    /**
275
     * {@inheritDoc}
276
     */
277
    public function getWrapOn(): int
278
    {
279
        return $this->wrapOn;
280
    }
281
}
282