Passed
Pull Request — master (#43)
by Jitendra
01:52
created

DocsCommand::prepare()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 0
dl 0
loc 15
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the PHINT package.
5
 *
6
 * (c) Jitendra Adhikari <[email protected]>
7
 *     <https://github.com/adhocore>
8
 *
9
 * Licensed under MIT license.
10
 */
11
12
namespace Ahc\Phint\Console;
13
14
use Ahc\Phint\Generator\TwigGenerator;
15
16
class DocsCommand extends BaseCommand
17
{
18
    /** @var string Command name */
19
    protected $_name = 'docs';
20
21
    /** @var string Command description */
22
    protected $_desc = 'Generate basic readme docs from docblocks';
23
24
    /** @var string Current working dir */
25
    protected $_workDir;
26
27
    /**
28
     * Configure the command options/arguments.
29
     *
30
     * @return void
31
     */
32
    protected function onConstruct()
33
    {
34
        $this->_workDir  = \realpath(\getcwd());
35
36
        $this
37
            ->option('-o --output', "Output file (default README.md)\nFor old project you should use something else")
38
            ->option('-a --with-abstract', 'Create stub for abstract/interface class')
39
            ->usage(
40
                '<bold>  phint docs</end>               Appends to readme.md<eol/>' .
41
                '<bold>  phint d</end> <comment>-o docs/api.md</end>   Writes to docs/api.md<eol/>'
42
            );
43
    }
44
45
    /**
46
     * Generate test stubs.
47
     *
48
     * @return void
49
     */
50
    public function execute()
51
    {
52
        $io = $this->app()->io();
53
54
        $io->comment('Preparing metadata ...', true);
55
        $metadata = $this->prepare();
56
57
        if (empty($metadata)) {
58
            $io->bgGreen('Looks like nothing to do here', true);
59
60
            return;
61
        }
62
63
        $io->comment('Generating tests ...', true);
64
        $generated = $this->generate($metadata);
65
66
        if ($generated) {
67
            $io->cyan("$generated test(s) generated", true);
68
        }
69
70
        $io->ok('Done', true);
71
    }
72
73
    protected function prepare(): array
74
    {
75
        // Sorry psr-0!
76
        $namespaces = $this->_composer->config('autoload.psr-4');
77
78
        $srcPaths = [];
79
        foreach ($namespaces as $ns => $path) {
80
            if (\preg_match('!^(source|src|lib|class)/?!', $path)) {
81
                $srcPaths[] = $path;
82
            }
83
        }
84
85
        $classes = $this->_pathUtil->loadClasses($srcPaths);
0 ignored issues
show
Bug introduced by
The call to Ahc\Phint\Util\Path::loadClasses() has too few arguments starting with ext. ( Ignorable by Annotation )

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

85
        /** @scrutinizer ignore-call */ 
86
        $classes = $this->_pathUtil->loadClasses($srcPaths);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
86
87
        return $this->getClassesMetadata($classes);
88
    }
89
90
    protected function getClassesMetadata(array $classes): array
91
    {
92
        $metadata = [];
93
94
        foreach ($classes as $classFqcn) {
95
            if ([] === $meta = $this->getClassMetadata($classFqcn)) {
96
                continue;
97
            }
98
99
            $metadata[] = $meta;
100
        }
101
102
        return $metadata;
103
    }
104
105
    protected function getClassMetadata(string $classFqcn): array
106
    {
107
        $reflex = new \ReflectionClass($classFqcn);
108
109
        if (!$this->shouldGenerateDocs($reflex)) {
110
            return [];
111
        }
112
113
        $methods     = [];
114
        $isTrait     = $reflex->isTrait();
115
        $isAbstract  = $reflex->isAbstract();
116
        $isInterface = $reflex->isInterface();
117
118
        foreach ($reflex->getMethods(\ReflectionMethod::IS_PUBLIC) as $m) {
119
            if ($m->class !== $classFqcn) {
120
                continue;
121
            }
122
123
            $methods[$m->name] = $this->getMethodMetadata($m);
124
        }
125
126
        if (empty($methods)) {
127
            return [];
128
        }
129
130
        return \compact('classFqcn', 'isTrait', 'isAbstract', 'isInterface', 'methods');
131
    }
132
133
    protected function shouldGenerateDocs(\ReflectionClass $reflex): bool
134
    {
135
        if ($this->abstract) {
0 ignored issues
show
Bug Best Practice introduced by
The property abstract does not exist on Ahc\Phint\Console\DocsCommand. Since you implemented __get, consider adding a @property annotation.
Loading history...
136
            return true;
137
        }
138
139
        return !$reflex->isInterface() && !$reflex->isAbstract();
140
    }
141
142
    protected function getMethodMetadata(\ReflectionMethod $method): array
143
    {
144
        $args = [];
145
146
        return ['static' => $method->isStatic(), 'abstract' => $method->isAbstract(), 'args' => $args];
147
    }
148
149
    protected function generate(array $metadata): int
150
    {
151
        $templatePath = __DIR__ . '/../../resources';
152
        $generator    = new TwigGenerator($templatePath, $this->getCachePath());
153
154
        return $generator->generateDocs($metadata, $this->values());
0 ignored issues
show
Bug introduced by
The method generateDocs() does not exist on Ahc\Phint\Generator\TwigGenerator. Did you maybe mean generate()? ( Ignorable by Annotation )

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

154
        return $generator->/** @scrutinizer ignore-call */ generateDocs($metadata, $this->values());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
155
    }
156
}
157