Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.62% covered (success)
97.62%
82 / 84
91.30% covered (success)
91.30%
21 / 23
CRAP
0.00% covered (danger)
0.00%
0 / 1
DocblockGenerator
97.62% covered (success)
97.62%
82 / 84
91.30% covered (success)
91.30%
21 / 23
52
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setDesc
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getDesc
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasDesc
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addTag
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addTags
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getTag
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasTag
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addParam
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addParams
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
4
 getParam
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
 hasParam
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 setReturn
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getReturn
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasReturn
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setThrows
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getThrows
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasThrows
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 render
92.31% covered (success)
92.31%
12 / 13
0.00% covered (danger)
0.00%
0 / 1
4.01
 formatTags
96.77% covered (success)
96.77%
30 / 31
0.00% covered (danger)
0.00%
0 / 1
15
 getTagLength
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getParamLength
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Code\Generator;
15
16/**
17 * Abstract generator class
18 *
19 * @category   Pop
20 * @package    Pop\Code
21 * @author     Nick Sagona, III <dev@nolainteractive.com>
22 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
23 * @license    http://www.popphp.org/license     New BSD License
24 * @version    5.0.0
25 */
26class DocblockGenerator extends AbstractGenerator
27{
28
29    /**
30     * Docblock description
31     * @var ?string
32     */
33    protected ?string $desc = null;
34
35    /**
36     * Docblock tags
37     * @var array
38     */
39    protected array $tags = ['param' => []];
40
41    /**
42     * Constructor
43     *
44     * Instantiate the docblock generator object
45     *
46     * @param ?string $desc
47     * @param int     $indent
48     */
49    public function __construct(?string $desc = null, int $indent = 4)
50    {
51        $this->setDesc($desc);
52        $this->setIndent($indent);
53    }
54
55    /**
56     * Set the docblock description
57     *
58     * @param  ?string $desc
59     * @return DocblockGenerator
60     */
61    public function setDesc(?string $desc = null): DocblockGenerator
62    {
63        $this->desc = $desc;
64        return $this;
65    }
66
67    /**
68     * Get the docblock description
69     *
70     * @return string|null
71     */
72    public function getDesc(): string|null
73    {
74        return $this->desc;
75    }
76
77    /**
78     * Has a docblock description
79     *
80     * @return bool
81     */
82    public function hasDesc(): bool
83    {
84        return ($this->desc !== null);
85    }
86
87    /**
88     * Add a basic tag
89     *
90     * @param  string  $name
91     * @param  ?string $desc
92     * @return DocblockGenerator
93     */
94    public function addTag(string $name, ?string $desc = null): DocblockGenerator
95    {
96        $this->tags[$name] = $desc;
97        return $this;
98    }
99
100    /**
101     * Add basic tags
102     *
103     * @param  array $tags
104     * @return DocblockGenerator
105     */
106    public function addTags(array $tags): DocblockGenerator
107    {
108        foreach ($tags as $name => $desc) {
109            $this->tags[$name] = $desc;
110        }
111        return $this;
112    }
113
114    /**
115     * Get a tag
116     *
117     * @param  string $name
118     * @return string|null
119     */
120    public function getTag(string $name): string|null
121    {
122        return $this->tags[$name] ?? null;
123    }
124
125    /**
126     * Has a tag
127     *
128     * @param  string $name
129     * @return bool
130     */
131    public function hasTag(string $name): bool
132    {
133        return (isset($this->tags[$name]));
134    }
135
136    /**
137     * Add a param tag
138     *
139     * @param  ?string $type
140     * @param  ?string $var
141     * @param  ?string $desc
142     * @return DocblockGenerator
143     */
144    public function addParam(?string $type = null, ?string $var = null, ?string $desc = null): DocblockGenerator
145    {
146        $this->tags['param'][] = ['type' => $type, 'var' => $var, 'desc' => $desc];
147        return $this;
148    }
149
150    /**
151     * Add a param tag
152     *
153     * @param  array $params
154     * @return DocblockGenerator
155     */
156    public function addParams(array $params): DocblockGenerator
157    {
158        $params = (isset($params[0]) && is_array($params[0])) ? $params : [$params];
159        foreach ($params as $param) {
160            $this->tags['param'][] = $param;
161        }
162        return $this;
163    }
164
165    /**
166     * Get a param
167     *
168     * @param  int $index
169     * @return array|null
170     */
171    public function getParam(int $index): array|null
172    {
173        return (isset($this->tags['param']) && isset($this->tags['param'][$index])) ? $this->tags['param'][$index] : null;
174    }
175
176    /**
177     * Has a param
178     *
179     * @param  int $index
180     * @return bool
181     */
182    public function hasParam(int $index): bool
183    {
184        return (isset($this->tags['param']) && isset($this->tags['param'][$index]));
185    }
186
187    /**
188     * Add a return tag
189     *
190     * @param  string  $type
191     * @param  ?string $desc
192     * @return DocblockGenerator
193     */
194    public function setReturn(string $type, ?string $desc = null): DocblockGenerator
195    {
196        $this->tags['return'] = ['type' => $type, 'desc' => $desc];
197        return $this;
198    }
199
200    /**
201     * Get the return
202     *
203     * @return array|null
204     */
205    public function getReturn(): array|null
206    {
207        return $this->tags['return'] ?? null;
208    }
209
210    /**
211     * Has a return
212     *
213     * @return bool
214     */
215    public function hasReturn(): bool
216    {
217        return (isset($this->tags['return']));
218    }
219
220    /**
221     * Add a throws tag
222     *
223     * @param  string  $type
224     * @param  ?string $desc
225     * @return DocblockGenerator
226     */
227    public function setThrows(string $type, ?string $desc = null): DocblockGenerator
228    {
229        $this->tags['throws'] = ['type' => $type, 'desc' => $desc];
230        return $this;
231    }
232
233    /**
234     * Get the throws
235     *
236     * @return array|null
237     */
238    public function getThrows(): array|null
239    {
240        return $this->tags['throws'] ?? null;
241    }
242
243    /**
244     * Has a throws
245     *
246     * @return bool
247     */
248    public function hasThrows(): bool
249    {
250        return (isset($this->tags['throws']));
251    }
252
253    /**
254     * Render docblock
255     *
256     * @return string
257     */
258    public function render(): string
259    {
260        $this->output = $this->printIndent() . '/**' . PHP_EOL;
261
262        if (!empty($this->desc)) {
263            $desc    = trim($this->desc);
264            $descAry = explode("\n", $desc);
265            $i = 0;
266            foreach ($descAry as $d) {
267                $i++;
268                $this->output .= $this->printIndent() . ' * ' . wordwrap($d, 70, PHP_EOL . $this->printIndent() . " * ") . PHP_EOL;
269                if ($i < count($descAry)) {
270                    $this->output .= $this->printIndent() . ' * ' . PHP_EOL;
271                }
272            }
273        }
274
275        $this->output .= $this->formatTags();
276        $this->output .= $this->printIndent() . ' */' . PHP_EOL;
277
278        return $this->output;
279    }
280
281    /**
282     * Format the docblock tags
283     *
284     * @return string
285     */
286    protected function formatTags(): string
287    {
288        $tags      = null;
289        $tagLength = $this->getTagLength();
290
291        // Format basic tags
292        foreach ($this->tags as $tag => $desc) {
293            if (($tag != 'param') && ($tag != 'return') && ($tag != 'throws')) {
294                $tags .= $this->printIndent() . ' * @' . $tag .
295                    str_repeat(' ', $tagLength - strlen($tag) + 1) .
296                    $desc . PHP_EOL;
297            }
298        }
299
300        // Format param tags
301        foreach ($this->tags['param'] as $param) {
302            $paramLength = $this->getParamLength();
303            $tags .= $this->printIndent() . ' * @param';
304
305            if (!empty($param['type'])) {
306                $tags .= str_repeat(' ', $tagLength - 4) . $param['type'] .
307                    str_repeat(' ', $paramLength - strlen($param['type']) + 1);
308            }
309            if (!empty($param['var'])) {
310                $tags .= ' ' . $param['var'];
311            }
312            $tags .= ($param['desc'] !== null) ? $param['desc'] . PHP_EOL : PHP_EOL;
313        }
314
315        // Format throw tag
316        if (array_key_exists('throws', $this->tags)) {
317            $throws = $this->tags['throws']['type'];
318            if (!empty($this->tags['throws']['desc'])) {
319                $throws .= ' ' . $this->tags['throws']['desc'];
320            }
321            $tags .= $this->printIndent() . ' * @throws' .
322                str_repeat(' ', $tagLength - 5) .
323                $throws . PHP_EOL;
324        }
325
326        // Format return tag
327        if (array_key_exists('return', $this->tags)) {
328            $tags .= $this->printIndent() . ' * @return' .
329                str_repeat(' ', $tagLength - 5) .
330                $this->tags['return']['type'];
331            if ($this->tags['return']['desc'] !== null) {
332                $tags .= ' ' . $this->tags['return']['desc'] . PHP_EOL;
333            } else {
334                $tags .= PHP_EOL;
335            }
336        }
337
338        return (($tags !== null) && ($this->desc !== null)) ? $this->printIndent() . ' * ' . PHP_EOL . $tags : $tags;
339    }
340
341    /**
342     * Get the longest tag length
343     *
344     * @return int
345     */
346    protected function getTagLength(): int
347    {
348        $length = 0;
349
350        foreach ($this->tags as $key => $value) {
351            if (strlen($key) > $length) {
352                $length = strlen($key);
353            }
354        }
355
356        return $length;
357    }
358
359    /**
360     * Get the longest param type length
361     *
362     * @return int
363     */
364    protected function getParamLength(): int
365    {
366        $length = 0;
367
368        foreach ($this->tags['param'] as $param) {
369            if (!empty($param['type']) && (strlen($param['type']) > $length)) {
370                $length = strlen($param['type']);
371            }
372        }
373
374        return $length;
375    }
376
377    /**
378     * Print docblock
379     *
380     * @return string
381     */
382    public function __toString(): string
383    {
384        return $this->render();
385    }
386
387}