Completed
Push — master ( 37d62c...e7e72e )
by Alexander
138:08 queued 134:55
created

Controller::runAction()   D

Complexity

Conditions 19
Paths 20

Size

Total Lines 68
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 23.2394

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 19
eloc 45
c 1
b 0
f 0
nc 20
nop 2
dl 0
loc 68
ccs 34
cts 44
cp 0.7727
crap 23.2394
rs 4.5166

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
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\console;
9
10
use Yii;
11
use yii\base\Action;
12
use yii\base\InlineAction;
13
use yii\base\InvalidRouteException;
14
use yii\helpers\Console;
15
use yii\helpers\Inflector;
16
17
/**
18
 * Controller is the base class of console command classes.
19
 *
20
 * A console controller consists of one or several actions known as sub-commands.
21
 * Users call a console command by specifying the corresponding route which identifies a controller action.
22
 * The `yii` program is used when calling a console command, like the following:
23
 *
24
 * ```
25
 * yii <route> [--param1=value1 --param2 ...]
26
 * ```
27
 *
28
 * where `<route>` is a route to a controller action and the params will be populated as properties of a command.
29
 * See [[options()]] for details.
30
 *
31
 * @property string $help This property is read-only.
32
 * @property string $helpSummary This property is read-only.
33
 * @property array $passedOptionValues The properties corresponding to the passed options. This property is
34
 * read-only.
35
 * @property array $passedOptions The names of the options passed during execution. This property is
36
 * read-only.
37
 *
38
 * @author Qiang Xue <[email protected]>
39
 * @since 2.0
40
 */
41
class Controller extends \yii\base\Controller
42
{
43
    /**
44
     * @deprecated since 2.0.13. Use [[ExitCode::OK]] instead.
45
     */
46
    const EXIT_CODE_NORMAL = 0;
47
    /**
48
     * @deprecated since 2.0.13. Use [[ExitCode::UNSPECIFIED_ERROR]] instead.
49
     */
50
    const EXIT_CODE_ERROR = 1;
51
52
    /**
53
     * @var bool whether to run the command interactively.
54
     */
55
    public $interactive = true;
56
    /**
57
     * @var bool whether to enable ANSI color in the output.
58
     * If not set, ANSI color will only be enabled for terminals that support it.
59
     */
60
    public $color;
61
    /**
62
     * @var bool whether to display help information about current command.
63
     * @since 2.0.10
64
     */
65
    public $help;
66
67
    /**
68
     * @var array the options passed during execution.
69
     */
70
    private $_passedOptions = [];
71
72
73
    /**
74
     * Returns a value indicating whether ANSI color is enabled.
75
     *
76
     * ANSI color is enabled only if [[color]] is set true or is not set
77
     * and the terminal supports ANSI color.
78
     *
79
     * @param resource $stream the stream to check.
80
     * @return bool Whether to enable ANSI style in output.
81
     */
82 7
    public function isColorEnabled($stream = \STDOUT)
83
    {
84 7
        return $this->color === null ? Console::streamSupportsAnsiColors($stream) : $this->color;
85
    }
86
87
    /**
88
     * Runs an action with the specified action ID and parameters.
89
     * If the action ID is empty, the method will use [[defaultAction]].
90
     * @param string $id the ID of the action to be executed.
91
     * @param array $params the parameters (name-value pairs) to be passed to the action.
92
     * @return int the status of the action execution. 0 means normal, other values mean abnormal.
93
     * @throws InvalidRouteException if the requested action ID cannot be resolved into an action successfully.
94
     * @throws Exception if there are unknown options or missing arguments
95
     * @see createAction
96
     */
97 220
    public function runAction($id, $params = [])
98
    {
99 220
        if (!empty($params)) {
100
            // populate options here so that they are available in beforeAction().
101 208
            $options = $this->options($id === '' ? $this->defaultAction : $id);
102 208
            if (isset($params['_aliases'])) {
103 1
                $optionAliases = $this->optionAliases();
104 1
                foreach ($params['_aliases'] as $name => $value) {
105 1
                    if (array_key_exists($name, $optionAliases)) {
106 1
                        $params[$optionAliases[$name]] = $value;
107
                    } else {
108
                        $message = Yii::t('yii', 'Unknown alias: -{name}', ['name' => $name]);
109
                        if (!empty($optionAliases)) {
110
                            $aliasesAvailable = [];
111
                            foreach ($optionAliases as $alias => $option) {
112
                                $aliasesAvailable[] = '-' . $alias . ' (--' . $option . ')';
113
                            }
114
115
                            $message .= '. ' . Yii::t('yii', 'Aliases available: {aliases}', [
116
                                'aliases' => implode(', ', $aliasesAvailable)
117
                            ]);
118
                        }
119 1
                        throw new Exception($message);
120
                    }
121
                }
122 1
                unset($params['_aliases']);
123
            }
124 208
            foreach ($params as $name => $value) {
125
                // Allow camelCase options to be entered in kebab-case
126 208
                if (!in_array($name, $options, true) && strpos($name, '-') !== false) {
127 1
                    $kebabName = $name;
128 1
                    $altName = lcfirst(Inflector::id2camel($kebabName));
129 1
                    if (in_array($altName, $options, true)) {
130 1
                        $name = $altName;
131
                    }
132
                }
133
134 208
                if (in_array($name, $options, true)) {
135 51
                    $default = $this->$name;
136 51
                    if (is_array($default)) {
137 51
                        $this->$name = preg_split('/\s*,\s*(?![^()]*\))/', $value);
138 11
                    } elseif ($default !== null) {
139 10
                        settype($value, gettype($default));
140 10
                        $this->$name = $value;
141
                    } else {
142 1
                        $this->$name = $value;
143
                    }
144 51
                    $this->_passedOptions[] = $name;
145 51
                    unset($params[$name]);
146 51
                    if (isset($kebabName)) {
147 51
                        unset($params[$kebabName]);
148
                    }
149 202
                } elseif (!is_int($name)) {
150
                    $message = Yii::t('yii', 'Unknown option: --{name}', ['name' => $name]);
151
                    if (!empty($options)) {
152
                        $message .= '. ' . Yii::t('yii', 'Options available: {options}', ['options' => '--' . implode(', --', $options)]);
153
                    }
154
155 208
                    throw new Exception($message);
156
                }
157
            }
158
        }
159 220
        if ($this->help) {
160 2
            $route = $this->getUniqueId() . '/' . $id;
161 2
            return Yii::$app->runAction('help', [$route]);
162
        }
163
164 220
        return parent::runAction($id, $params);
165
    }
166
167
    /**
168
     * Binds the parameters to the action.
169
     * This method is invoked by [[Action]] when it begins to run with the given parameters.
170
     * This method will first bind the parameters with the [[options()|options]]
171
     * available to the action. It then validates the given arguments.
172
     * @param Action $action the action to be bound with parameters
173
     * @param array $params the parameters to be bound to the action
174
     * @return array the valid parameters that the action can run with.
175
     * @throws Exception if there are unknown options or missing arguments
176
     */
177 229
    public function bindActionParams($action, $params)
178
    {
179 229
        if ($action instanceof InlineAction) {
180 229
            $method = new \ReflectionMethod($this, $action->actionMethod);
181
        } else {
182
            $method = new \ReflectionMethod($action, 'run');
183
        }
184
185 229
        $args = array_values($params);
186
187 229
        $missing = [];
188 229
        foreach ($method->getParameters() as $i => $param) {
189 223
            if ($param->isArray() && isset($args[$i])) {
190 1
                $args[$i] = $args[$i] === '' ? [] : preg_split('/\s*,\s*/', $args[$i]);
191
            }
192 223
            if (!isset($args[$i])) {
193 56
                if ($param->isDefaultValueAvailable()) {
194 56
                    $args[$i] = $param->getDefaultValue();
195
                } else {
196 223
                    $missing[] = $param->getName();
197
                }
198
            }
199
        }
200
201 229
        if (!empty($missing)) {
202 1
            throw new Exception(Yii::t('yii', 'Missing required arguments: {params}', ['params' => implode(', ', $missing)]));
203
        }
204
205 229
        return $args;
206
    }
207
208
    /**
209
     * Formats a string with ANSI codes.
210
     *
211
     * You may pass additional parameters using the constants defined in [[\yii\helpers\Console]].
212
     *
213
     * Example:
214
     *
215
     * ```
216
     * echo $this->ansiFormat('This will be red and underlined.', Console::FG_RED, Console::UNDERLINE);
217
     * ```
218
     *
219
     * @param string $string the string to be formatted
220
     * @return string
221
     */
222 7
    public function ansiFormat($string)
223
    {
224 7
        if ($this->isColorEnabled()) {
225 7
            $args = func_get_args();
226 7
            array_shift($args);
227 7
            $string = Console::ansiFormat($string, $args);
228
        }
229
230 7
        return $string;
231
    }
232
233
    /**
234
     * Prints a string to STDOUT.
235
     *
236
     * You may optionally format the string with ANSI codes by
237
     * passing additional parameters using the constants defined in [[\yii\helpers\Console]].
238
     *
239
     * Example:
240
     *
241
     * ```
242
     * $this->stdout('This will be red and underlined.', Console::FG_RED, Console::UNDERLINE);
243
     * ```
244
     *
245
     * @param string $string the string to print
246
     * @return int|bool Number of bytes printed or false on error
247
     */
248
    public function stdout($string)
249
    {
250
        if ($this->isColorEnabled()) {
251
            $args = func_get_args();
252
            array_shift($args);
253
            $string = Console::ansiFormat($string, $args);
254
        }
255
256
        return Console::stdout($string);
257
    }
258
259
    /**
260
     * Prints a string to STDERR.
261
     *
262
     * You may optionally format the string with ANSI codes by
263
     * passing additional parameters using the constants defined in [[\yii\helpers\Console]].
264
     *
265
     * Example:
266
     *
267
     * ```
268
     * $this->stderr('This will be red and underlined.', Console::FG_RED, Console::UNDERLINE);
269
     * ```
270
     *
271
     * @param string $string the string to print
272
     * @return int|bool Number of bytes printed or false on error
273
     */
274
    public function stderr($string)
275
    {
276
        if ($this->isColorEnabled(\STDERR)) {
277
            $args = func_get_args();
278
            array_shift($args);
279
            $string = Console::ansiFormat($string, $args);
280
        }
281
282
        return fwrite(\STDERR, $string);
283
    }
284
285
    /**
286
     * Prompts the user for input and validates it.
287
     *
288
     * @param string $text prompt string
289
     * @param array $options the options to validate the input:
290
     *
291
     *  - required: whether it is required or not
292
     *  - default: default value if no input is inserted by the user
293
     *  - pattern: regular expression pattern to validate user input
294
     *  - validator: a callable function to validate input. The function must accept two parameters:
295
     *      - $input: the user input to validate
296
     *      - $error: the error value passed by reference if validation failed.
297
     *
298
     * An example of how to use the prompt method with a validator function.
299
     *
300
     * ```php
301
     * $code = $this->prompt('Enter 4-Chars-Pin', ['required' => true, 'validator' => function($input, &$error) {
302
     *     if (strlen($input) !== 4) {
303
     *         $error = 'The Pin must be exactly 4 chars!';
304
     *         return false;
305
     *     }
306
     *     return true;
307
     * }]);
308
     * ```
309
     *
310
     * @return string the user input
311
     */
312
    public function prompt($text, $options = [])
313
    {
314
        if ($this->interactive) {
315
            return Console::prompt($text, $options);
316
        }
317
318
        return isset($options['default']) ? $options['default'] : '';
319
    }
320
321
    /**
322
     * Asks user to confirm by typing y or n.
323
     *
324
     * A typical usage looks like the following:
325
     *
326
     * ```php
327
     * if ($this->confirm("Are you sure?")) {
328
     *     echo "user typed yes\n";
329
     * } else {
330
     *     echo "user typed no\n";
331
     * }
332
     * ```
333
     *
334
     * @param string $message to echo out before waiting for user input
335
     * @param bool $default this value is returned if no selection is made.
336
     * @return bool whether user confirmed.
337
     * Will return true if [[interactive]] is false.
338
     */
339 153
    public function confirm($message, $default = false)
340
    {
341 153
        if ($this->interactive) {
342
            return Console::confirm($message, $default);
343
        }
344
345 153
        return true;
346
    }
347
348
    /**
349
     * Gives the user an option to choose from. Giving '?' as an input will show
350
     * a list of options to choose from and their explanations.
351
     *
352
     * @param string $prompt the prompt message
353
     * @param array $options Key-value array of options to choose from
354
     *
355
     * @return string An option character the user chose
356
     */
357
    public function select($prompt, $options = [])
358
    {
359
        return Console::select($prompt, $options);
360
    }
361
362
    /**
363
     * Returns the names of valid options for the action (id)
364
     * An option requires the existence of a public member variable whose
365
     * name is the option name.
366
     * Child classes may override this method to specify possible options.
367
     *
368
     * Note that the values setting via options are not available
369
     * until [[beforeAction()]] is being called.
370
     *
371
     * @param string $actionID the action id of the current request
372
     * @return string[] the names of the options valid for the action
373
     */
374 211
    public function options($actionID)
0 ignored issues
show
Unused Code introduced by
The parameter $actionID is not used and could be removed. ( Ignorable by Annotation )

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

374
    public function options(/** @scrutinizer ignore-unused */ $actionID)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
375
    {
376
        // $actionId might be used in subclasses to provide options specific to action id
377 211
        return ['color', 'interactive', 'help'];
378
    }
379
380
    /**
381
     * Returns option alias names.
382
     * Child classes may override this method to specify alias options.
383
     *
384
     * @return array the options alias names valid for the action
385
     * where the keys is alias name for option and value is option name.
386
     *
387
     * @since 2.0.8
388
     * @see options()
389
     */
390 2
    public function optionAliases()
391
    {
392
        return [
393 2
            'h' => 'help',
394
        ];
395
    }
396
397
    /**
398
     * Returns properties corresponding to the options for the action id
399
     * Child classes may override this method to specify possible properties.
400
     *
401
     * @param string $actionID the action id of the current request
402
     * @return array properties corresponding to the options for the action
403
     */
404 65
    public function getOptionValues($actionID)
0 ignored issues
show
Unused Code introduced by
The parameter $actionID is not used and could be removed. ( Ignorable by Annotation )

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

404
    public function getOptionValues(/** @scrutinizer ignore-unused */ $actionID)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
405
    {
406
        // $actionId might be used in subclasses to provide properties specific to action id
407 65
        $properties = [];
408 65
        foreach ($this->options($this->action->id) as $property) {
409 65
            $properties[$property] = $this->$property;
410
        }
411
412 65
        return $properties;
413
    }
414
415
    /**
416
     * Returns the names of valid options passed during execution.
417
     *
418
     * @return array the names of the options passed during execution
419
     */
420
    public function getPassedOptions()
421
    {
422
        return $this->_passedOptions;
423
    }
424
425
    /**
426
     * Returns the properties corresponding to the passed options.
427
     *
428
     * @return array the properties corresponding to the passed options
429
     */
430 59
    public function getPassedOptionValues()
431
    {
432 59
        $properties = [];
433 59
        foreach ($this->_passedOptions as $property) {
434
            $properties[$property] = $this->$property;
435
        }
436
437 59
        return $properties;
438
    }
439
440
    /**
441
     * Returns one-line short summary describing this controller.
442
     *
443
     * You may override this method to return customized summary.
444
     * The default implementation returns first line from the PHPDoc comment.
445
     *
446
     * @return string
447
     */
448 5
    public function getHelpSummary()
449
    {
450 5
        return $this->parseDocCommentSummary(new \ReflectionClass($this));
451
    }
452
453
    /**
454
     * Returns help information for this controller.
455
     *
456
     * You may override this method to return customized help.
457
     * The default implementation returns help information retrieved from the PHPDoc comment.
458
     * @return string
459
     */
460
    public function getHelp()
461
    {
462
        return $this->parseDocCommentDetail(new \ReflectionClass($this));
463
    }
464
465
    /**
466
     * Returns a one-line short summary describing the specified action.
467
     * @param Action $action action to get summary for
468
     * @return string a one-line short summary describing the specified action.
469
     */
470 3
    public function getActionHelpSummary($action)
471
    {
472 3
        if ($action === null) {
473 1
            return $this->ansiFormat(Yii::t('yii', 'Action not found.'), Console::FG_RED);
474
        }
475
476 2
        return $this->parseDocCommentSummary($this->getActionMethodReflection($action));
477
    }
478
479
    /**
480
     * Returns the detailed help information for the specified action.
481
     * @param Action $action action to get help for
482
     * @return string the detailed help information for the specified action.
483
     */
484 3
    public function getActionHelp($action)
485
    {
486 3
        return $this->parseDocCommentDetail($this->getActionMethodReflection($action));
487
    }
488
489
    /**
490
     * Returns the help information for the anonymous arguments for the action.
491
     *
492
     * The returned value should be an array. The keys are the argument names, and the values are
493
     * the corresponding help information. Each value must be an array of the following structure:
494
     *
495
     * - required: boolean, whether this argument is required.
496
     * - type: string, the PHP type of this argument.
497
     * - default: string, the default value of this argument
498
     * - comment: string, the comment of this argument
499
     *
500
     * The default implementation will return the help information extracted from the doc-comment of
501
     * the parameters corresponding to the action method.
502
     *
503
     * @param Action $action
504
     * @return array the help information of the action arguments
505
     */
506 6
    public function getActionArgsHelp($action)
507
    {
508 6
        $method = $this->getActionMethodReflection($action);
509 6
        $tags = $this->parseDocCommentTags($method);
510 6
        $params = isset($tags['param']) ? (array) $tags['param'] : [];
511
512 6
        $args = [];
513
514
        /** @var \ReflectionParameter $reflection */
515 6
        foreach ($method->getParameters() as $i => $reflection) {
516 6
            if ($reflection->getClass() !== null) {
517 1
                continue;
518
            }
519 6
            $name = $reflection->getName();
520 6
            $tag = isset($params[$i]) ? $params[$i] : '';
521 6
            if (preg_match('/^(\S+)\s+(\$\w+\s+)?(.*)/s', $tag, $matches)) {
522 4
                $type = $matches[1];
523 4
                $comment = $matches[3];
524
            } else {
525 2
                $type = null;
526 2
                $comment = $tag;
527
            }
528 6
            if ($reflection->isDefaultValueAvailable()) {
529 3
                $args[$name] = [
530 3
                    'required' => false,
531 3
                    'type' => $type,
532 3
                    'default' => $reflection->getDefaultValue(),
533 3
                    'comment' => $comment,
534
                ];
535
            } else {
536 4
                $args[$name] = [
537 4
                    'required' => true,
538 4
                    'type' => $type,
539
                    'default' => null,
540 6
                    'comment' => $comment,
541
                ];
542
            }
543
        }
544
545 6
        return $args;
546
    }
547
548
    /**
549
     * Returns the help information for the options for the action.
550
     *
551
     * The returned value should be an array. The keys are the option names, and the values are
552
     * the corresponding help information. Each value must be an array of the following structure:
553
     *
554
     * - type: string, the PHP type of this argument.
555
     * - default: string, the default value of this argument
556
     * - comment: string, the comment of this argument
557
     *
558
     * The default implementation will return the help information extracted from the doc-comment of
559
     * the properties corresponding to the action options.
560
     *
561
     * @param Action $action
562
     * @return array the help information of the action options
563
     */
564 4
    public function getActionOptionsHelp($action)
565
    {
566 4
        $optionNames = $this->options($action->id);
567 4
        if (empty($optionNames)) {
568
            return [];
569
        }
570
571 4
        $class = new \ReflectionClass($this);
572 4
        $options = [];
573 4
        foreach ($class->getProperties() as $property) {
574 4
            $name = $property->getName();
575 4
            if (!in_array($name, $optionNames, true)) {
576 4
                continue;
577
            }
578 4
            $defaultValue = $property->getValue($this);
579 4
            $tags = $this->parseDocCommentTags($property);
580
581
            // Display camelCase options in kebab-case
582 4
            $name = Inflector::camel2id($name, '-', true);
583
584 4
            if (isset($tags['var']) || isset($tags['property'])) {
585 4
                $doc = isset($tags['var']) ? $tags['var'] : $tags['property'];
586 4
                if (is_array($doc)) {
587
                    $doc = reset($doc);
588
                }
589 4
                if (preg_match('/^(\S+)(.*)/s', $doc, $matches)) {
590 4
                    $type = $matches[1];
591 4
                    $comment = $matches[2];
592
                } else {
593
                    $type = null;
594
                    $comment = $doc;
595
                }
596 4
                $options[$name] = [
597 4
                    'type' => $type,
598 4
                    'default' => $defaultValue,
599 4
                    'comment' => $comment,
600
                ];
601
            } else {
602 1
                $options[$name] = [
603 1
                    'type' => null,
604 1
                    'default' => $defaultValue,
605 4
                    'comment' => '',
606
                ];
607
            }
608
        }
609
610 4
        return $options;
611
    }
612
613
    private $_reflections = [];
614
615
    /**
616
     * @param Action $action
617
     * @return \ReflectionMethod
618
     */
619 8
    protected function getActionMethodReflection($action)
620
    {
621 8
        if (!isset($this->_reflections[$action->id])) {
622 8
            if ($action instanceof InlineAction) {
623 8
                $this->_reflections[$action->id] = new \ReflectionMethod($this, $action->actionMethod);
624
            } else {
625
                $this->_reflections[$action->id] = new \ReflectionMethod($action, 'run');
626
            }
627
        }
628
629 8
        return $this->_reflections[$action->id];
630
    }
631
632
    /**
633
     * Parses the comment block into tags.
634
     * @param \Reflector $reflection the comment block
635
     * @return array the parsed tags
636
     */
637 6
    protected function parseDocCommentTags($reflection)
638
    {
639 6
        $comment = $reflection->getDocComment();
0 ignored issues
show
Bug introduced by
The method getDocComment() does not exist on Reflector. It seems like you code against a sub-type of Reflector such as ReflectionFunction or ReflectionProperty or ReflectionFunctionAbstract or ReflectionClassConstant or ReflectionObject or ReflectionClass or ReflectionMethod. ( Ignorable by Annotation )

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

639
        /** @scrutinizer ignore-call */ 
640
        $comment = $reflection->getDocComment();
Loading history...
640 6
        $comment = "@description \n" . strtr(trim(preg_replace('/^\s*\**( |\t)?/m', '', trim($comment, '/'))), "\r", '');
641 6
        $parts = preg_split('/^\s*@/m', $comment, -1, PREG_SPLIT_NO_EMPTY);
642 6
        $tags = [];
643 6
        foreach ($parts as $part) {
644 6
            if (preg_match('/^(\w+)(.*)/ms', trim($part), $matches)) {
645 6
                $name = $matches[1];
646 6
                if (!isset($tags[$name])) {
647 6
                    $tags[$name] = trim($matches[2]);
648
                } elseif (is_array($tags[$name])) {
649
                    $tags[$name][] = trim($matches[2]);
650
                } else {
651 6
                    $tags[$name] = [$tags[$name], trim($matches[2])];
652
                }
653
            }
654
        }
655
656 6
        return $tags;
657
    }
658
659
    /**
660
     * Returns the first line of docblock.
661
     *
662
     * @param \Reflector $reflection
663
     * @return string
664
     */
665 5
    protected function parseDocCommentSummary($reflection)
666
    {
667 5
        $docLines = preg_split('~\R~u', $reflection->getDocComment());
668 5
        if (isset($docLines[1])) {
669 5
            return trim($docLines[1], "\t *");
670
        }
671
672 2
        return '';
673
    }
674
675
    /**
676
     * Returns full description from the docblock.
677
     *
678
     * @param \Reflector $reflection
679
     * @return string
680
     */
681 3
    protected function parseDocCommentDetail($reflection)
682
    {
683 3
        $comment = strtr(trim(preg_replace('/^\s*\**( |\t)?/m', '', trim($reflection->getDocComment(), '/'))), "\r", '');
684 3
        if (preg_match('/^\s*@\w+/m', $comment, $matches, PREG_OFFSET_CAPTURE)) {
685 2
            $comment = trim(substr($comment, 0, $matches[0][1]));
686
        }
687 3
        if ($comment !== '') {
688 2
            return rtrim(Console::renderColoredString(Console::markdownToAnsi($comment)));
689
        }
690
691 1
        return '';
692
    }
693
}
694